]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gprofng: a new GNU profiler
authorVladimir Mezentsev <vladimir.mezentsev@oracle.com>
Fri, 11 Mar 2022 08:58:31 +0000 (08:58 +0000)
committerNick Clifton <nickc@redhat.com>
Fri, 11 Mar 2022 08:58:31 +0000 (08:58 +0000)
top-level
* Makefile.def: Add gprofng module.
* configure.ac: Add --enable-gprofng option.
* src-release.sh: Add gprofng.
* Makefile.in: Regenerate.
* configure: Regenerate.
* gprofng: New directory.

binutils
* MAINTAINERS: Add gprofng maintainer.
* README-how-to-make-a-release: Add gprofng.

include.
* collectorAPI.h: New file.
* libcollector.h: New file.
* libfcollector.h: New file.

319 files changed:
ChangeLog
Makefile.def
Makefile.in
binutils/ChangeLog
binutils/MAINTAINERS
binutils/README-how-to-make-a-release
configure
configure.ac
gprofng/Makefile.am [new file with mode: 0644]
gprofng/Makefile.in [new file with mode: 0644]
gprofng/README [new file with mode: 0644]
gprofng/acinclude.m4 [new file with mode: 0644]
gprofng/aclocal.m4 [new file with mode: 0644]
gprofng/common/cc_libcollector.h [new file with mode: 0644]
gprofng/common/config.h.in [new file with mode: 0644]
gprofng/common/core_pcbe.c [new file with mode: 0644]
gprofng/common/cpu_frequency.h [new file with mode: 0644]
gprofng/common/cpuid.c [new file with mode: 0644]
gprofng/common/gp-defs.h [new file with mode: 0644]
gprofng/common/gp-experiment.h [new file with mode: 0644]
gprofng/common/gp-time.h [new file with mode: 0644]
gprofng/common/hwc_cpus.h [new file with mode: 0644]
gprofng/common/hwcdrv.c [new file with mode: 0644]
gprofng/common/hwcdrv.h [new file with mode: 0644]
gprofng/common/hwcentry.h [new file with mode: 0644]
gprofng/common/hwcfuncs.c [new file with mode: 0644]
gprofng/common/hwcfuncs.h [new file with mode: 0644]
gprofng/common/hwctable.c [new file with mode: 0644]
gprofng/common/opteron_pcbe.c [new file with mode: 0644]
gprofng/config/bison.m4 [new file with mode: 0644]
gprofng/configure [new file with mode: 0755]
gprofng/configure.ac [new file with mode: 0644]
gprofng/doc/Makefile.am [new file with mode: 0644]
gprofng/doc/Makefile.in [new file with mode: 0644]
gprofng/doc/fdl.texi [new file with mode: 0644]
gprofng/doc/gprofng.texi [new file with mode: 0644]
gprofng/doc/mdate-sh [new file with mode: 0755]
gprofng/doc/texinfo.tex [new file with mode: 0644]
gprofng/doc/version.texi [new file with mode: 0644]
gprofng/gp-display-html/Makefile.am [new file with mode: 0644]
gprofng/gp-display-html/Makefile.in [new file with mode: 0644]
gprofng/gp-display-html/gp-display-html.in [new file with mode: 0644]
gprofng/libcollector/CHK_LIBC_OBJ [new file with mode: 0755]
gprofng/libcollector/Makefile.am [new file with mode: 0644]
gprofng/libcollector/Makefile.in [new file with mode: 0644]
gprofng/libcollector/aclocal.m4 [new file with mode: 0644]
gprofng/libcollector/collector.c [new file with mode: 0644]
gprofng/libcollector/collector.h [new file with mode: 0644]
gprofng/libcollector/collectorAPI.c [new file with mode: 0644]
gprofng/libcollector/configure [new file with mode: 0755]
gprofng/libcollector/configure.ac [new file with mode: 0644]
gprofng/libcollector/descendants.h [new file with mode: 0644]
gprofng/libcollector/dispatcher.c [new file with mode: 0644]
gprofng/libcollector/envmgmt.c [new file with mode: 0644]
gprofng/libcollector/gethrtime.c [new file with mode: 0644]
gprofng/libcollector/heaptrace.c [new file with mode: 0644]
gprofng/libcollector/hwprofile.c [new file with mode: 0644]
gprofng/libcollector/hwprofile.h [new file with mode: 0644]
gprofng/libcollector/iolib.c [new file with mode: 0644]
gprofng/libcollector/iotrace.c [new file with mode: 0644]
gprofng/libcollector/jprofile.c [new file with mode: 0644]
gprofng/libcollector/libcol-i386-dis.c [new file with mode: 0644]
gprofng/libcollector/libcol_hwcdrv.c [new file with mode: 0644]
gprofng/libcollector/libcol_hwcfuncs.c [new file with mode: 0644]
gprofng/libcollector/libcol_util.c [new file with mode: 0644]
gprofng/libcollector/libcol_util.h [new file with mode: 0644]
gprofng/libcollector/linetrace.c [new file with mode: 0644]
gprofng/libcollector/mapfile.aarch64-Linux [new file with mode: 0644]
gprofng/libcollector/mapfile.amd64-Linux [new file with mode: 0644]
gprofng/libcollector/mapfile.intel-Linux [new file with mode: 0644]
gprofng/libcollector/mapfile.sparc-Linux [new file with mode: 0644]
gprofng/libcollector/mapfile.sparcv9-Linux [new file with mode: 0644]
gprofng/libcollector/memmgr.c [new file with mode: 0644]
gprofng/libcollector/memmgr.h [new file with mode: 0644]
gprofng/libcollector/mmaptrace.c [new file with mode: 0644]
gprofng/libcollector/profile.c [new file with mode: 0644]
gprofng/libcollector/synctrace.c [new file with mode: 0644]
gprofng/libcollector/tsd.c [new file with mode: 0644]
gprofng/libcollector/tsd.h [new file with mode: 0644]
gprofng/libcollector/unwind.c [new file with mode: 0644]
gprofng/src/ABS.h [new file with mode: 0644]
gprofng/src/Application.cc [new file with mode: 0644]
gprofng/src/Application.h [new file with mode: 0644]
gprofng/src/ArchiveExp.cc [new file with mode: 0644]
gprofng/src/ArchiveExp.h [new file with mode: 0644]
gprofng/src/BaseMetric.cc [new file with mode: 0644]
gprofng/src/BaseMetric.h [new file with mode: 0644]
gprofng/src/BaseMetricTreeNode.cc [new file with mode: 0644]
gprofng/src/BaseMetricTreeNode.h [new file with mode: 0644]
gprofng/src/CacheMap.h [new file with mode: 0644]
gprofng/src/CallStack.cc [new file with mode: 0644]
gprofng/src/CallStack.h [new file with mode: 0644]
gprofng/src/CatchOutOfMemory.cc [new file with mode: 0644]
gprofng/src/ClassFile.cc [new file with mode: 0644]
gprofng/src/ClassFile.h [new file with mode: 0644]
gprofng/src/Command.cc [new file with mode: 0644]
gprofng/src/Command.h [new file with mode: 0644]
gprofng/src/CompCom.cc [new file with mode: 0644]
gprofng/src/CompCom.h [new file with mode: 0644]
gprofng/src/DataObject.cc [new file with mode: 0644]
gprofng/src/DataObject.h [new file with mode: 0644]
gprofng/src/DataSpace.cc [new file with mode: 0644]
gprofng/src/DataSpace.h [new file with mode: 0644]
gprofng/src/DataStream.cc [new file with mode: 0644]
gprofng/src/DataStream.h [new file with mode: 0644]
gprofng/src/Data_window.cc [new file with mode: 0644]
gprofng/src/Data_window.h [new file with mode: 0644]
gprofng/src/Dbe.cc [new file with mode: 0644]
gprofng/src/Dbe.h [new file with mode: 0644]
gprofng/src/DbeApplication.cc [new file with mode: 0644]
gprofng/src/DbeApplication.h [new file with mode: 0644]
gprofng/src/DbeArray.h [new file with mode: 0644]
gprofng/src/DbeCacheMap.h [new file with mode: 0644]
gprofng/src/DbeFile.cc [new file with mode: 0644]
gprofng/src/DbeFile.h [new file with mode: 0644]
gprofng/src/DbeJarFile.cc [new file with mode: 0644]
gprofng/src/DbeJarFile.h [new file with mode: 0644]
gprofng/src/DbeLinkList.h [new file with mode: 0644]
gprofng/src/DbeLock.cc [new file with mode: 0644]
gprofng/src/DbeLock.h [new file with mode: 0644]
gprofng/src/DbeSession.cc [new file with mode: 0644]
gprofng/src/DbeSession.cc.1 [new file with mode: 0644]
gprofng/src/DbeSession.h [new file with mode: 0644]
gprofng/src/DbeSyncMap.h [new file with mode: 0644]
gprofng/src/DbeThread.cc [new file with mode: 0644]
gprofng/src/DbeThread.h [new file with mode: 0644]
gprofng/src/DbeView.cc [new file with mode: 0644]
gprofng/src/DbeView.h [new file with mode: 0644]
gprofng/src/DefaultHandler.h [new file with mode: 0644]
gprofng/src/DefaultMap.h [new file with mode: 0644]
gprofng/src/DefaultMap2D.h [new file with mode: 0644]
gprofng/src/DerivedMetrics.cc [new file with mode: 0644]
gprofng/src/DerivedMetrics.h [new file with mode: 0644]
gprofng/src/Disasm.cc [new file with mode: 0644]
gprofng/src/Disasm.h [new file with mode: 0644]
gprofng/src/Dwarf.cc [new file with mode: 0644]
gprofng/src/Dwarf.h [new file with mode: 0644]
gprofng/src/DwarfLib.cc [new file with mode: 0644]
gprofng/src/DwarfLib.h [new file with mode: 0644]
gprofng/src/Elf.cc [new file with mode: 0644]
gprofng/src/Elf.h [new file with mode: 0644]
gprofng/src/Emsg.cc [new file with mode: 0644]
gprofng/src/Emsg.h [new file with mode: 0644]
gprofng/src/Emsgnum.h [new file with mode: 0644]
gprofng/src/ExpGroup.cc [new file with mode: 0644]
gprofng/src/ExpGroup.h [new file with mode: 0644]
gprofng/src/Exp_Layout.cc [new file with mode: 0644]
gprofng/src/Exp_Layout.h [new file with mode: 0644]
gprofng/src/Experiment.cc [new file with mode: 0644]
gprofng/src/Experiment.h [new file with mode: 0644]
gprofng/src/Expression.cc [new file with mode: 0644]
gprofng/src/Expression.h [new file with mode: 0644]
gprofng/src/FileData.cc [new file with mode: 0644]
gprofng/src/FileData.h [new file with mode: 0644]
gprofng/src/Filter.cc [new file with mode: 0644]
gprofng/src/Filter.h [new file with mode: 0644]
gprofng/src/FilterExp.h [new file with mode: 0644]
gprofng/src/FilterSet.cc [new file with mode: 0644]
gprofng/src/FilterSet.h [new file with mode: 0644]
gprofng/src/Function.cc [new file with mode: 0644]
gprofng/src/Function.h [new file with mode: 0644]
gprofng/src/HashMap.h [new file with mode: 0644]
gprofng/src/HeapActivity.cc [new file with mode: 0644]
gprofng/src/HeapActivity.h [new file with mode: 0644]
gprofng/src/HeapData.cc [new file with mode: 0644]
gprofng/src/HeapData.h [new file with mode: 0644]
gprofng/src/HeapMap.cc [new file with mode: 0644]
gprofng/src/HeapMap.h [new file with mode: 0644]
gprofng/src/Hist_data.cc [new file with mode: 0644]
gprofng/src/Hist_data.h [new file with mode: 0644]
gprofng/src/Histable.h [new file with mode: 0644]
gprofng/src/IOActivity.cc [new file with mode: 0644]
gprofng/src/IOActivity.h [new file with mode: 0644]
gprofng/src/IndexMap2D.h [new file with mode: 0644]
gprofng/src/IndexObject.cc [new file with mode: 0644]
gprofng/src/IndexObject.h [new file with mode: 0644]
gprofng/src/IntervalMap.h [new file with mode: 0644]
gprofng/src/LoadObject.cc [new file with mode: 0644]
gprofng/src/LoadObject.h [new file with mode: 0644]
gprofng/src/MachineModel.cc [new file with mode: 0644]
gprofng/src/Makefile.am [new file with mode: 0644]
gprofng/src/Makefile.in [new file with mode: 0644]
gprofng/src/Map.h [new file with mode: 0644]
gprofng/src/Map2D.h [new file with mode: 0644]
gprofng/src/MemObject.cc [new file with mode: 0644]
gprofng/src/MemObject.h [new file with mode: 0644]
gprofng/src/MemorySpace.cc [new file with mode: 0644]
gprofng/src/MemorySpace.h [new file with mode: 0644]
gprofng/src/Metric.cc [new file with mode: 0644]
gprofng/src/Metric.h [new file with mode: 0644]
gprofng/src/MetricList.cc [new file with mode: 0644]
gprofng/src/MetricList.h [new file with mode: 0644]
gprofng/src/Module.cc [new file with mode: 0644]
gprofng/src/Module.h [new file with mode: 0644]
gprofng/src/Ovw_data.cc [new file with mode: 0644]
gprofng/src/Ovw_data.h [new file with mode: 0644]
gprofng/src/PRBTree.cc [new file with mode: 0644]
gprofng/src/PRBTree.h [new file with mode: 0644]
gprofng/src/PathTree.cc [new file with mode: 0644]
gprofng/src/PathTree.h [new file with mode: 0644]
gprofng/src/PreviewExp.cc [new file with mode: 0644]
gprofng/src/PreviewExp.h [new file with mode: 0644]
gprofng/src/Print.cc [new file with mode: 0644]
gprofng/src/Print.h [new file with mode: 0644]
gprofng/src/QLParser.h [new file with mode: 0644]
gprofng/src/QLParser.tab.cc [new file with mode: 0644]
gprofng/src/QLParser.tab.hh [new file with mode: 0644]
gprofng/src/QLParser.yy [new file with mode: 0644]
gprofng/src/SAXParser.h [new file with mode: 0644]
gprofng/src/SAXParserFactory.cc [new file with mode: 0644]
gprofng/src/SAXParserFactory.h [new file with mode: 0644]
gprofng/src/Sample.cc [new file with mode: 0644]
gprofng/src/Sample.h [new file with mode: 0644]
gprofng/src/SegMem.h [new file with mode: 0644]
gprofng/src/Settings.cc [new file with mode: 0644]
gprofng/src/Settings.h [new file with mode: 0644]
gprofng/src/SourceFile.cc [new file with mode: 0644]
gprofng/src/SourceFile.h [new file with mode: 0644]
gprofng/src/Stabs.cc [new file with mode: 0644]
gprofng/src/Stabs.h [new file with mode: 0644]
gprofng/src/Stats_data.cc [new file with mode: 0644]
gprofng/src/Stats_data.h [new file with mode: 0644]
gprofng/src/StringBuilder.cc [new file with mode: 0644]
gprofng/src/StringBuilder.h [new file with mode: 0644]
gprofng/src/StringMap.h [new file with mode: 0644]
gprofng/src/Table.cc [new file with mode: 0644]
gprofng/src/Table.h [new file with mode: 0644]
gprofng/src/UserLabel.cc [new file with mode: 0644]
gprofng/src/UserLabel.h [new file with mode: 0644]
gprofng/src/checks.cc [new file with mode: 0644]
gprofng/src/collctrl.cc [new file with mode: 0644]
gprofng/src/collctrl.h [new file with mode: 0644]
gprofng/src/collect.h [new file with mode: 0644]
gprofng/src/collector_module.h [new file with mode: 0644]
gprofng/src/comp_com.c [new file with mode: 0644]
gprofng/src/comp_com.h [new file with mode: 0644]
gprofng/src/count.cc [new file with mode: 0644]
gprofng/src/data_pckts.h [new file with mode: 0644]
gprofng/src/dbe_collctrl.cc [new file with mode: 0644]
gprofng/src/dbe_hwc.h [new file with mode: 0644]
gprofng/src/dbe_hwcdrv.c [new file with mode: 0644]
gprofng/src/dbe_hwcfuncs.c [new file with mode: 0644]
gprofng/src/dbe_hwctable.c [new file with mode: 0644]
gprofng/src/dbe_memmgr.c [new file with mode: 0644]
gprofng/src/dbe_structs.h [new file with mode: 0644]
gprofng/src/dbe_types.h [new file with mode: 0644]
gprofng/src/debug.h [new file with mode: 0644]
gprofng/src/enums.h [new file with mode: 0644]
gprofng/src/envsets.cc [new file with mode: 0644]
gprofng/src/gethrtime.c [new file with mode: 0644]
gprofng/src/gp-archive.cc [new file with mode: 0644]
gprofng/src/gp-archive.h [new file with mode: 0644]
gprofng/src/gp-collect-app.cc [new file with mode: 0644]
gprofng/src/gp-display-src.cc [new file with mode: 0644]
gprofng/src/gp-display-text.cc [new file with mode: 0644]
gprofng/src/gp-print.h [new file with mode: 0644]
gprofng/src/gprofng.cc [new file with mode: 0644]
gprofng/src/gprofng.h2m [new file with mode: 0644]
gprofng/src/gprofng.rc [new file with mode: 0644]
gprofng/src/i18n.cc [new file with mode: 0644]
gprofng/src/i18n.h [new file with mode: 0644]
gprofng/src/info.h [new file with mode: 0644]
gprofng/src/ipc.cc [new file with mode: 0644]
gprofng/src/ipcio.cc [new file with mode: 0644]
gprofng/src/ipcio.h [new file with mode: 0644]
gprofng/src/machinemodels/generic.ermm [new file with mode: 0644]
gprofng/src/machinemodels/m5.ermm [new file with mode: 0644]
gprofng/src/machinemodels/m6.ermm [new file with mode: 0644]
gprofng/src/machinemodels/m7.ermm [new file with mode: 0644]
gprofng/src/machinemodels/t4.ermm [new file with mode: 0644]
gprofng/src/machinemodels/t5.ermm [new file with mode: 0644]
gprofng/src/parse.cc [new file with mode: 0644]
gprofng/src/stab.h [new file with mode: 0644]
gprofng/src/util.cc [new file with mode: 0644]
gprofng/src/util.h [new file with mode: 0644]
gprofng/src/vec.h [new file with mode: 0644]
gprofng/testsuite/config/default.exp [new file with mode: 0644]
gprofng/testsuite/gprofng.display/display.exp [new file with mode: 0644]
gprofng/testsuite/gprofng.display/jsynprog/Intface.java [new file with mode: 0644]
gprofng/testsuite/gprofng.display/jsynprog/Launcher.java [new file with mode: 0644]
gprofng/testsuite/gprofng.display/jsynprog/Makefile [new file with mode: 0644]
gprofng/testsuite/gprofng.display/jsynprog/Routine.java [new file with mode: 0644]
gprofng/testsuite/gprofng.display/jsynprog/Sub_Routine.java [new file with mode: 0644]
gprofng/testsuite/gprofng.display/jsynprog/check_results.pl [new file with mode: 0755]
gprofng/testsuite/gprofng.display/jsynprog/cloop.cc [new file with mode: 0644]
gprofng/testsuite/gprofng.display/jsynprog/jsynprog.h [new file with mode: 0644]
gprofng/testsuite/gprofng.display/jsynprog/jsynprog.java [new file with mode: 0644]
gprofng/testsuite/gprofng.display/mttest/Makefile [new file with mode: 0644]
gprofng/testsuite/gprofng.display/mttest/check_results.pl [new file with mode: 0644]
gprofng/testsuite/gprofng.display/mttest/gethrtime.c [new file with mode: 0644]
gprofng/testsuite/gprofng.display/mttest/mttest.c [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/Makefile [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/callso.c [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/callsx.c [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/check_results.pl [new file with mode: 0755]
gprofng/testsuite/gprofng.display/synprog/endcases.c [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/fitos.c [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/inc_body.h [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/inc_brace.h [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/inc_entry.h [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/inc_exit.h [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/inc_func.h [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/inc_inline.h [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/inc_macro.h [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/iosyn.c [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/pagethrash.c [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/so_syn.c [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/so_syx.c [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/stopwatch.c [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/stopwatch.h [new file with mode: 0644]
gprofng/testsuite/gprofng.display/synprog/synprog.c [new file with mode: 0644]
gprofng/testsuite/lib/Makefile.skel [new file with mode: 0644]
gprofng/testsuite/lib/acct.pm [new file with mode: 0644]
gprofng/testsuite/lib/display-lib.exp [new file with mode: 0644]
include/ChangeLog
include/collectorAPI.h [new file with mode: 0644]
include/libcollector.h [new file with mode: 0644]
include/libfcollector.h [new file with mode: 0644]
src-release.sh

index 18e8b6835da5486eab58b08a62cb5666cb412b3e..73b6085d6ef7e7b795eabfb1cd2eb8633ea514fa 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2022-03-11  Vladimir Mezentsev  <vladimir.mezentsev@oracle.com>
+
+       * Makefile.def: Add gprofng module.
+       * configure.ac: Add --enable-gprofng option.
+       * src-release.sh: Add gprofng.
+       * Makefile.in: Regenerate.
+       * configure: Regenerate.
+       * gprofng: New directory.
+
 2022-01-22  Nick Clifton  <nickc@redhat.com>
 
        * 2.38 release branch created.
index 8181a7aa97b56141bdb0574a394b28266912b2dd..acdcd625ed6fd052359809c8c339f310815735d7 100644 (file)
@@ -75,6 +75,7 @@ host_modules= { module= libelf; lib_path=.libs; bootstrap=true;
                no_install= true; };
 host_modules= { module= gold; bootstrap=true; };
 host_modules= { module= gprof; };
+host_modules= { module= gprofng; };
 host_modules= { module= intl; bootstrap=true; };
 host_modules= { module= tcl;
                 missing=mostlyclean; };
@@ -508,6 +509,16 @@ dependencies = { module=all-gprof; on=all-bfd; };
 dependencies = { module=all-gprof; on=all-opcodes; };
 dependencies = { module=all-gprof; on=all-intl; };
 dependencies = { module=all-gprof; on=all-gas; };
+
+dependencies = { module=configure-gprofng; on=configure-intl; };
+dependencies = { module=all-gprofng; on=all-libiberty; };
+dependencies = { module=all-gprofng; on=all-bfd; };
+dependencies = { module=all-gprofng; on=all-opcodes; };
+dependencies = { module=all-gprofng; on=all-intl; };
+dependencies = { module=all-gprofng; on=all-gas; };
+dependencies = { module=install-gprofng; on=install-opcodes; };
+dependencies = { module=install-gprofng; on=install-bfd; };
+
 dependencies = { module=configure-ld; on=configure-intl; };
 dependencies = { module=all-ld; on=all-libiberty; };
 dependencies = { module=all-ld; on=all-bfd; };
index 843e150dac638e77b9a86ad3a9d3628760475496..3aacd2daac9cdf3bba927cd9f554fa1cbf3c94ea 100644 (file)
@@ -1073,6 +1073,7 @@ configure-host:  \
     maybe-configure-libelf \
     maybe-configure-gold \
     maybe-configure-gprof \
+    maybe-configure-gprofng \
     maybe-configure-intl \
     maybe-configure-tcl \
     maybe-configure-itcl \
@@ -1228,6 +1229,7 @@ all-host: maybe-all-libelf
 all-host: maybe-all-gold
 @endif gold-no-bootstrap
 all-host: maybe-all-gprof
+all-host: maybe-all-gprofng
 @if intl-no-bootstrap
 all-host: maybe-all-intl
 @endif intl-no-bootstrap
@@ -1357,6 +1359,7 @@ info-host: maybe-info-isl
 info-host: maybe-info-libelf
 info-host: maybe-info-gold
 info-host: maybe-info-gprof
+info-host: maybe-info-gprofng
 info-host: maybe-info-intl
 info-host: maybe-info-tcl
 info-host: maybe-info-itcl
@@ -1447,6 +1450,7 @@ dvi-host: maybe-dvi-isl
 dvi-host: maybe-dvi-libelf
 dvi-host: maybe-dvi-gold
 dvi-host: maybe-dvi-gprof
+dvi-host: maybe-dvi-gprofng
 dvi-host: maybe-dvi-intl
 dvi-host: maybe-dvi-tcl
 dvi-host: maybe-dvi-itcl
@@ -1537,6 +1541,7 @@ pdf-host: maybe-pdf-isl
 pdf-host: maybe-pdf-libelf
 pdf-host: maybe-pdf-gold
 pdf-host: maybe-pdf-gprof
+pdf-host: maybe-pdf-gprofng
 pdf-host: maybe-pdf-intl
 pdf-host: maybe-pdf-tcl
 pdf-host: maybe-pdf-itcl
@@ -1627,6 +1632,7 @@ html-host: maybe-html-isl
 html-host: maybe-html-libelf
 html-host: maybe-html-gold
 html-host: maybe-html-gprof
+html-host: maybe-html-gprofng
 html-host: maybe-html-intl
 html-host: maybe-html-tcl
 html-host: maybe-html-itcl
@@ -1717,6 +1723,7 @@ TAGS-host: maybe-TAGS-isl
 TAGS-host: maybe-TAGS-libelf
 TAGS-host: maybe-TAGS-gold
 TAGS-host: maybe-TAGS-gprof
+TAGS-host: maybe-TAGS-gprofng
 TAGS-host: maybe-TAGS-intl
 TAGS-host: maybe-TAGS-tcl
 TAGS-host: maybe-TAGS-itcl
@@ -1807,6 +1814,7 @@ install-info-host: maybe-install-info-isl
 install-info-host: maybe-install-info-libelf
 install-info-host: maybe-install-info-gold
 install-info-host: maybe-install-info-gprof
+install-info-host: maybe-install-info-gprofng
 install-info-host: maybe-install-info-intl
 install-info-host: maybe-install-info-tcl
 install-info-host: maybe-install-info-itcl
@@ -1897,6 +1905,7 @@ install-dvi-host: maybe-install-dvi-isl
 install-dvi-host: maybe-install-dvi-libelf
 install-dvi-host: maybe-install-dvi-gold
 install-dvi-host: maybe-install-dvi-gprof
+install-dvi-host: maybe-install-dvi-gprofng
 install-dvi-host: maybe-install-dvi-intl
 install-dvi-host: maybe-install-dvi-tcl
 install-dvi-host: maybe-install-dvi-itcl
@@ -1987,6 +1996,7 @@ install-pdf-host: maybe-install-pdf-isl
 install-pdf-host: maybe-install-pdf-libelf
 install-pdf-host: maybe-install-pdf-gold
 install-pdf-host: maybe-install-pdf-gprof
+install-pdf-host: maybe-install-pdf-gprofng
 install-pdf-host: maybe-install-pdf-intl
 install-pdf-host: maybe-install-pdf-tcl
 install-pdf-host: maybe-install-pdf-itcl
@@ -2077,6 +2087,7 @@ install-html-host: maybe-install-html-isl
 install-html-host: maybe-install-html-libelf
 install-html-host: maybe-install-html-gold
 install-html-host: maybe-install-html-gprof
+install-html-host: maybe-install-html-gprofng
 install-html-host: maybe-install-html-intl
 install-html-host: maybe-install-html-tcl
 install-html-host: maybe-install-html-itcl
@@ -2167,6 +2178,7 @@ installcheck-host: maybe-installcheck-isl
 installcheck-host: maybe-installcheck-libelf
 installcheck-host: maybe-installcheck-gold
 installcheck-host: maybe-installcheck-gprof
+installcheck-host: maybe-installcheck-gprofng
 installcheck-host: maybe-installcheck-intl
 installcheck-host: maybe-installcheck-tcl
 installcheck-host: maybe-installcheck-itcl
@@ -2257,6 +2269,7 @@ mostlyclean-host: maybe-mostlyclean-isl
 mostlyclean-host: maybe-mostlyclean-libelf
 mostlyclean-host: maybe-mostlyclean-gold
 mostlyclean-host: maybe-mostlyclean-gprof
+mostlyclean-host: maybe-mostlyclean-gprofng
 mostlyclean-host: maybe-mostlyclean-intl
 mostlyclean-host: maybe-mostlyclean-tcl
 mostlyclean-host: maybe-mostlyclean-itcl
@@ -2347,6 +2360,7 @@ clean-host: maybe-clean-isl
 clean-host: maybe-clean-libelf
 clean-host: maybe-clean-gold
 clean-host: maybe-clean-gprof
+clean-host: maybe-clean-gprofng
 clean-host: maybe-clean-intl
 clean-host: maybe-clean-tcl
 clean-host: maybe-clean-itcl
@@ -2437,6 +2451,7 @@ distclean-host: maybe-distclean-isl
 distclean-host: maybe-distclean-libelf
 distclean-host: maybe-distclean-gold
 distclean-host: maybe-distclean-gprof
+distclean-host: maybe-distclean-gprofng
 distclean-host: maybe-distclean-intl
 distclean-host: maybe-distclean-tcl
 distclean-host: maybe-distclean-itcl
@@ -2527,6 +2542,7 @@ maintainer-clean-host: maybe-maintainer-clean-isl
 maintainer-clean-host: maybe-maintainer-clean-libelf
 maintainer-clean-host: maybe-maintainer-clean-gold
 maintainer-clean-host: maybe-maintainer-clean-gprof
+maintainer-clean-host: maybe-maintainer-clean-gprofng
 maintainer-clean-host: maybe-maintainer-clean-intl
 maintainer-clean-host: maybe-maintainer-clean-tcl
 maintainer-clean-host: maybe-maintainer-clean-itcl
@@ -2675,6 +2691,7 @@ check-host:  \
     maybe-check-libelf \
     maybe-check-gold \
     maybe-check-gprof \
+    maybe-check-gprofng \
     maybe-check-intl \
     maybe-check-tcl \
     maybe-check-itcl \
@@ -2812,6 +2829,7 @@ install-host-nogcc:  \
     maybe-install-libelf \
     maybe-install-gold \
     maybe-install-gprof \
+    maybe-install-gprofng \
     maybe-install-intl \
     maybe-install-tcl \
     maybe-install-itcl \
@@ -2867,6 +2885,7 @@ install-host:  \
     maybe-install-libelf \
     maybe-install-gold \
     maybe-install-gprof \
+    maybe-install-gprofng \
     maybe-install-intl \
     maybe-install-tcl \
     maybe-install-itcl \
@@ -2977,6 +2996,7 @@ install-strip-host:  \
     maybe-install-strip-libelf \
     maybe-install-strip-gold \
     maybe-install-strip-gprof \
+    maybe-install-strip-gprofng \
     maybe-install-strip-intl \
     maybe-install-strip-tcl \
     maybe-install-strip-itcl \
@@ -20404,6 +20424,474 @@ maintainer-clean-gprof:
 
 
 
+.PHONY: configure-gprofng maybe-configure-gprofng
+maybe-configure-gprofng:
+@if gcc-bootstrap
+configure-gprofng: stage_current
+@endif gcc-bootstrap
+@if gprofng
+maybe-configure-gprofng: configure-gprofng
+configure-gprofng: 
+       @: $(MAKE); $(unstage)
+       @r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       test ! -f $(HOST_SUBDIR)/gprofng/Makefile || exit 0; \
+       $(SHELL) $(srcdir)/mkinstalldirs $(HOST_SUBDIR)/gprofng; \
+       $(HOST_EXPORTS)  \
+       echo Configuring in $(HOST_SUBDIR)/gprofng; \
+       cd "$(HOST_SUBDIR)/gprofng" || exit 1; \
+       case $(srcdir) in \
+         /* | [A-Za-z]:[\\/]*) topdir=$(srcdir) ;; \
+         *) topdir=`echo $(HOST_SUBDIR)/gprofng/ | \
+               sed -e 's,\./,,g' -e 's,[^/]*/,../,g' `$(srcdir) ;; \
+       esac; \
+       module_srcdir=gprofng; \
+       $(SHELL) \
+         $$s/$$module_srcdir/configure \
+         --srcdir=$${topdir}/$$module_srcdir \
+         $(HOST_CONFIGARGS) --build=${build_alias} --host=${host_alias} \
+         --target=${target_alias}  \
+         || exit 1
+@endif gprofng
+
+
+
+
+
+.PHONY: all-gprofng maybe-all-gprofng
+maybe-all-gprofng:
+@if gcc-bootstrap
+all-gprofng: stage_current
+@endif gcc-bootstrap
+@if gprofng
+TARGET-gprofng=all
+maybe-all-gprofng: all-gprofng
+all-gprofng: configure-gprofng
+       @: $(MAKE); $(unstage)
+       @r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS)  \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) $(EXTRA_HOST_FLAGS) $(STAGE1_FLAGS_TO_PASS)  \
+               $(TARGET-gprofng))
+@endif gprofng
+
+
+
+
+.PHONY: check-gprofng maybe-check-gprofng
+maybe-check-gprofng:
+@if gprofng
+maybe-check-gprofng: check-gprofng
+
+check-gprofng:
+       @: $(MAKE); $(unstage)
+       @r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS)  \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(FLAGS_TO_PASS)  check)
+
+@endif gprofng
+
+.PHONY: install-gprofng maybe-install-gprofng
+maybe-install-gprofng:
+@if gprofng
+maybe-install-gprofng: install-gprofng
+
+install-gprofng: installdirs
+       @: $(MAKE); $(unstage)
+       @r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(FLAGS_TO_PASS)  install)
+
+@endif gprofng
+
+.PHONY: install-strip-gprofng maybe-install-strip-gprofng
+maybe-install-strip-gprofng:
+@if gprofng
+maybe-install-strip-gprofng: install-strip-gprofng
+
+install-strip-gprofng: installdirs
+       @: $(MAKE); $(unstage)
+       @r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(FLAGS_TO_PASS)  install-strip)
+
+@endif gprofng
+
+# Other targets (info, dvi, pdf, etc.)
+
+.PHONY: maybe-info-gprofng info-gprofng
+maybe-info-gprofng:
+@if gprofng
+maybe-info-gprofng: info-gprofng
+
+info-gprofng: \
+    configure-gprofng 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing info in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 info) \
+         || exit 1
+
+@endif gprofng
+
+.PHONY: maybe-dvi-gprofng dvi-gprofng
+maybe-dvi-gprofng:
+@if gprofng
+maybe-dvi-gprofng: dvi-gprofng
+
+dvi-gprofng: \
+    configure-gprofng 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing dvi in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 dvi) \
+         || exit 1
+
+@endif gprofng
+
+.PHONY: maybe-pdf-gprofng pdf-gprofng
+maybe-pdf-gprofng:
+@if gprofng
+maybe-pdf-gprofng: pdf-gprofng
+
+pdf-gprofng: \
+    configure-gprofng 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing pdf in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 pdf) \
+         || exit 1
+
+@endif gprofng
+
+.PHONY: maybe-html-gprofng html-gprofng
+maybe-html-gprofng:
+@if gprofng
+maybe-html-gprofng: html-gprofng
+
+html-gprofng: \
+    configure-gprofng 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing html in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 html) \
+         || exit 1
+
+@endif gprofng
+
+.PHONY: maybe-TAGS-gprofng TAGS-gprofng
+maybe-TAGS-gprofng:
+@if gprofng
+maybe-TAGS-gprofng: TAGS-gprofng
+
+TAGS-gprofng: \
+    configure-gprofng 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing TAGS in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 TAGS) \
+         || exit 1
+
+@endif gprofng
+
+.PHONY: maybe-install-info-gprofng install-info-gprofng
+maybe-install-info-gprofng:
+@if gprofng
+maybe-install-info-gprofng: install-info-gprofng
+
+install-info-gprofng: \
+    configure-gprofng \
+    info-gprofng 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing install-info in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 install-info) \
+         || exit 1
+
+@endif gprofng
+
+.PHONY: maybe-install-dvi-gprofng install-dvi-gprofng
+maybe-install-dvi-gprofng:
+@if gprofng
+maybe-install-dvi-gprofng: install-dvi-gprofng
+
+install-dvi-gprofng: \
+    configure-gprofng \
+    dvi-gprofng 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing install-dvi in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 install-dvi) \
+         || exit 1
+
+@endif gprofng
+
+.PHONY: maybe-install-pdf-gprofng install-pdf-gprofng
+maybe-install-pdf-gprofng:
+@if gprofng
+maybe-install-pdf-gprofng: install-pdf-gprofng
+
+install-pdf-gprofng: \
+    configure-gprofng \
+    pdf-gprofng 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing install-pdf in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 install-pdf) \
+         || exit 1
+
+@endif gprofng
+
+.PHONY: maybe-install-html-gprofng install-html-gprofng
+maybe-install-html-gprofng:
+@if gprofng
+maybe-install-html-gprofng: install-html-gprofng
+
+install-html-gprofng: \
+    configure-gprofng \
+    html-gprofng 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing install-html in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 install-html) \
+         || exit 1
+
+@endif gprofng
+
+.PHONY: maybe-installcheck-gprofng installcheck-gprofng
+maybe-installcheck-gprofng:
+@if gprofng
+maybe-installcheck-gprofng: installcheck-gprofng
+
+installcheck-gprofng: \
+    configure-gprofng 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing installcheck in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 installcheck) \
+         || exit 1
+
+@endif gprofng
+
+.PHONY: maybe-mostlyclean-gprofng mostlyclean-gprofng
+maybe-mostlyclean-gprofng:
+@if gprofng
+maybe-mostlyclean-gprofng: mostlyclean-gprofng
+
+mostlyclean-gprofng: 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing mostlyclean in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 mostlyclean) \
+         || exit 1
+
+@endif gprofng
+
+.PHONY: maybe-clean-gprofng clean-gprofng
+maybe-clean-gprofng:
+@if gprofng
+maybe-clean-gprofng: clean-gprofng
+
+clean-gprofng: 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing clean in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 clean) \
+         || exit 1
+
+@endif gprofng
+
+.PHONY: maybe-distclean-gprofng distclean-gprofng
+maybe-distclean-gprofng:
+@if gprofng
+maybe-distclean-gprofng: distclean-gprofng
+
+distclean-gprofng: 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing distclean in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 distclean) \
+         || exit 1
+
+@endif gprofng
+
+.PHONY: maybe-maintainer-clean-gprofng maintainer-clean-gprofng
+maybe-maintainer-clean-gprofng:
+@if gprofng
+maybe-maintainer-clean-gprofng: maintainer-clean-gprofng
+
+maintainer-clean-gprofng: 
+       @: $(MAKE); $(unstage)
+       @[ -f ./gprofng/Makefile ] || exit 0; \
+       r=`${PWD_COMMAND}`; export r; \
+       s=`cd $(srcdir); ${PWD_COMMAND}`; export s; \
+       $(HOST_EXPORTS) \
+       for flag in $(EXTRA_HOST_FLAGS) ; do \
+         eval `echo "$$flag" | sed -e "s|^\([^=]*\)=\(.*\)|\1='\2'; export \1|"`; \
+       done; \
+       echo "Doing maintainer-clean in gprofng"; \
+       (cd $(HOST_SUBDIR)/gprofng && \
+         $(MAKE) $(BASE_FLAGS_TO_PASS) "AR=$${AR}" "AS=$${AS}" \
+                 "CC=$${CC}" "CXX=$${CXX}" "LD=$${LD}" "NM=$${NM}" \
+                 "RANLIB=$${RANLIB}" \
+                 "DLLTOOL=$${DLLTOOL}" "WINDRES=$${WINDRES}" "WINDMC=$${WINDMC}" \
+                 maintainer-clean) \
+         || exit 1
+
+@endif gprofng
+
+
+
 .PHONY: configure-intl maybe-configure-intl
 maybe-configure-intl:
 @if gcc-bootstrap
@@ -62838,6 +63326,8 @@ all-stagetrain-gas: maybe-all-stagetrain-intl
 all-stagefeedback-gas: maybe-all-stagefeedback-intl
 all-stageautoprofile-gas: maybe-all-stageautoprofile-intl
 all-stageautofeedback-gas: maybe-all-stageautofeedback-intl
+install-gprofng: maybe-install-opcodes
+install-gprofng: maybe-install-bfd
 configure-ld: maybe-configure-intl
 configure-stage1-ld: maybe-configure-stage1-intl
 configure-stage2-ld: maybe-configure-stage2-intl
@@ -63240,6 +63730,7 @@ configure-gdb: stage_last
 configure-gdbserver: stage_last
 configure-gdbsupport: stage_last
 configure-gprof: stage_last
+configure-gprofng: stage_last
 configure-sid: stage_last
 configure-sim: stage_last
 configure-fastjar: stage_last
@@ -63272,6 +63763,12 @@ all-gprof: maybe-all-bfd
 all-gprof: maybe-all-opcodes
 all-gprof: maybe-all-intl
 all-gprof: maybe-all-gas
+configure-gprofng: maybe-configure-intl
+all-gprofng: maybe-all-libiberty
+all-gprofng: maybe-all-bfd
+all-gprofng: maybe-all-opcodes
+all-gprofng: maybe-all-intl
+all-gprofng: maybe-all-gas
 all-sid: maybe-all-libiberty
 all-sid: maybe-all-bfd
 all-sid: maybe-all-opcodes
index 213f8710c39abfd3fcb03e467600e20ff23cb43f..539849c8815523063585d589691c3202a2640d1d 100644 (file)
@@ -1,3 +1,8 @@
+2022-03-11  Vladimir Mezentsev  <vladimir.mezentsev@oracle.com>
+
+       * MAINTAINERS: Add gprofng maintainer.
+       * README-how-to-make-a-release: Add gprofng.
+
 2022-03-10  Nick Clifton  <nickc@redhat.com>
 
        * dwarf.c (use_debuginfod): New variable.  Set to 1.
index ef12371f353b81aa942228b8633b566614ba4411..fda4a653a9970ff061cf4cf23934c8acc153e9b0 100644 (file)
@@ -84,6 +84,7 @@ responsibility among the other maintainers.
   FRV             Alexandre Oliva <aoliva@sourceware.org>
   GOLD            Ian Lance Taylor <iant@google.com>
   GOLD            Cary Coutant <ccoutant@gmail.com>
+  gprofng         Vladimir Mezentsev <vladimir.mezentsev@oracle.com>
   H8300                   Prafulla Thakare <prafulla.thakare@kpitcummins.com>
   HPPA            Dave Anglin <dave.anglin@bell.net>
   HPPA elf32      Alan Modra <amodra@gmail.com>
index e52d9aebbe401db9953446322f295e7f1520ee5b..5afc6f25ccbb4902090fa9bd01f0dc4a4f61587d 100644 (file)
@@ -35,7 +35,7 @@ Approx time to complete from here: 2 hours ....
      in the gold directory - it has its own release numbering.
 
      Likewise for the ChangeLog files in: bfd, binutils, config, cpu,
-     elfcpp, gas, gold, gprof, include, ld, libctf, libiberty, opcodes
+     elfcpp, gas, gold, gprof, gprofng, include, ld, libctf, libiberty, opcodes
      and toplevel.
 
      Add a note of the name of the new branch to binutils/BRANCHES.
@@ -97,8 +97,8 @@ Approx time to complete from here: 2 hours ....
        m4_define([BFD_VERSION], [2.39.50])
 
      Regenerate various files on both branch and HEAD by configuring
-     with "--enable-maintainer-mode --enable-gold" and then building
-     with "make all-binutils all-gas all-gold all-gprof all-ld"
+     with "--enable-maintainer-mode --enable-gold --enable-shared" and then building
+     with "make all-binutils all-gas all-gold all-gprof all-gprofng all-ld"
 
      Add ChangeLog entries for the updated files.  Commit the changes.
      Make sure that this includes the .pot files as well as the
@@ -114,7 +114,7 @@ Approx time to complete from here: 2 hours ....
          
      b. Create a source tarball of the BRANCH sources:
 
-          ./src-release -x binutils
+          ./src-release.sh -x binutils
 
      c. Build a test target using this tarball.
 
@@ -262,8 +262,8 @@ When the time comes to actually make the release....
        chmod -R -w binutils-2.*
        mkdir build
        cd build
-       ../binutils-2.*/configure --quiet --enable-gold --prefix=`pwd`/install --enable-plugins
-       make all-gas all-gold all-ld all-binutils all-gprof
+       ../binutils-2.*/configure --quiet --enable-gold --prefix=`pwd`/install --enable-plugins --enable-shared
+       make all-gas all-gold all-ld all-binutils all-gprof all-gprofng
        make check-gas check-binutils check-ld check-gold
         make install-gas install-gold install-ld install-binutils
 
index 787fcf891004a6145663d56d7566895e38f0b6c4..26935ebda249dec8b6f528440792cd0b39321c6c 100755 (executable)
--- a/configure
+++ b/configure
@@ -787,6 +787,7 @@ enable_as_accelerator_for
 enable_offload_targets
 enable_gold
 enable_ld
+enable_gprofng
 enable_compressed_debug_sections
 enable_libquadmath
 enable_libquadmath_support
@@ -1514,6 +1515,7 @@ Optional Features:
                           offload target compiler during the build
   --enable-gold[=ARG]     build gold [ARG={default,yes,no}]
   --enable-ld[=ARG]       build ld [ARG={default,yes,no}]
+  --enable-gprofng[=ARG]  build gprofng [ARG={yes,no}]
   --enable-compressed-debug-sections={all,gas,gold,ld,none}
                           Enable compressed debug sections for gas, gold or ld
                           by default
@@ -3072,6 +3074,22 @@ $as_echo "$as_me: WARNING: neither ld nor gold are enabled" >&2;}
     ;;
 esac
 
+# Check whether --enable-gprofng was given.
+if test "${enable_gprofng+set}" = set; then :
+  enableval=$enable_gprofng; enable_gprofng=$enableval
+else
+  enable_gprofng=yes
+fi
+
+if test "$enable_gprofng" = "yes"; then
+  case "${target}" in
+    x86_64-*-linux* | i?86-*-linux* | aarch64-*-linux*)
+    configdirs="$configdirs gprofng"
+    ;;
+  esac
+fi
+
+
 # PR gas/19109
 # Decide the default method for compressing debug sections.
 # Provide a configure time option to override our default.
index 2b10e9a1b0260668cc3851ecfa04d59210d6eca0..da4e41d72479f64d65d07712d5d4d250fa53ccd5 100644 (file)
@@ -392,6 +392,20 @@ case "${ENABLE_LD}" in
     ;;
 esac
 
+AC_ARG_ENABLE(gprofng,
+[AS_HELP_STRING([[--enable-gprofng[=ARG]]],
+               [build gprofng @<:@ARG={yes,no}@:>@])],
+enable_gprofng=$enableval,
+enable_gprofng=yes)
+if test "$enable_gprofng" = "yes"; then
+  case "${target}" in
+    x86_64-*-linux* | i?86-*-linux* | aarch64-*-linux*)
+    configdirs="$configdirs gprofng"
+    ;;
+  esac
+fi
+
+
 # PR gas/19109
 # Decide the default method for compressing debug sections.
 # Provide a configure time option to override our default.
diff --git a/gprofng/Makefile.am b/gprofng/Makefile.am
new file mode 100644 (file)
index 0000000..3bf7074
--- /dev/null
@@ -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/>.
+
+ACLOCAL_AMFLAGS = -I . -I .. 
+
+AUTOMAKE_OPTIONS = dejagnu foreign
+
+if BUILD_COLLECTOR
+    COLLECTOR_SUBDIRS = libcollector
+endif
+if BUILD_SRC
+    SRC_SUBDIRS = src gp-display-html doc
+endif
+SUBDIRS = $(COLLECTOR_SUBDIRS) $(SRC_SUBDIRS)
+DIST_SUBDIRS = libcollector src gp-display-html doc
+
+# Setup the testing framework, if you have one
+EXPECT = expect
+RUNTEST = runtest
+RUNTESTFLAGS =
+
+BASEDIR = $(srcdir)/..
+BFDDIR = $(BASEDIR)/bfd
+jdk_inc = @jdk_inc@
+LD_NO_AS_NEEDED = @LD_NO_AS_NEEDED@
+GPROFNG_CFLAGS = @GPROFNG_CFLAGS@
+GPROFNG_CPPFLAGS = @GPROFNG_CPPFLAGS@
+GPROFNG_LIBDIR = @GPROFNG_LIBDIR@
+
+AM_MAKEFLAGS = \
+       jdk_inc="$(jdk_inc)" \
+       LD_NO_AS_NEEDED="$(LD_NO_AS_NEEDED)" \
+       GPROFNG_CFLAGS="$(GPROFNG_CFLAGS)" \
+       GPROFNG_CPPFLAGS="$(GPROFNG_CPPFLAGS)" \
+       GPROFNG_LIBDIR="$(GPROFNG_LIBDIR)"
+
+if TCL_TRY
+check-DEJAGNU: site.exp development.exp
+       srcroot=`cd $(srcdir) && pwd`; export srcroot; \
+       r=`pwd`; export r; \
+       LC_ALL=C; export LC_ALL; \
+       EXPECT=$(EXPECT); export EXPECT; \
+       jdk_inc="$(jdk_inc)"; export jdk_inc; \
+       runtest=$(RUNTEST); \
+       if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \
+         $$runtest --tool $(DEJATOOL) --srcdir $${srcroot}/testsuite \
+               MAKE="$(MAKE)" CC="$(CC)" CFLAGS="$(CFLAGS) $(PTHREAD_CFLAGS)" \
+               LDFLAGS="$(LDFLAGS)" LIBS="$(PTHREAD_LIBS) $(LIBS)" \
+               BUILDDIR="$(abs_top_builddir)" $(RUNTESTFLAGS); \
+       else echo "WARNING: could not find \`runtest'" 1>&2; :;\
+       fi
+
+development.exp: $(BFDDIR)/development.sh
+       $(EGREP) "(development|experimental)=" $(BFDDIR)/development.sh  \
+         | $(AWK) -F= '{ print "set " $$1 " " $$2 }' > $@
+
+# development.sh is used to determine -Werror default.
+CONFIG_STATUS_DEPENDENCIES = $(BFDDIR)/development.sh
+
+EXTRA_DEJAGNU_SITE_CONFIG = development.exp
+
+DISTCLEANFILES = site.exp development.exp
+endif
+
diff --git a/gprofng/Makefile.in b/gprofng/Makefile.in
new file mode 100644 (file)
index 0000000..08ffdd2
--- /dev/null
@@ -0,0 +1,940 @@
+# 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)/../libtool.m4 \
+       $(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
+       $(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+       $(top_srcdir)/acinclude.m4 $(top_srcdir)/../config/warnings.m4 \
+       $(top_srcdir)/../config/enable.m4 \
+       $(top_srcdir)/../config/ax_pthread.m4 \
+       $(top_srcdir)/config/bison.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) $(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 = config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+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 = 
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+       ctags-recursive dvi-recursive html-recursive info-recursive \
+       install-data-recursive install-dvi-recursive \
+       install-exec-recursive install-html-recursive \
+       install-info-recursive install-pdf-recursive \
+       install-ps-recursive install-recursive installcheck-recursive \
+       installdirs-recursive pdf-recursive ps-recursive \
+       tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive        \
+  distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+  $(RECURSIVE_TARGETS) \
+  $(RECURSIVE_CLEAN_TARGETS) \
+  $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+       cscope distdir dist dist-all distcheck
+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
+DEJATOOL = $(PACKAGE)
+RUNTESTDEFAULTFLAGS = --tool $$tool --srcdir $$srcdir
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../ar-lib \
+       $(top_srcdir)/../compile $(top_srcdir)/../config.guess \
+       $(top_srcdir)/../config.sub $(top_srcdir)/../install-sh \
+       $(top_srcdir)/../ltmain.sh $(top_srcdir)/../missing \
+       $(top_srcdir)/../mkinstalldirs \
+       $(top_srcdir)/common/config.h.in README
+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)
+am__relativize = \
+  dir0=`pwd`; \
+  sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+  sed_rest='s,^[^/]*/*,,'; \
+  sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+  sed_butlast='s,/*[^/]*$$,,'; \
+  while test -n "$$dir1"; do \
+    first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+    if test "$$first" != "."; then \
+      if test "$$first" = ".."; then \
+        dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+        dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+      else \
+        first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+        if test "$$first2" = "$$first"; then \
+          dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+        else \
+          dir2="../$$dir2"; \
+        fi; \
+        dir0="$$dir0"/"$$first"; \
+      fi; \
+    fi; \
+    dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+  done; \
+  reldir="$$dir2"
+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@
+BUILD_SUBDIRS = @BUILD_SUBDIRS@
+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@
+
+# Setup the testing framework, if you have one
+EXPECT = expect
+FGREP = @FGREP@
+GPROFNG_CFLAGS = @GPROFNG_CFLAGS@
+GPROFNG_CPPFLAGS = @GPROFNG_CPPFLAGS@
+GPROFNG_LIBADD = @GPROFNG_LIBADD@
+GPROFNG_LIBDIR = @GPROFNG_LIBDIR@
+GREP = @GREP@
+HELP2MAN = @HELP2MAN@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA = @JAVA@
+JAVAC = @JAVAC@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LD_NO_AS_NEEDED = @LD_NO_AS_NEEDED@
+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@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WERROR = @WERROR@
+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@
+ax_pthread_config = @ax_pthread_config@
+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@
+gprofng_cflags = @gprofng_cflags@
+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@
+jdk_inc = @jdk_inc@
+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@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+ACLOCAL_AMFLAGS = -I . -I .. 
+AUTOMAKE_OPTIONS = dejagnu foreign
+@BUILD_COLLECTOR_TRUE@COLLECTOR_SUBDIRS = libcollector
+@BUILD_SRC_TRUE@SRC_SUBDIRS = src gp-display-html doc
+SUBDIRS = $(COLLECTOR_SUBDIRS) $(SRC_SUBDIRS)
+DIST_SUBDIRS = libcollector src gp-display-html doc
+RUNTEST = runtest
+RUNTESTFLAGS = 
+BASEDIR = $(srcdir)/..
+BFDDIR = $(BASEDIR)/bfd
+AM_MAKEFLAGS = \
+       jdk_inc="$(jdk_inc)" \
+       LD_NO_AS_NEEDED="$(LD_NO_AS_NEEDED)" \
+       GPROFNG_CFLAGS="$(GPROFNG_CFLAGS)" \
+       GPROFNG_CPPFLAGS="$(GPROFNG_CPPFLAGS)" \
+       GPROFNG_LIBDIR="$(GPROFNG_LIBDIR)"
+
+
+# development.sh is used to determine -Werror default.
+@TCL_TRY_TRUE@CONFIG_STATUS_DEPENDENCIES = $(BFDDIR)/development.sh
+@TCL_TRY_TRUE@EXTRA_DEJAGNU_SITE_CONFIG = development.exp
+@TCL_TRY_TRUE@DISTCLEANFILES = site.exp development.exp
+all: config.h
+       $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+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):
+
+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 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 config.h stamp-h1
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+distclean-libtool:
+       -rm -f libtool config.lt
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+#     (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+       @fail=; \
+       if $(am__make_keepgoing); then \
+         failcom='fail=yes'; \
+       else \
+         failcom='exit 1'; \
+       fi; \
+       dot_seen=no; \
+       target=`echo $@ | sed s/-recursive//`; \
+       case "$@" in \
+         distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+         *) list='$(SUBDIRS)' ;; \
+       esac; \
+       for subdir in $$list; do \
+         echo "Making $$target in $$subdir"; \
+         if test "$$subdir" = "."; then \
+           dot_seen=yes; \
+           local_target="$$target-am"; \
+         else \
+           local_target="$$target"; \
+         fi; \
+         ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+         || eval $$failcom; \
+       done; \
+       if test "$$dot_seen" = "no"; then \
+         $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+       fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+       $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+       set x; \
+       here=`pwd`; \
+       if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+         include_option=--etags-include; \
+         empty_fix=.; \
+       else \
+         include_option=--include; \
+         empty_fix=; \
+       fi; \
+       list='$(SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           test ! -f $$subdir/TAGS || \
+             set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+         fi; \
+       done; \
+       $(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-recursive
+
+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-recursive
+
+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
+
+@TCL_TRY_FALSE@check-DEJAGNU: site.exp
+@TCL_TRY_FALSE@        srcdir='$(srcdir)'; export srcdir; \
+@TCL_TRY_FALSE@        EXPECT=$(EXPECT); export EXPECT; \
+@TCL_TRY_FALSE@        if $(SHELL) -c "$(RUNTEST) --version" > /dev/null 2>&1; then \
+@TCL_TRY_FALSE@          exit_status=0; l='$(DEJATOOL)'; for tool in $$l; do \
+@TCL_TRY_FALSE@            if $(RUNTEST) $(AM_RUNTESTFLAGS) $(RUNTESTDEFAULTFLAGS) $(RUNTESTFLAGS); \
+@TCL_TRY_FALSE@            then :; else exit_status=1; fi; \
+@TCL_TRY_FALSE@          done; \
+@TCL_TRY_FALSE@        else echo "WARNING: could not find '$(RUNTEST)'" 1>&2; :;\
+@TCL_TRY_FALSE@        fi; \
+@TCL_TRY_FALSE@        exit $$exit_status
+site.exp: Makefile $(EXTRA_DEJAGNU_SITE_CONFIG)
+       @echo 'Making a new site.exp file ...'
+       @echo '## these variables are automatically generated by make ##' >site.tmp
+       @echo '# Do not edit here.  If you wish to override these values' >>site.tmp
+       @echo '# edit the last section' >>site.tmp
+       @echo 'set srcdir "$(srcdir)"' >>site.tmp
+       @echo "set objdir `pwd`" >>site.tmp
+       @echo 'set build_alias "$(build_alias)"' >>site.tmp
+       @echo 'set build_triplet $(build_triplet)' >>site.tmp
+       @echo 'set host_alias "$(host_alias)"' >>site.tmp
+       @echo 'set host_triplet $(host_triplet)' >>site.tmp
+       @list='$(EXTRA_DEJAGNU_SITE_CONFIG)'; for f in $$list; do \
+         echo "## Begin content included from file $$f.  Do not modify. ##" \
+          && cat `test -f "$$f" || echo '$(srcdir)/'`$$f \
+          && echo "## End content included from file $$f. ##" \
+          || exit 1; \
+        done >> site.tmp
+       @echo "## End of auto-generated content; you can edit from here. ##" >> site.tmp
+       @if test -f site.exp; then \
+          sed -e '1,/^## End of auto-generated content.*##/d' site.exp >> site.tmp; \
+        fi
+       @-rm -f site.bak
+       @test ! -f site.exp || mv site.exp site.bak
+       @mv site.tmp site.exp
+
+distclean-DEJAGNU:
+       -rm -f site.exp site.bak
+       -l='$(DEJATOOL)'; for tool in $$l; do \
+         rm -f $$tool.sum $$tool.log; \
+       done
+
+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
+       @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+         if test "$$subdir" = .; then :; else \
+           $(am__make_dryrun) \
+             || test -d "$(distdir)/$$subdir" \
+             || $(MKDIR_P) "$(distdir)/$$subdir" \
+             || exit 1; \
+           dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+           $(am__relativize); \
+           new_distdir=$$reldir; \
+           dir1=$$subdir; dir2="$(top_distdir)"; \
+           $(am__relativize); \
+           new_top_distdir=$$reldir; \
+           echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+           echo "     am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+           ($(am__cd) $$subdir && \
+             $(MAKE) $(AM_MAKEFLAGS) \
+               top_distdir="$$new_top_distdir" \
+               distdir="$$new_distdir" \
+               am__remove_distdir=: \
+               am__skip_length_check=: \
+               am__skip_mode_fix=: \
+               distdir) \
+             || 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
+       $(MAKE) $(AM_MAKEFLAGS) check-DEJAGNU
+check: check-recursive
+all-am: Makefile config.h
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+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)
+       -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+       -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+       -rm -f Makefile
+distclean-am: clean-am distclean-DEJAGNU distclean-generic \
+       distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+       -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+       -rm -rf $(top_srcdir)/autom4te.cache
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) all check-am install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+       am--refresh check check-DEJAGNU check-am clean clean-cscope \
+       clean-generic 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-DEJAGNU 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-man \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       installdirs-am maintainer-clean maintainer-clean-generic \
+       mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+       ps ps-am tags tags-am uninstall uninstall-am
+
+.PRECIOUS: Makefile
+
+
+@TCL_TRY_TRUE@check-DEJAGNU: site.exp development.exp
+@TCL_TRY_TRUE@ srcroot=`cd $(srcdir) && pwd`; export srcroot; \
+@TCL_TRY_TRUE@ r=`pwd`; export r; \
+@TCL_TRY_TRUE@ LC_ALL=C; export LC_ALL; \
+@TCL_TRY_TRUE@ EXPECT=$(EXPECT); export EXPECT; \
+@TCL_TRY_TRUE@ jdk_inc="$(jdk_inc)"; export jdk_inc; \
+@TCL_TRY_TRUE@ runtest=$(RUNTEST); \
+@TCL_TRY_TRUE@ if $(SHELL) -c "$$runtest --version" > /dev/null 2>&1; then \
+@TCL_TRY_TRUE@   $$runtest --tool $(DEJATOOL) --srcdir $${srcroot}/testsuite \
+@TCL_TRY_TRUE@         MAKE="$(MAKE)" CC="$(CC)" CFLAGS="$(CFLAGS) $(PTHREAD_CFLAGS)" \
+@TCL_TRY_TRUE@         LDFLAGS="$(LDFLAGS)" LIBS="$(PTHREAD_LIBS) $(LIBS)" \
+@TCL_TRY_TRUE@         BUILDDIR="$(abs_top_builddir)" $(RUNTESTFLAGS); \
+@TCL_TRY_TRUE@ else echo "WARNING: could not find \`runtest'" 1>&2; :;\
+@TCL_TRY_TRUE@ fi
+
+@TCL_TRY_TRUE@development.exp: $(BFDDIR)/development.sh
+@TCL_TRY_TRUE@ $(EGREP) "(development|experimental)=" $(BFDDIR)/development.sh  \
+@TCL_TRY_TRUE@   | $(AWK) -F= '{ print "set " $$1 " " $$2 }' > $@
+
+# 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/README b/gprofng/README
new file mode 100644 (file)
index 0000000..66d2e7c
--- /dev/null
@@ -0,0 +1,100 @@
+What is gprofng?
+
+   Gprofng is the GNU Next Generation profiler for analyzing the performance 
+   of Linux applications.  Gprofng allows you to:
+     - Profile C / C++ / Java / Scala applications without needing to recompile
+     - Profile multi-threaded applications
+     - Analyze and compare multiple experiments 
+     - Use time-based sampling and / or hardware event counters
+
+Building gprofng
+
+   Gprofng is distributed with binutils.  To build gprofng, you build binutils.
+   Overview:
+      1. Set paths
+      2. Verify prerequisites 
+      3. Git clone 
+      4. Configure, make, and make install
+   Details follow for each of these.
+
+1. Set paths
+
+   If you are configuring binutils for the default location, it will use:
+       /usr/local
+   In your shell initialization procedure, set your paths using commands 
+   similar to these: 
+      export PATH=/usr/local/bin:$PATH
+      export MANPATH=/usr/local/share/man:$MANPATH
+      export INFOPATH=/usr/local/share/info/:$INFOPATH
+
+2. Verify prerequisites
+
+  To build a recent version of binutils, it is useful to have a developer
+  system with the most recent compilers, libraries, and operating system.
+  Development systems will typically already include most of these: 
+
+     bison  bison-devel  bzip2  elfutils-debuginfod-client-devel 
+     expat-devel  flex  gcc  gcc-c++  git-core  git-core-doc  gmp-devel
+     help2man  libbabeltrace-devel  libipt-devel  m4  make  mpfr-devel 
+     ncurses-devel  perl-Data-Dumper  tar  texinfo  xz  zlib-devel
+     java-17-openjdk-devel 
+
+  CAUTION: The list of prerequisites changes depending on your operating system
+  and changes as binutils evolves.  The list above is a snapshot of the useful
+  packages in early 2022 for Red Hat Enterprise Linux and Oracle Linux. 
+
+  Your system may use other packages; for example, you may be able to use a
+  different version of Java than shown above.  If there are failures, you may
+  need to search for other packages as described in the "Hints" section below.
+
+3. Git clone 
+
+   Select a binutils repository and a branch that you would like 
+   to start from.  For example, to clone from the master at 
+   sourceware.org, you could say: 
+     git clone http://sourceware.org/git/binutils-gdb.git CloneDir
+
+4. Configure, make, and install
+
+   There are many options for configure (see: configure --help).  For example,
+   --prefix sets the destination, as described in the "Hints" section below.
+   If the default destination /usr/local is acceptable for your needs, then
+   after the clone operation finishes, you can simply say:
+
+      mkdir build
+      cd build
+      ../CloneDir/configure
+      make
+      sudo make install
+
+Getting started
+
+  To start using gprofng, see the tutorial available by saying:
+      info gprofng
+
+Hints and tips for building binutils
+
+  - Use the script(1) command to write a log of your build.
+
+  - If you run multiple commands at once (for example: make --jobs=10) then you
+    should also use make option:
+          --output-sync
+    Without --output-sync, the log would be difficult to interpret.
+
+  - Search the log for errors and warnings, for example:
+        configure: WARNING: <package> is missing or unusable; some features 
+                   may be unavailable. 
+    The above message suggests that <package> may be needed on your system.
+
+  - Sometimes the above message is not sufficiently specific to guide you to
+    the right package.  In the directory where the failure happens, config.log
+    may identify a specific missing file, and your package manager may allow
+    you to search for it. For example, if build/gprofng/config.log shows that
+    javac is missing, and if your package manager is dnf, you could try:
+       dnf --repo='*' whatprovides '*/javac'
+
+  - You can set a custom destination directory using configure --prefix.
+    This is useful if you prefer not to change /usr/local, or if you are not
+    allowed to do so.  If you set a custom prefix, be sure to change all three
+    paths mentioned in the PATH section above.
+
diff --git a/gprofng/acinclude.m4 b/gprofng/acinclude.m4
new file mode 100644 (file)
index 0000000..966da18
--- /dev/null
@@ -0,0 +1,4 @@
+m4_include([../config/warnings.m4])
+m4_include([../config/enable.m4])
+m4_include([../config/ax_pthread.m4])
+m4_include([config/bison.m4])
diff --git a/gprofng/aclocal.m4 b/gprofng/aclocal.m4
new file mode 100644 (file)
index 0000000..02b07b9
--- /dev/null
@@ -0,0 +1,1254 @@
+# 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])])
+
+# Copyright (C) 2003-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.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot.  For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[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
+AC_SUBST([am__leading_dot])])
+
+# 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([../libtool.m4])
+m4_include([../ltoptions.m4])
+m4_include([../ltsugar.m4])
+m4_include([../ltversion.m4])
+m4_include([../lt~obsolete.m4])
+m4_include([acinclude.m4])
diff --git a/gprofng/common/cc_libcollector.h b/gprofng/common/cc_libcollector.h
new file mode 100644 (file)
index 0000000..e078541
--- /dev/null
@@ -0,0 +1,44 @@
+/* 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.  */
+
+/*
+ *  This file describes the enum's, etc. shared by the collector control
+ *     class and libcollector and its modules.  It is #included in collctrl.h
+ *     so any changes to it should follow the procedure described there.
+ */
+
+#ifndef _CC_LIBCOLLECTOR_H
+#define _CC_LIBCOLLECTOR_H
+
+/* definitions for synchronization tracing scope -- a bit mask */
+#define SYNCSCOPE_NATIVE    0x1
+#define SYNCSCOPE_JAVA      0x2
+
+typedef enum
+{
+  FOLLOW_NONE  = 0x0,
+  FOLLOW_EXEC  = 0x1,
+  FOLLOW_FORK  = 0x2,
+  FOLLOW_ON    = 0x3,
+  FOLLOW_COMBO = 0x4,
+  FOLLOW_ALL   = 0x7
+} Follow_type;
+
+#endif /* !__CC_LIBCOLLECTOR_H */
diff --git a/gprofng/common/config.h.in b/gprofng/common/config.h.in
new file mode 100644 (file)
index 0000000..e46e64f
--- /dev/null
@@ -0,0 +1,117 @@
+/* common/config.h.in.  Generated from configure.ac by autoheader.  */
+
+/* Enable debugging output. */
+#undef DEBUG
+
+/* Enable java profiling */
+#undef GPROFNG_JAVA_PROFILING
+
+/* Define to 1 if you have the declaration of `basename', and to 0 if you
+   don't. */
+#undef HAVE_DECL_BASENAME
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if you have POSIX threads libraries and header files. */
+#undef HAVE_PTHREAD
+
+/* Have PTHREAD_PRIO_INHERIT. */
+#undef HAVE_PTHREAD_PRIO_INHERIT
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define to 1 if you have the `strsignal' function. */
+#undef HAVE_STRSIGNAL
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+   */
+#undef LT_OBJDIR
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+   your system. */
+#undef PTHREAD_CREATE_JOINABLE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
diff --git a/gprofng/common/core_pcbe.c b/gprofng/common/core_pcbe.c
new file mode 100644 (file)
index 0000000..6f746d8
--- /dev/null
@@ -0,0 +1,3023 @@
+/* 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.  */
+
+/*
+ * Performance Counter Back-End for Intel Family 6
+ *   Models 15(06_0FH) 23(06_17H)                       (Core 2)
+ *   Models 28(06_1CH)                                  (Atom)
+ *   Models 37(06_25H) 44(06_2CH)                       (Westmere)
+ *   Models 26(06_1AH) 30(06_1EH) 31(06_1FH) 46(06_2EH) (Nehalem)
+ *   Models 42(06_2AH) 45(06_2DH)                       (Sandy Bridge)
+ *   Models 58(06_3AH) 62(06_3EH)                       (Ivy Bridge)
+ *   Models 60(06_3CH) 63(06_3FH) 69(06_45H) 70(06_46H) (Haswell)
+ *   Models 61(06_3DH) 71(06_47H) 79(06_4FH) 86(06_??H) (Broadwell) (79 not listed in Intel SDM as of June 2015)
+ *   Models 78(06_4EH) 85(06_55H) 94(06_5EH)            (Skylake) (Note Skylake and later: versionID==4)
+ * To add another model number:
+ *   - add appropriate table data in the form
+ *       #define EVENTS_FAM6_MODXX
+ *   - add appropriate table definitions in the form
+ *       const struct events_table_t events_fam6_modXX[] =
+ *   - set events_table to the appropriate table
+ *     using the "switch ( cpuid_getmodel(CPU) )" statement
+ *     in core_pcbe_init()
+ *   - check the date in core_pcbe_cpuref()
+ * Table data can be derived from:
+ *   - the Intel SDM
+ *       also https://download.01.org/perfmon/
+ *   - libcpc source code in usr/src/uts/intel/pcbe/
+ *   - libpfm4
+ * but there are typically inconsistencies among these
+ * sources of data.  So, judgment is required.
+ * Other things to do to add a new processor:
+ *   x file hwc_cpus.h
+ *     add a cpuver enumerator
+ *     add lookup entry
+ *   x file hwctable.c
+ *     add a table (aliases, etc.)
+ *     add a cputabs entry, including default metrics
+ *     look for other places where the most-recently-added CPU is mentioned
+ *   x file cpu_frequency.h
+ *     function get_max_turbo_freq()
+ *     go to "switch (model)", and add turbo boosts
+ */
+
+#include <sys/types.h>
+#include "hwcdrv.h"
+
+static uint64_t num_gpc;    /* number of general purpose counters (e.g. 2-4) */
+static uint64_t num_ffc;    /* number fixed function counters (e.g. 3) */
+static uint_t total_pmc;    /* num_gpc + num_ffc */
+
+/*
+ * Only the lower 32-bits can be written to in the general-purpose
+ * counters.  The higher bits are extended from bit 31; all ones if
+ * bit 31 is one and all zeros otherwise.
+ *
+ * The fixed-function counters do not have this restriction.
+ */
+
+static const char *ffc_names[] = {
+/*
+ * While modern Intel processors have fixed-function counters (FFCs),
+ * on Linux we access HWCs through the perf_event_open() kernel interface,
+ * which does not allow us direct access to the FFCs.
+ * Rather, the Linux kernel manages registers opaquely.
+ * At best, it allows us extra HW events by off-loading
+ * HWCs to FFCs as available.  Often, however, the FFCs
+ * are commandeered by other activities like the NMI watchdog.
+ * We will omit any explicit reference to them.
+ * https://lists.eecs.utk.edu/pipermail/perfapi-devel/2015-February/006895.html
+ * See also bug 21315497.
+ */
+#if 0
+       "instr_retired.any",
+       "cpu_clk_unhalted.core",
+       "cpu_clk_unhalted.ref",
+#endif
+       NULL
+};
+
+#define IMPL_NAME_LEN   100
+static char core_impl_name[IMPL_NAME_LEN];
+
+/*
+ * Most events require only an event code and a umask.
+ * Some also require attributes, cmasks, or MSR programming.
+ * Until Sandy Bridge, the number of these other events
+ * was small and libcpc just ignored them.
+ * With Sandy Bridge, libcpc added for support for these
+ * additional events.
+ *
+ * We use an expanded events_table_t here -- patterned
+ * after snb_pcbe_events_table_t in libcpc's
+ * usr/src/uts/intel/pcbe/snb_pcbe.h -- for all processors.
+ *
+ * Correspondingly, we also define ATTR_* macros, but we
+ * define them to set bits as they will appear
+ * in bits 16-23 of the final eventsel.  Definitions of those
+ * bits can be found in "struct ia32_perfevtsel" in libcpc's
+ * usr/src/uts/intel/pcbe/intel_pcbe_utils.h .
+ *
+ * For now, I don't know how to handle msr_offset.
+ * So, let's not include events that call for it.
+ *
+ * For now, don't do anything with ATTR_PEBS other than
+ * to note it in tables (starting with Haswell).
+ *
+ * Solaris tables also have ATTR_PEBS_ONLY.  We cannot
+ * use these counters from "collect -h" and so do not
+ * include them.
+ */
+#define ATTR_NONE               0
+#define ATTR_EDGE               (1 << 2) /* bit 18 - offset 16 */
+#define ATTR_ANY                (1 << 5) /* bit 21 - offset 16 */
+#define ATTR_INV                (1 << 7) /* bit 23 - offset 16 */
+#define ATTR_PEBS               ATTR_NONE // PEBS not supported
+#define ATTR_TSX                ATTR_NONE // TSX MSRs not supported
+#undef ATTR_PEBS_ONLY           // PEBS-only event, not supported
+#undef ATTR_PEBS_ONLY_LD_LAT    // not supported
+
+struct events_table_t
+{
+  uint32_t eventselect;
+  uint32_t unitmask;
+  uint64_t supported_counters;
+  const char *name;
+  uint8_t cmask;
+  uint8_t attrs;
+  uint16_t msr_offset;
+};
+
+/* Used to describe which counters support an event */
+#define C(x)    (1 << (x))
+#define C0      C(0)
+#define C1      C(1)
+#define C2      C(2)
+#define C3      C(3)
+#define C_ALL   0xFFFFFFFFFFFFFFFF
+#define CDEAD   0 /* Counter that is broken  */
+
+/* note that regular events use the original spelling like "inst_retired.any_p" */
+#define        ARCH_EVENTS /* NOTE: Order specified in PRM must be maintained! */ \
+{ 0x3C, 0x00, C_ALL, "unhalted-core-cycles"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x01, C_ALL, "unhalted-reference-cycles"    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC0, 0x00, C_ALL, "instruction-retired"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2E, 0x4F, C_ALL, "llc-reference"    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2E, 0x41, C_ALL, "llc-misses"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x00, C_ALL, "branch-instruction-retired"   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x00, C_ALL, "branch-misses-retired"        , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+/*
+ * FAM6/MOD15:
+ *  Xeon 3000, 3200, 5100, 5300, 7300
+ *  Core 2 Quad, Extreme, and Duo
+ *  Pentium dual-core processors
+ * FAM6/MOD23:
+ *  Xeon 5200, 5400 series, Intel
+ *  Core 2 Quad Q9650.
+ */
+#define EVENTS_FAM6_MOD23                                               \
+{ 0x03, 0x00, C0|C1, "load_block"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x03, 0x02, C0|C1, "load_block.sta"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x03, 0x04, C0|C1, "load_block.std"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x03, 0x08, C0|C1, "load_block.overlap_store"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x03, 0x10, C0|C1, "load_block.until_retire"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x03, 0x20, C0|C1, "load_block.l1d"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x04, 0x00, C0|C1, "store_block"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x04, 0x01, C0|C1, "store_block.drain_cycles" /*spell-diff*/    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x04, 0x02, C0|C1, "store_block.order"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x04, 0x08, C0|C1, "store_block.snoop"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x05, 0x00, C0|C1, "misalign_mem_ref"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x06, 0x00, C0|C1, "segment_reg_loads"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x00, C0|C1, "sse_pre_exec"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x00, C0|C1, "sse_pre_exec.nta"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x01, C0|C1, "sse_pre_exec.l1"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x02, C0|C1, "sse_pre_exec.l2"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x03, C0|C1, "sse_pre_exec.stores"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x00, C0|C1, "dtlb_misses"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x01, C0|C1, "dtlb_misses.any"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x02, C0|C1, "dtlb_misses.miss_ld"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x04, C0|C1, "dtlb_misses.l0_miss_ld"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x08, C0|C1, "dtlb_misses.miss_st"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x09, 0x00, C0|C1, "memory_disambiguation"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x09, 0x01, C0|C1, "memory_disambiguation.reset"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x09, 0x02, C0|C1, "memory_disambiguation.success"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0c, 0x00, C0|C1, "page_walks"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0c, 0x01, C0|C1, "page_walks.count"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0c, 0x02, C0|C1, "page_walks.cycles"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x00, C0   , "fp_comp_ops_exe"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x11, 0x00,    C1, "fp_assist"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x00,    C1, "mul"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x13, 0x00,    C1, "div"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x14, 0x00, C0   , "cycles_div_busy"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x18, 0x00, C0   , "idle_during_div"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x19, 0x00,    C1, "delayed_bypass"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x19, 0x00,    C1, "delayed_bypass.fp"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x19, 0x01,    C1, "delayed_bypass.simd"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x19, 0x02,    C1, "delayed_bypass.load"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x21, 0x00, C0|C1, "l2_ads"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x23, 0x00, C0|C1, "l2_dbus_busy_rd"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x00, C0|C1, "l2_lines_in"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x25, 0x00, C0|C1, "l2_m_lines_in"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x00, C0|C1, "l2_lines_out"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x00, C0|C1, "l2_m_lines_out"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x00, C0|C1, "l2_ifetch"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x29, 0x00, C0|C1, "l2_ld"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2a, 0x00, C0|C1, "l2_st"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2b, 0x00, C0|C1, "l2_lock"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2e, 0x00, C0|C1, "l2_rqsts"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2e, 0x41, C0|C1, "l2_rqsts.self.demand.i_state"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2e, 0x4f, C0|C1, "l2_rqsts.self.demand.mesi"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x30, 0x00, C0|C1, "l2_reject_busq"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x32, 0x00, C0|C1, "l2_no_req"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3a, 0x00, C0|C1, "eist_trans"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3b, 0xc0, C0|C1, "thermal_trip" /*non-zero umask*/      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3c, 0x00, C0|C1, "cpu_clk_unhalted"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3c, 0x00, C0|C1, "cpu_clk_unhalted.core_p"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3c, 0x01, C0|C1, "cpu_clk_unhalted.bus"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3c, 0x02, C0|C1, "cpu_clk_unhalted.no_other"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x40, 0x00, C0|C1, "l1d_cache_ld"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x41, 0x00, C0|C1, "l1d_cache_st"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x42, 0x00, C0|C1, "l1d_cache_lock"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x42, 0x10, C0|C1, "l1d_cache_lock.duration" /*spelling*/ , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x43, 0x00, C0|C1, "l1d_all"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x43, 0x00, C0|C1, "l1d_all_ref"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x43, 0x01, C0|C1, "l1d_all.ref" /*spelling*/             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x43, 0x02, C0|C1, "l1d_all.cache_ref" /*spelling*/       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x45, 0x0f, C0|C1, "l1d_repl" /*non-zero umask*/          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x46, 0x00, C0|C1, "l1d_m_repl"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x47, 0x00, C0|C1, "l1d_m_evict"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x00, C0|C1, "l1d_pend_miss"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x00, C0|C1, "l1d_split"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x01, C0|C1, "l1d_split.loads"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x02, C0|C1, "l1d_split.stores"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4b, 0x00, C0|C1, "sse_pre_miss"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4b, 0x00, C0|C1, "sse_pre_miss.nta"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4b, 0x01, C0|C1, "sse_pre_miss.l1"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4b, 0x02, C0|C1, "sse_pre_miss.l2"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4c, 0x00, C0|C1, "load_hit_pre"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4e, 0x00, C0|C1, "l1d_prefetch"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4e, 0x10, C0|C1, "l1d_prefetch.requests"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x00, C0|C1, "bus_request_outstanding"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x61, 0x00, C0|C1, "bus_bnr_drv"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x62, 0x00, C0|C1, "bus_drdy_clocks"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x63, 0x00, C0|C1, "bus_lock_clocks"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x64, 0x00, C0|C1, "bus_data_rcv"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x65, 0x00, C0|C1, "bus_trans_brd"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x66, 0x00, C0|C1, "bus_trans_rfo"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x67, 0x00, C0|C1, "bus_trans_wb"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x68, 0x00, C0|C1, "bus_trans_ifetch"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x69, 0x00, C0|C1, "bus_trans_inval"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6a, 0x00, C0|C1, "bus_trans_pwr"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6b, 0x00, C0|C1, "bus_trans_p"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6c, 0x00, C0|C1, "bus_trans_io"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6d, 0x00, C0|C1, "bus_trans_def"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6e, 0x00, C0|C1, "bus_trans_burst"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6f, 0x00, C0|C1, "bus_trans_mem"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x70, 0x00, C0|C1, "bus_trans_any"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x77, 0x00, C0|C1, "ext_snoop"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x78, 0x00, C0|C1, "cmp_snoop"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x7a, 0x00, C0|C1, "bus_hit_drv"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x7b, 0x00, C0|C1, "bus_hitm_drv"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x7d, 0x00, C0|C1, "busq_empty"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x7e, 0x00, C0|C1, "snoop_stall_drv"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x7f, 0x00, C0|C1, "bus_io_wait"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x00, C0|C1, "l1i_reads"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x81, 0x00, C0|C1, "l1i_misses"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x82, 0x00, C0|C1, "itlb"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x82, 0x02, C0|C1, "itlb.small_miss"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x82, 0x10, C0|C1, "itlb.large_miss"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x82, 0x12, C0|C1, "itlb.misses"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x82, 0x40, C0|C1, "itlb.flush"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x83, 0x00, C0|C1, "inst_queue"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x83, 0x02, C0|C1, "inst_queue.full"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x86, 0x00, C0|C1, "cycles_l1i_mem_stalled"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x00, C0|C1, "ild_stall"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x00, C0|C1, "br_inst_exec"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x00, C0|C1, "br_missp_exec"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x8a, 0x00, C0|C1, "br_bac_missp_exec"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x8b, 0x00, C0|C1, "br_cnd_exec"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x8c, 0x00, C0|C1, "br_cnd_missp_exec"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x8d, 0x00, C0|C1, "br_ind_exec"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x8e, 0x00, C0|C1, "br_ind_missp_exec"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x8f, 0x00, C0|C1, "br_ret_exec"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x90, 0x00, C0|C1, "br_ret_missp_exec"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x91, 0x00, C0|C1, "br_ret_bac_missp_exec"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x92, 0x00, C0|C1, "br_call_exec"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x93, 0x00, C0|C1, "br_call_missp_exec"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x94, 0x00, C0|C1, "br_ind_call_exec"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x97, 0x00, C0|C1, "br_tkn_bubble_1"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x98, 0x00, C0|C1, "br_tkn_bubble_2"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xa0, 0x00, C0|C1, "rs_uops_dispatched"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xa1, 0x00, C0   , "rs_uops_dispatched_port"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xa1, 0x01, C0   , "rs_uops_dispatched_port.0" /*spelling*/     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xa1, 0x02, C0   , "rs_uops_dispatched_port.1" /*spelling*/     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xa1, 0x04, C0   , "rs_uops_dispatched_port.2" /*spelling*/     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xa1, 0x08, C0   , "rs_uops_dispatched_port.3" /*spelling*/     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xa1, 0x10, C0   , "rs_uops_dispatched_port.4" /*spelling*/     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xa1, 0x20, C0   , "rs_uops_dispatched_port.5" /*spelling*/     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xaa, 0x00, C0|C1, "macro_insts"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xaa, 0x01, C0|C1, "macro_insts.decoded"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xaa, 0x08, C0|C1, "macro_insts.cisc_decoded"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xab, 0x00, C0|C1, "esp"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xab, 0x01, C0|C1, "esp.synch"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xab, 0x02, C0|C1, "esp.additions"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb0, 0x00, C0|C1, "simd_uops_exec"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb1, 0x00, C0|C1, "simd_sat_uop_exec"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x00, C0|C1, "simd_uop_type_exec"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x01, C0|C1, "simd_uop_type_exec.mul"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x02, C0|C1, "simd_uop_type_exec.shift"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x04, C0|C1, "simd_uop_type_exec.pack"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x08, C0|C1, "simd_uop_type_exec.unpack"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x10, C0|C1, "simd_uop_type_exec.logical"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x20, C0|C1, "simd_uop_type_exec.arithmetic"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc0, 0x00, C0|C1, "inst_retired"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc0, 0x00, C0|C1, "inst_retired.any_p"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc0, 0x01, C0|C1, "inst_retired.loads"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc0, 0x02, C0|C1, "inst_retired.stores"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc0, 0x04, C0|C1, "inst_retired.other"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc0, 0x08, C0|C1, "inst_retired.vm_h"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc1, 0x00, C0|C1, "x87_ops_retired"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc1, 0x01, C0|C1, "x87_ops_retired.fxch"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc1, 0xfe, C0|C1, "x87_ops_retired.any"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc2, 0x00, C0|C1, "uops_retired"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc2, 0x01, C0|C1, "uops_retired.ld_ind_br"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc2, 0x02, C0|C1, "uops_retired.std_sta"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc2, 0x04, C0|C1, "uops_retired.macro_fusion"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc2, 0x07, C0|C1, "uops_retired.fused"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc2, 0x08, C0|C1, "uops_retired.non_fused"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc2, 0x0f, C0|C1, "uops_retired.any"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc3, 0x00, C0|C1, "machine_nukes"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc3, 0x01, C0|C1, "machine_nukes.smc"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc3, 0x04, C0|C1, "machine_nukes.mem_order"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x00, C0|C1, "br_inst_retired"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x00, C0|C1, "br_inst_retired.any"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x01, C0|C1, "br_inst_retired.pred_not_taken"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x02, C0|C1, "br_inst_retired.mispred_not_taken"    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x04, C0|C1, "br_inst_retired.pred_taken"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x08, C0|C1, "br_inst_retired.mispred_taken"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x0c, C0|C1, "br_inst_retired.taken"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc5, 0x00, C0|C1, "br_inst_retired_mispred"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc5, 0x00, C0|C1, "br_inst_retired.mispred" /*alt-spelling*/   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc6, 0x00, C0|C1, "cycles_int"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc6, 0x01, C0|C1, "cycles_int.masked" /*spelling*/       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc6, 0x02, C0|C1, "cycles_int.pending_and_masked" /*spelling*/ , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc7, 0x00, C0|C1, "simd_inst_retired"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc7, 0x01, C0|C1, "simd_inst_retired.packed_single"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc7, 0x02, C0|C1, "simd_inst_retired.scalar_single"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc7, 0x04, C0|C1, "simd_inst_retired.packed_double"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc7, 0x08, C0|C1, "simd_inst_retired.scalar_double"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc7, 0x10, C0|C1, "simd_inst_retired.vector"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc7, 0x1f, C0|C1, "simd_inst_retired.any"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc8, 0x00, C0|C1, "hw_int_rcv"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc9, 0x00, C0|C1, "itlb_miss_retired"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xca, 0x00, C0|C1, "simd_comp_inst_retired"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xca, 0x01, C0|C1, "simd_comp_inst_retired.packed_single" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xca, 0x02, C0|C1, "simd_comp_inst_retired.scalar_single" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xca, 0x04, C0|C1, "simd_comp_inst_retired.packed_double" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xca, 0x08, C0|C1, "simd_comp_inst_retired.scalar_double" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcb, 0x00, C0   , "mem_load_retired"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcb, 0x01, C0   , "mem_load_retired.l1d_miss"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcb, 0x02, C0   , "mem_load_retired.l1d_line_miss"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcb, 0x04, C0   , "mem_load_retired.l2_miss"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcb, 0x08, C0   , "mem_load_retired.l2_line_miss"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcb, 0x10, C0   , "mem_load_retired.dtlb_miss"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcc, 0x00, C0|C1, "fp_mmx_trans"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcc, 0x01, C0|C1, "fp_mmx_trans.to_mmx" /*spelling*/     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcc, 0x02, C0|C1, "fp_mmx_trans.to_fp" /*spelling*/      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcd, 0x00, C0|C1, "simd_assist"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xce, 0x00, C0|C1, "simd_instr_retired"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcf, 0x00, C0|C1, "simd_sat_instr_retired"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd2, 0x00, C0|C1, "rat_stalls"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd2, 0x01, C0|C1, "rat_stalls.rob_read_port"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd2, 0x02, C0|C1, "rat_stalls.partial_cycles"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd2, 0x04, C0|C1, "rat_stalls.flags"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd2, 0x08, C0|C1, "rat_stalls.fpsw"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd2, 0x0f, C0|C1, "rat_stalls.any"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd2, 0x10, C0|C1, "rat_stalls.other_serialization_stalls", 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd4, 0x00, C0|C1, "seg_rename_stalls"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd4, 0x01, C0|C1, "seg_rename_stalls.es"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd4, 0x02, C0|C1, "seg_rename_stalls.ds"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd4, 0x04, C0|C1, "seg_rename_stalls.fs"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd4, 0x08, C0|C1, "seg_rename_stalls.gs"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd4, 0x0f, C0|C1, "seg_rename_stalls.any"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd5, 0x00, C0|C1, "seg_reg_renames"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd5, 0x01, C0|C1, "seg_reg_renames.es"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd5, 0x02, C0|C1, "seg_reg_renames.ds"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd5, 0x04, C0|C1, "seg_reg_renames.fs"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd5, 0x08, C0|C1, "seg_reg_renames.gs"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xd5, 0x0f, C0|C1, "seg_reg_renames.any"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xdc, 0x00, C0|C1, "resource_stalls"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xdc, 0x01, C0|C1, "resource_stalls.rob_full"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xdc, 0x02, C0|C1, "resource_stalls.rs_full"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xdc, 0x04, C0|C1, "resource_stalls.ld_st"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xdc, 0x08, C0|C1, "resource_stalls.fpcw"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xdc, 0x10, C0|C1, "resource_stalls.br_miss_clear"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xdc, 0x1f, C0|C1, "resource_stalls.any"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xe0, 0x00, C0|C1, "br_inst_decoded"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xe4, 0x00, C0|C1, "bogus_br"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xe6, 0x00, C0|C1, "baclears"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xf0, 0x00, C0|C1, "pref_rqsts_up"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xf8, 0x00, C0|C1, "pref_rqsts_dn"                        , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+/* FAM6 MOD28: Intel Atom processor */
+#define EVENTS_FAM6_MOD28                                               \
+{ 0x02, 0x81, C0|C1, "store_forwards.good"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x06, 0x00, C0|C1, "segment_reg_loads.any"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x01, C0|C1, "prefetch.prefetcht0"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x06, C0|C1, "prefetch.sw_l2"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x08, C0|C1, "prefetch.prefetchnta"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x05, C0|C1, "data_tlb_misses.dtlb_miss_ld"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x06, C0|C1, "data_tlb_misses.dtlb_miss_st"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x07, C0|C1, "data_tlb_misses.dtlb_miss"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x09, C0|C1, "data_tlb_misses.l0_dtlb_miss_ld"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0c, 0x03, C0|C1, "page_walks.cycles"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x01, C0|C1, "x87_comp_ops_exe.any.s"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x81, C0|C1, "x87_comp_ops_exe.any.ar"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x11, 0x01, C0|C1, "fp_assist"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x11, 0x81, C0|C1, "fp_assist.ar"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x01, C0|C1, "mul.s"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x81, C0|C1, "mul.ar"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x13, 0x01, C0|C1, "div.s"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x13, 0x81, C0|C1, "div.ar"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x14, 0x01, C0|C1, "cycles_div_busy"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x21, 0x00, C0|C1, "l2_ads"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x22, 0x00, C0|C1, "l2_dbus_busy"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x00, C0|C1, "l2_lines_in"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x25, 0x00, C0|C1, "l2_m_lines_in"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x00, C0|C1, "l2_lines_out"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x00, C0|C1, "l2_m_lines_out"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x00, C0|C1, "l2_ifetch"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x29, 0x00, C0|C1, "l2_ld"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2a, 0x00, C0|C1, "l2_st"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2b, 0x00, C0|C1, "l2_lock"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2e, 0x00, C0|C1, "l2_rqsts"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2e, 0x41, C0|C1, "l2_rqsts.self.demand.i_state"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2e, 0x4f, C0|C1, "l2_rqsts.self.demand.mesi"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x30, 0x00, C0|C1, "l2_reject_busq"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x32, 0x00, C0|C1, "l2_no_req"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3a, 0x00, C0|C1, "eist_trans"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3b, 0xc0, C0|C1, "thermal_trip"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3c, 0x00, C0|C1, "cpu_clk_unhalted.core_p"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3c, 0x01, C0|C1, "cpu_clk_unhalted.bus"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3c, 0x02, C0|C1, "cpu_clk_unhalted.no_other"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x40, 0x21, C0|C1, "l1d_cache.ld"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x40, 0x22, C0|C1, "l1d_cache.st"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x00, C0|C1, "bus_request_outstanding"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x61, 0x00, C0|C1, "bus_bnr_drv"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x62, 0x00, C0|C1, "bus_drdy_clocks"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x63, 0x00, C0|C1, "bus_lock_clocks"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x64, 0x00, C0|C1, "bus_data_rcv"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x65, 0x00, C0|C1, "bus_trans_brd"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x66, 0x00, C0|C1, "bus_trans_rfo"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x67, 0x00, C0|C1, "bus_trans_wb"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x68, 0x00, C0|C1, "bus_trans_ifetch"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x69, 0x00, C0|C1, "bus_trans_inval"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6a, 0x00, C0|C1, "bus_trans_pwr"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6b, 0x00, C0|C1, "bus_trans_p"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6c, 0x00, C0|C1, "bus_trans_io"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6d, 0x00, C0|C1, "bus_trans_def"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6e, 0x00, C0|C1, "bus_trans_burst"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6f, 0x00, C0|C1, "bus_trans_mem"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x70, 0x00, C0|C1, "bus_trans_any"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x77, 0x00, C0|C1, "ext_snoop"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x7a, 0x00, C0|C1, "bus_hit_drv"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x7b, 0x00, C0|C1, "bus_hitm_drv"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x7d, 0x00, C0|C1, "busq_empty"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x7e, 0x00, C0|C1, "snoop_stall_drv"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x7f, 0x00, C0|C1, "bus_io_wait"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x02, C0|C1, "icache.misses"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x03, C0|C1, "icache.accesses"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x82, 0x02, C0|C1, "itlb.misses"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x82, 0x04, C0|C1, "itlb.flush"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xaa, 0x02, C0|C1, "macro_insts.cisc_decoded"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xaa, 0x03, C0|C1, "macro_insts.all_decoded"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb0, 0x00, C0|C1, "simd_uops_exec.s"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb0, 0x80, C0|C1, "simd_uops_exec.ar"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb1, 0x00, C0|C1, "simd_sat_uop_exec.s"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb1, 0x80, C0|C1, "simd_sat_uop_exec.ar"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x01, C0|C1, "simd_uop_type_exec.mul.s"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x02, C0|C1, "simd_uop_type_exec.shift.s"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x04, C0|C1, "simd_uop_type_exec.pack.s"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x08, C0|C1, "simd_uop_type_exec.unpack.s"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x10, C0|C1, "simd_uop_type_exec.logical.s"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x20, C0|C1, "simd_uop_type_exec.arithmetic.s"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x81, C0|C1, "simd_uop_type_exec.mul.ar"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x82, C0|C1, "simd_uop_type_exec.shift.ar"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x84, C0|C1, "simd_uop_type_exec.pack.ar"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x88, C0|C1, "simd_uop_type_exec.unpack.ar"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0x90, C0|C1, "simd_uop_type_exec.logical.ar"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xb3, 0xa0, C0|C1, "simd_uop_type_exec.arithmetic.ar"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc0, 0x00, C0|C1, "inst_retired.any_p"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc2, 0x10, C0|C1, "uops_retired.any"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc3, 0x01, C0|C1, "machine_clears.smc"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x00, C0|C1, "br_inst_retired.any"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x01, C0|C1, "br_inst_retired.pred_not_taken"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x02, C0|C1, "br_inst_retired.mispred_not_taken"    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x04, C0|C1, "br_inst_retired.pred_taken"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x08, C0|C1, "br_inst_retired.mispred_taken"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x0a, C0|C1, "br_inst_retired.mispred"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x0c, C0|C1, "br_inst_retired.taken"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x0f, C0|C1, "br_inst_retired.any1"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc5, 0x00, C0|C1, "br_inst_retired.mispred"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc6, 0x01, C0|C1, "cycles_int_masked.cycles_int_masked"  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc6, 0x02, C0|C1, "cycles_int_masked.cycles_int_pending_and_masked" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc7, 0x01, C0|C1, "simd_inst_retired.packed_single"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc7, 0x02, C0|C1, "simd_inst_retired.scalar_single"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc7, 0x04, C0|C1, "simd_inst_retired.packed_double"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc7, 0x08, C0|C1, "simd_inst_retired.scalar_double"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc7, 0x10, C0|C1, "simd_inst_retired.vector"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc7, 0x1f, C0|C1, "simd_inst_retired.any"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc8, 0x00, C0|C1, "hw_int_rcv"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xca, 0x01, C0|C1, "simd_comp_inst_retired.packed_single" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xca, 0x02, C0|C1, "simd_comp_inst_retired.scalar_single" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xca, 0x04, C0|C1, "simd_comp_inst_retired.packed_double" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xca, 0x08, C0|C1, "simd_comp_inst_retired.scalar_double" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcb, 0x01, C0|C1, "mem_load_retired.l2_hit"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcb, 0x02, C0|C1, "mem_load_retired.l2_miss"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcb, 0x04, C0|C1, "mem_load_retired.dtlb_miss"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcd, 0x00, C0|C1, "simd_assist"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xce, 0x00, C0|C1, "simd_instr_retired"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xcf, 0x00, C0|C1, "simd_sat_instr_retired"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xe0, 0x01, C0|C1, "br_inst_decoded"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xe4, 0x01, C0|C1, "bogus_br"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xe6, 0x01, C0|C1, "baclears.any"                         , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+/* Intel Core i7 (Nehalem) Processor */
+/*
+ * The Nehalem tables are basically from Bug 16457009
+ *   libcpc counter names should be based on public Intel documentation -- Nehalem
+ * and those tables are basically from the
+ * Intel SDM, January 2013, Section 19.5, Table 19-11.
+ * We omit the Table 19-12 uncore events.
+ *
+ * Note that the table below includes some events from
+ * the Intel SDM that require cmask or attr settings.
+ * These events are not in libcpc, which did not include
+ * events requiring cmask or attr until Sandy Bridge.
+ */
+
+#define EVENTS_FAM6_MOD26                                               \
+{ 0x04, 0x07, C0|C1|C2|C3, "sb_drain.any"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x06, 0x04, C0|C1|C2|C3, "store_blocks.at_ret"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x06, 0x08, C0|C1|C2|C3, "store_blocks.l1d_block"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x01, C0|C1|C2|C3, "partial_address_alias"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x01, C0|C1|C2|C3, "dtlb_load_misses.any"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x02, C0|C1|C2|C3, "dtlb_load_misses.walk_completed"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x10, C0|C1|C2|C3, "dtlb_load_misses.stlb_hit"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x20, C0|C1|C2|C3, "dtlb_load_misses.pde_miss"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x80, C0|C1|C2|C3, "dtlb_load_misses.large_walk_completed", 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0B, 0x01, C0|C1|C2|C3, "mem_inst_retired.loads"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0B, 0x02, C0|C1|C2|C3, "mem_inst_retired.stores"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0B, 0x10, C0|C1|C2|C3, "mem_inst_retired.latency_above_threshold"   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0C, 0x01, C0|C1|C2|C3, "mem_store_retired.dtlb_miss"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x01, C0|C1|C2|C3, "uops_issued.any"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x01, C0|C1|C2|C3, "uops_issued.stalled_cycles"           , 0x1, ATTR_INV , 0x0 }, \
+{ 0x0E, 0x02, C0|C1|C2|C3, "uops_issued.fused"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0F, 0x02, C0|C1|C2|C3, "mem_uncore_retired.other_core_l2_hitm", 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0F, 0x08, C0|C1|C2|C3, "mem_uncore_retired.remote_cache_local_home_hit", 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0F, 0x10, C0|C1|C2|C3, "mem_uncore_retired.remote_dram"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0F, 0x20, C0|C1|C2|C3, "mem_uncore_retired.local_dram"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x01, C0|C1|C2|C3, "fp_comp_ops_exe.x87"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x02, C0|C1|C2|C3, "fp_comp_ops_exe.mmx"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x04, C0|C1|C2|C3, "fp_comp_ops_exe.sse_fp"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x08, C0|C1|C2|C3, "fp_comp_ops_exe.sse2_integer"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x10, C0|C1|C2|C3, "fp_comp_ops_exe.sse_fp_packed"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x20, C0|C1|C2|C3, "fp_comp_ops_exe.sse_fp_scalar"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x40, C0|C1|C2|C3, "fp_comp_ops_exe.sse_single_precision" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x80, C0|C1|C2|C3, "fp_comp_ops_exe.sse_double_precision" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x01, C0|C1|C2|C3, "simd_int_128.packed_mpy"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x02, C0|C1|C2|C3, "simd_int_128.packed_shift"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x04, C0|C1|C2|C3, "simd_int_128.pack"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x08, C0|C1|C2|C3, "simd_int_128.unpack"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x10, C0|C1|C2|C3, "simd_int_128.packed_logical"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x20, C0|C1|C2|C3, "simd_int_128.packed_arith"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x40, C0|C1|C2|C3, "simd_int_128.shuffle_move"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x13, 0x01, C0|C1|C2|C3, "load_dispatch.rs"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x13, 0x02, C0|C1|C2|C3, "load_dispatch.rs_delayed"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x13, 0x04, C0|C1|C2|C3, "load_dispatch.mob"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x13, 0x07, C0|C1|C2|C3, "load_dispatch.any"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x14, 0x01, C0|C1|C2|C3, "arith.cycles_div_busy"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x14, 0x01, C0|C1|C2|C3, "arith.fpu_div"                        , 0x1, ATTR_EDGE | ATTR_INV, 0x0 }, \
+{ 0x14, 0x02, C0|C1|C2|C3, "arith.mul"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x17, 0x01, C0|C1|C2|C3, "inst_queue_writes"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x18, 0x01, C0|C1|C2|C3, "inst_decoded.dec0"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x19, 0x01, C0|C1|C2|C3, "two_uop_insts_decoded"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x1E, 0x01, C0|C1|C2|C3, "inst_queue_write_cycles"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x20, 0x01, C0|C1|C2|C3, "lsd_overflow"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x01, C0|C1|C2|C3, "l2_rqsts.ld_hit"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x02, C0|C1|C2|C3, "l2_rqsts.ld_miss"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x03, C0|C1|C2|C3, "l2_rqsts.loads"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x04, C0|C1|C2|C3, "l2_rqsts.rfo_hit"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x08, C0|C1|C2|C3, "l2_rqsts.rfo_miss"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x0C, C0|C1|C2|C3, "l2_rqsts.rfos"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x10, C0|C1|C2|C3, "l2_rqsts.ifetch_hit"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x20, C0|C1|C2|C3, "l2_rqsts.ifetch_miss"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x30, C0|C1|C2|C3, "l2_rqsts.ifetches"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x40, C0|C1|C2|C3, "l2_rqsts.prefetch_hit"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x80, C0|C1|C2|C3, "l2_rqsts.prefetch_miss"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xAA, C0|C1|C2|C3, "l2_rqsts.miss"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xC0, C0|C1|C2|C3, "l2_rqsts.prefetches"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xFF, C0|C1|C2|C3, "l2_rqsts.references"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x01, C0|C1|C2|C3, "l2_data_rqsts.demand.i_state"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x02, C0|C1|C2|C3, "l2_data_rqsts.demand.s_state"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x04, C0|C1|C2|C3, "l2_data_rqsts.demand.e_state"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x08, C0|C1|C2|C3, "l2_data_rqsts.demand.m_state"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x0F, C0|C1|C2|C3, "l2_data_rqsts.demand.mesi"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x10, C0|C1|C2|C3, "l2_data_rqsts.prefetch.i_state"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x20, C0|C1|C2|C3, "l2_data_rqsts.prefetch.s_state"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x40, C0|C1|C2|C3, "l2_data_rqsts.prefetch.e_state"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x80, C0|C1|C2|C3, "l2_data_rqsts.prefetch.m_state"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0xF0, C0|C1|C2|C3, "l2_data_rqsts.prefetch.mesi"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0xFF, C0|C1|C2|C3, "l2_data_rqsts.any"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x01, C0|C1|C2|C3, "l2_write.rfo.i_state"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x02, C0|C1|C2|C3, "l2_write.rfo.s_state"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x08, C0|C1|C2|C3, "l2_write.rfo.m_state"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x0E, C0|C1|C2|C3, "l2_write.rfo.hit"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x0F, C0|C1|C2|C3, "l2_write.rfo.mesi"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x10, C0|C1|C2|C3, "l2_write.lock.i_state"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x20, C0|C1|C2|C3, "l2_write.lock.s_state"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x40, C0|C1|C2|C3, "l2_write.lock.e_state"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x80, C0|C1|C2|C3, "l2_write.lock.m_state"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0xE0, C0|C1|C2|C3, "l2_write.lock.hit"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0xF0, C0|C1|C2|C3, "l2_write.lock.mesi"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x01, C0|C1|C2|C3, "l1d_wb_l2.i_state"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x02, C0|C1|C2|C3, "l1d_wb_l2.s_state"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x04, C0|C1|C2|C3, "l1d_wb_l2.e_state"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x08, C0|C1|C2|C3, "l1d_wb_l2.m_state"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x0F, C0|C1|C2|C3, "l1d_wb_l2.mesi"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2E, 0x41, C0|C1|C2|C3, "l3_lat_cache.miss"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2E, 0x4F, C0|C1|C2|C3, "l3_lat_cache.reference"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x00, C0|C1|C2|C3, "cpu_clk_unhalted.thread_p"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x01, C0|C1|C2|C3, "cpu_clk_unhalted.ref_p"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x40, 0x01, C0|C1      , "l1d_cache_ld.i_state"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x40, 0x02, C0|C1      , "l1d_cache_ld.s_state"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x40, 0x04, C0|C1      , "l1d_cache_ld.e_state"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x40, 0x08, C0|C1      , "l1d_cache_ld.m_state"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x40, 0x0F, C0|C1      , "l1d_cache_ld.mesi"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x41, 0x02, C0|C1      , "l1d_cache_st.s_state"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x41, 0x04, C0|C1      , "l1d_cache_st.e_state"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x41, 0x08, C0|C1      , "l1d_cache_st.m_state"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x42, 0x01, C0|C1      , "l1d_cache_lock.hit"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x42, 0x02, C0|C1      , "l1d_cache_lock.s_state"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x42, 0x04, C0|C1      , "l1d_cache_lock.e_state"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x42, 0x08, C0|C1      , "l1d_cache_lock.m_state"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x43, 0x01, C0|C1      , "l1d_all_ref.any"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x43, 0x02, C0|C1      , "l1d_all_ref.cacheable"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x01, C0|C1|C2|C3, "dtlb_misses.any"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x02, C0|C1|C2|C3, "dtlb_misses.walk_completed"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x10, C0|C1|C2|C3, "dtlb_misses.stlb_hit"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x20, C0|C1|C2|C3, "dtlb_misses.pde_miss"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x80, C0|C1|C2|C3, "dtlb_misses.large_walk_completed"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4C, 0x01, C0|C1|C2|C3, "load_hit_pre"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4E, 0x01, C0|C1|C2|C3, "l1d_prefetch.requests"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4E, 0x02, C0|C1|C2|C3, "l1d_prefetch.miss"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4E, 0x04, C0|C1|C2|C3, "l1d_prefetch.triggers"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x01, C0|C1      , "l1d.repl"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x02, C0|C1      , "l1d.m_repl"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x04, C0|C1      , "l1d.m_evict"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x08, C0|C1      , "l1d.m_snoop_evict"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x52, 0x01, C0|C1|C2|C3, "l1d_cache_prefetch_lock_fb_hit"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x53, 0x01, C0|C1|C2|C3, "l1d_cache_lock_fb_hit"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x63, 0x01, C0|C1      , "cache_lock_cycles.l1d_l2"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x63, 0x02, C0|C1      , "cache_lock_cycles.l1d"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6C, 0x01, C0|C1|C2|C3, "io_transactions"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x01, C0|C1|C2|C3, "l1i.hits"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x02, C0|C1|C2|C3, "l1i.misses"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x03, C0|C1|C2|C3, "l1i.reads"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x04, C0|C1|C2|C3, "l1i.cycles_stalled"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x82, 0x01, C0|C1|C2|C3, "large_itlb.hit"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x01, C0|C1|C2|C3, "itlb_misses.any"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x02, C0|C1|C2|C3, "itlb_misses.walk_completed"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x01, C0|C1|C2|C3, "ild_stall.lcp"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x02, C0|C1|C2|C3, "ild_stall.mru"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x04, C0|C1|C2|C3, "ild_stall.iq_full"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x08, C0|C1|C2|C3, "ild_stall.regen"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x0F, C0|C1|C2|C3, "ild_stall.any"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x01, C0|C1|C2|C3, "br_inst_exec.cond"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x02, C0|C1|C2|C3, "br_inst_exec.direct"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x04, C0|C1|C2|C3, "br_inst_exec.indirect_non_call"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x07, C0|C1|C2|C3, "br_inst_exec.non_calls"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x08, C0|C1|C2|C3, "br_inst_exec.return_near"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x10, C0|C1|C2|C3, "br_inst_exec.direct_near_call"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x20, C0|C1|C2|C3, "br_inst_exec.indirect_near_call"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x30, C0|C1|C2|C3, "br_inst_exec.near_calls"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x40, C0|C1|C2|C3, "br_inst_exec.taken"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x7F, C0|C1|C2|C3, "br_inst_exec.any"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x01, C0|C1|C2|C3, "br_misp_exec.cond"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x02, C0|C1|C2|C3, "br_misp_exec.direct"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x04, C0|C1|C2|C3, "br_misp_exec.indirect_non_call"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x07, C0|C1|C2|C3, "br_misp_exec.non_calls"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x08, C0|C1|C2|C3, "br_misp_exec.return_near"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x10, C0|C1|C2|C3, "br_misp_exec.direct_near_call"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x20, C0|C1|C2|C3, "br_misp_exec.indirect_near_call"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x30, C0|C1|C2|C3, "br_misp_exec.near_calls"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x40, C0|C1|C2|C3, "br_misp_exec.taken"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x7F, C0|C1|C2|C3, "br_misp_exec.any"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x01, C0|C1|C2|C3, "resource_stalls.any"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x02, C0|C1|C2|C3, "resource_stalls.load"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x04, C0|C1|C2|C3, "resource_stalls.rs_full"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x08, C0|C1|C2|C3, "resource_stalls.store"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x10, C0|C1|C2|C3, "resource_stalls.rob_full"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x20, C0|C1|C2|C3, "resource_stalls.fpcw"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x40, C0|C1|C2|C3, "resource_stalls.mxcsr"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x80, C0|C1|C2|C3, "resource_stalls.other"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA6, 0x01, C0|C1|C2|C3, "macro_insts.fusions_decoded"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA7, 0x01, C0|C1|C2|C3, "baclear_force_iq"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA8, 0x01, C0|C1|C2|C3, "lsd.uops"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA8, 0x01, C0|C1|C2|C3, "lsd.cycles"                           , 0x1, ATTR_INV , 0x0 }, \
+{ 0xAE, 0x01, C0|C1|C2|C3, "itlb_flush"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x40, C0|C1|C2|C3, "offcore_requests.l1d_writeback"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C0|C1|C2|C3, "uops_executed.port0"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x02, C0|C1|C2|C3, "uops_executed.port1"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x04, C0|C1|C2|C3, "uops_executed.port2_core"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x08, C0|C1|C2|C3, "uops_executed.port3_core"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x10, C0|C1|C2|C3, "uops_executed.port4_core"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x1F, C0|C1|C2|C3, "uops_executed.core_active_cycles_no_port5"  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x20, C0|C1|C2|C3, "uops_executed.port5"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x3F, C0|C1|C2|C3, "uops_executed.core_active_cycles"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x40, C0|C1|C2|C3, "uops_executed.port015"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x40, C0|C1|C2|C3, "uops_executed.port015_stall_cycles"   , 0x1, ATTR_INV , 0x0 }, \
+{ 0xB1, 0x80, C0|C1|C2|C3, "uops_executed.port234"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB2, 0x01, C0|C1|C2|C3, "offcore_requests_sq_full"             , 0x0, ATTR_NONE, 0x0 }, \
+/* { 0xB7, 0x01, C0|C1|C2|C3, "off_core_response_0"                  , 0x0, ATTR_NONE, 0x1A6 }, ignore events that require msr_offset */ \
+{ 0xB8, 0x01, C0|C1|C2|C3, "snoop_response.hit"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB8, 0x02, C0|C1|C2|C3, "snoop_response.hite"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB8, 0x04, C0|C1|C2|C3, "snoop_response.hitm"                  , 0x0, ATTR_NONE, 0x0 }, \
+/* { 0xBB, 0x01, C0|C1|C2|C3, "off_core_response_1"                  , 0x0, ATTR_NONE, 0x1A7 }, ignore events that require msr_offset */ \
+{ 0xC0, 0x00, C0|C1|C2|C3, "inst_retired.any_p"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC0, 0x02, C0|C1|C2|C3, "inst_retired.x87"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC0, 0x04, C0|C1|C2|C3, "inst_retired.mmx"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x01, C0|C1|C2|C3, "uops_retired.any"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x01, C0|C1|C2|C3, "uops_retired.active_cycles"           , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x01, C0|C1|C2|C3, "uops_retired.stall_cycles"            , 0x1, ATTR_INV , 0x0 }, \
+{ 0xC2, 0x02, C0|C1|C2|C3, "uops_retired.retire_slots"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x04, C0|C1|C2|C3, "uops_retired.macro_fused"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x01, C0|C1|C2|C3, "machine_clears.cycles"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x02, C0|C1|C2|C3, "machine_clears.mem_order"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x04, C0|C1|C2|C3, "machine_clears.smc"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x00, C0|C1|C2|C3, "br_inst_retired.all_branches"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x01, C0|C1|C2|C3, "br_inst_retired.conditional"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x02, C0|C1|C2|C3, "br_inst_retired.near_call"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x00, C0|C1|C2|C3, "br_misp_retired.all_branches"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x02, C0|C1|C2|C3, "br_misp_retired.near_call"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x01, C0|C1|C2|C3, "ssex_uops_retired.packed_single"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x02, C0|C1|C2|C3, "ssex_uops_retired.scalar_single"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x04, C0|C1|C2|C3, "ssex_uops_retired.packed_double"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x08, C0|C1|C2|C3, "ssex_uops_retired.scalar_double"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x10, C0|C1|C2|C3, "ssex_uops_retired.vector_integer"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC8, 0x20, C0|C1|C2|C3, "itlb_miss_retired"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x01, C0|C1|C2|C3, "mem_load_retired.l1d_hit"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x02, C0|C1|C2|C3, "mem_load_retired.l2_hit"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x04, C0|C1|C2|C3, "mem_load_retired.llc_unshared_hit"    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x08, C0|C1|C2|C3, "mem_load_retired.other_core_l2_hit_hitm"    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x10, C0|C1|C2|C3, "mem_load_retired.llc_miss"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x40, C0|C1|C2|C3, "mem_load_retired.hit_lfb"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x80, C0|C1|C2|C3, "mem_load_retired.dtlb_miss"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCC, 0x01, C0|C1|C2|C3, "fp_mmx_trans.to_fp"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCC, 0x02, C0|C1|C2|C3, "fp_mmx_trans.to_mmx"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCC, 0x03, C0|C1|C2|C3, "fp_mmx_trans.any"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x01, C0|C1|C2|C3, "macro_insts.decoded"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x02, C0|C1|C2|C3, "uops_decoded.ms"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x04, C0|C1|C2|C3, "uops_decoded.esp_folding"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x08, C0|C1|C2|C3, "uops_decoded.esp_sync"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x01, C0|C1|C2|C3, "rat_stalls.flags"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x02, C0|C1|C2|C3, "rat_stalls.registers"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x04, C0|C1|C2|C3, "rat_stalls.rob_read_port"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x08, C0|C1|C2|C3, "rat_stalls.scoreboard"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x0F, C0|C1|C2|C3, "rat_stalls.any"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD4, 0x01, C0|C1|C2|C3, "seg_rename_stalls"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD5, 0x01, C0|C1|C2|C3, "es_reg_renames"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xDB, 0x01, C0|C1|C2|C3, "uop_unfusion"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xE0, 0x01, C0|C1|C2|C3, "br_inst_decoded"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xE5, 0x01, C0|C1|C2|C3, "bpu_missed_call_ret"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xE6, 0x01, C0|C1|C2|C3, "baclear.clear"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xE6, 0x02, C0|C1|C2|C3, "baclear.bad_target"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xE8, 0x01, C0|C1|C2|C3, "bpu_clears.early"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xE8, 0x02, C0|C1|C2|C3, "bpu_clears.late"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x01, C0|C1|C2|C3, "l2_transactions.load"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x02, C0|C1|C2|C3, "l2_transactions.rfo"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x04, C0|C1|C2|C3, "l2_transactions.ifetch"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x08, C0|C1|C2|C3, "l2_transactions.prefetch"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x10, C0|C1|C2|C3, "l2_transactions.l1d_wb"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x20, C0|C1|C2|C3, "l2_transactions.fill"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x40, C0|C1|C2|C3, "l2_transactions.wb"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x80, C0|C1|C2|C3, "l2_transactions.any"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x02, C0|C1|C2|C3, "l2_lines_in.s_state"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x04, C0|C1|C2|C3, "l2_lines_in.e_state"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x07, C0|C1|C2|C3, "l2_lines_in.any"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x01, C0|C1|C2|C3, "l2_lines_out.demand_clean"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x02, C0|C1|C2|C3, "l2_lines_out.demand_dirty"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x04, C0|C1|C2|C3, "l2_lines_out.prefetch_clean"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x08, C0|C1|C2|C3, "l2_lines_out.prefetch_dirty"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x0F, C0|C1|C2|C3, "l2_lines_out.any"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF4, 0x10, C0|C1|C2|C3, "sq_misc.split_lock"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF6, 0x01, C0|C1|C2|C3, "sq_full_stall_cycles"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF7, 0x01, C0|C1|C2|C3, "fp_assist.all"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF7, 0x02, C0|C1|C2|C3, "fp_assist.output"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF7, 0x04, C0|C1|C2|C3, "fp_assist.input"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x01, C0|C1|C2|C3, "simd_int_64.packed_mpy"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x02, C0|C1|C2|C3, "simd_int_64.packed_shift"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x04, C0|C1|C2|C3, "simd_int_64.pack"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x08, C0|C1|C2|C3, "simd_int_64.unpack"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x10, C0|C1|C2|C3, "simd_int_64.packed_logical"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x20, C0|C1|C2|C3, "simd_int_64.packed_arith"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x40, C0|C1|C2|C3, "simd_int_64.shuffle_move"             , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+#define   EVENTS_FAM6_MOD46_ONLY                  \
+{ 0x0F, 0x01, C0|C1|C2|C3, "mem_uncore_retired.l3_data_miss_unknown"    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0F, 0x80, C0|C1|C2|C3, "mem_uncore_retired.uncacheable"       , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+/* Intel Westmere Processor */
+/*
+ * The Westmere tables are basically from Bug 16173963
+ *   libcpc counter names should be based on public Intel documentation -- Westmere
+ * and those tables are basically from the
+ * Intel SDM, January 2013, Section 19.6, Table 19-13.
+ * We omit the Table 19-14 uncore events.
+ *
+ * Note that the table below includes some events from
+ * the Intel SDM that require cmask or attr settings.
+ * These events are not in libcpc, which did not include
+ * events requiring cmask or attr until Sandy Bridge.
+ */
+
+#define EVENTS_FAM6_MOD37                                               \
+{ 0x03, 0x02, C0|C1|C2|C3, "load_block.overlap_store"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x04, 0x07, C0|C1|C2|C3, "sb_drain.any"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x05, 0x02, C0|C1|C2|C3, "misalign_mem_ref.store"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x06, 0x04, C0|C1|C2|C3, "store_blocks.at_ret"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x06, 0x08, C0|C1|C2|C3, "store_blocks.l1d_block"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x01, C0|C1|C2|C3, "partial_address_alias"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x01, C0|C1|C2|C3, "dtlb_load_misses.any"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x02, C0|C1|C2|C3, "dtlb_load_misses.walk_completed"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x04, C0|C1|C2|C3, "dtlb_load_misses.walk_cycles"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x10, C0|C1|C2|C3, "dtlb_load_misses.stlb_hit"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x20, C0|C1|C2|C3, "dtlb_load_misses.pde_miss"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0B, 0x01, C0|C1|C2|C3, "mem_inst_retired.loads"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0B, 0x02, C0|C1|C2|C3, "mem_inst_retired.stores"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0B, 0x10, C0|C1|C2|C3, "mem_inst_retired.latency_above_threshold"   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0C, 0x01, C0|C1|C2|C3, "mem_store_retired.dtlb_miss"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x01, C0|C1|C2|C3, "uops_issued.any"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x02, C0|C1|C2|C3, "uops_issued.fused"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0F, 0x01, C0|C1|C2|C3, "mem_uncore_retired.unknown_source"    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0F, 0x80, C0|C1|C2|C3, "mem_uncore_retired.uncacheable"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x01, C0|C1|C2|C3, "fp_comp_ops_exe.x87"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x02, C0|C1|C2|C3, "fp_comp_ops_exe.mmx"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x04, C0|C1|C2|C3, "fp_comp_ops_exe.sse_fp"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x08, C0|C1|C2|C3, "fp_comp_ops_exe.sse2_integer"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x10, C0|C1|C2|C3, "fp_comp_ops_exe.sse_fp_packed"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x20, C0|C1|C2|C3, "fp_comp_ops_exe.sse_fp_scalar"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x40, C0|C1|C2|C3, "fp_comp_ops_exe.sse_single_precision" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x80, C0|C1|C2|C3, "fp_comp_ops_exe.sse_double_precision" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x01, C0|C1|C2|C3, "simd_int_128.packed_mpy"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x02, C0|C1|C2|C3, "simd_int_128.packed_shift"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x04, C0|C1|C2|C3, "simd_int_128.pack"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x08, C0|C1|C2|C3, "simd_int_128.unpack"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x10, C0|C1|C2|C3, "simd_int_128.packed_logical"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x20, C0|C1|C2|C3, "simd_int_128.packed_arith"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x12, 0x40, C0|C1|C2|C3, "simd_int_128.shuffle_move"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x13, 0x01, C0|C1|C2|C3, "load_dispatch.rs"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x13, 0x02, C0|C1|C2|C3, "load_dispatch.rs_delayed"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x13, 0x04, C0|C1|C2|C3, "load_dispatch.mob"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x13, 0x07, C0|C1|C2|C3, "load_dispatch.any"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x14, 0x01, C0|C1|C2|C3, "arith.cycles_div_busy"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x14, 0x02, C0|C1|C2|C3, "arith.mul"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x17, 0x01, C0|C1|C2|C3, "inst_queue_writes"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x18, 0x01, C0|C1|C2|C3, "inst_decoded.dec0"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x19, 0x01, C0|C1|C2|C3, "two_uop_insts_decoded"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x1E, 0x01, C0|C1|C2|C3, "inst_queue_write_cycles"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x20, 0x01, C0|C1|C2|C3, "lsd_overflow"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x01, C0|C1|C2|C3, "l2_rqsts.ld_hit"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x02, C0|C1|C2|C3, "l2_rqsts.ld_miss"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x03, C0|C1|C2|C3, "l2_rqsts.loads"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x04, C0|C1|C2|C3, "l2_rqsts.rfo_hit"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x08, C0|C1|C2|C3, "l2_rqsts.rfo_miss"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x0C, C0|C1|C2|C3, "l2_rqsts.rfos"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x10, C0|C1|C2|C3, "l2_rqsts.ifetch_hit"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x20, C0|C1|C2|C3, "l2_rqsts.ifetch_miss"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x30, C0|C1|C2|C3, "l2_rqsts.ifetches"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x40, C0|C1|C2|C3, "l2_rqsts.prefetch_hit"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x80, C0|C1|C2|C3, "l2_rqsts.prefetch_miss"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xAA, C0|C1|C2|C3, "l2_rqsts.miss"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xC0, C0|C1|C2|C3, "l2_rqsts.prefetches"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xFF, C0|C1|C2|C3, "l2_rqsts.references"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x01, C0|C1|C2|C3, "l2_data_rqsts.demand.i_state"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x02, C0|C1|C2|C3, "l2_data_rqsts.demand.s_state"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x04, C0|C1|C2|C3, "l2_data_rqsts.demand.e_state"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x08, C0|C1|C2|C3, "l2_data_rqsts.demand.m_state"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x0F, C0|C1|C2|C3, "l2_data_rqsts.demand.mesi"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x10, C0|C1|C2|C3, "l2_data_rqsts.prefetch.i_state"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x20, C0|C1|C2|C3, "l2_data_rqsts.prefetch.s_state"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x40, C0|C1|C2|C3, "l2_data_rqsts.prefetch.e_state"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0x80, C0|C1|C2|C3, "l2_data_rqsts.prefetch.m_state"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0xF0, C0|C1|C2|C3, "l2_data_rqsts.prefetch.mesi"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x26, 0xFF, C0|C1|C2|C3, "l2_data_rqsts.any"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x01, C0|C1|C2|C3, "l2_write.rfo.i_state"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x02, C0|C1|C2|C3, "l2_write.rfo.s_state"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x08, C0|C1|C2|C3, "l2_write.rfo.m_state"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x0E, C0|C1|C2|C3, "l2_write.rfo.hit"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x0F, C0|C1|C2|C3, "l2_write.rfo.mesi"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x10, C0|C1|C2|C3, "l2_write.lock.i_state"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x20, C0|C1|C2|C3, "l2_write.lock.s_state"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x40, C0|C1|C2|C3, "l2_write.lock.e_state"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x80, C0|C1|C2|C3, "l2_write.lock.m_state"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0xE0, C0|C1|C2|C3, "l2_write.lock.hit"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0xF0, C0|C1|C2|C3, "l2_write.lock.mesi"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x01, C0|C1|C2|C3, "l1d_wb_l2.i_state"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x02, C0|C1|C2|C3, "l1d_wb_l2.s_state"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x04, C0|C1|C2|C3, "l1d_wb_l2.e_state"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x08, C0|C1|C2|C3, "l1d_wb_l2.m_state"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x0F, C0|C1|C2|C3, "l1d_wb_l2.mesi"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2E, 0x41, C0|C1|C2|C3, "l3_lat_cache.miss"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2E, 0x4F, C0|C1|C2|C3, "l3_lat_cache.reference"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x00, C0|C1|C2|C3, "cpu_clk_unhalted.thread_p"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x01, C0|C1|C2|C3, "cpu_clk_unhalted.ref_p"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x01, C0|C1|C2|C3, "dtlb_misses.any"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x02, C0|C1|C2|C3, "dtlb_misses.walk_completed"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x04, C0|C1|C2|C3, "dtlb_misses.walk_cycles"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x10, C0|C1|C2|C3, "dtlb_misses.stlb_hit"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x20, C0|C1|C2|C3, "dtlb_misses.pde_miss"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x80, C0|C1|C2|C3, "dtlb_misses.large_walk_completed"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4C, 0x01, C0|C1      , "load_hit_pre"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4E, 0x01, C0|C1      , "l1d_prefetch.requests"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4E, 0x02, C0|C1      , "l1d_prefetch.miss"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4E, 0x04, C0|C1      , "l1d_prefetch.triggers"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4F, 0x10, C0|C1|C2|C3, "ept.walk_cycles"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x01, C0|C1      , "l1d.repl"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x02, C0|C1      , "l1d.m_repl"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x04, C0|C1      , "l1d.m_evict"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x08, C0|C1      , "l1d.m_snoop_evict"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x52, 0x01, C0|C1|C2|C3, "l1d_cache_prefetch_lock_fb_hit"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x01, C0         , "offcore_requests_outstanding.demand.read_data", 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x02, C0         , "offcore_requests_outstanding.demand.read_code", 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x04, C0         , "offcore_requests_outstanding.demand.rfo"    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x08, C0         , "offcore_requests_outstanding.any_read", 0x0, ATTR_NONE, 0x0 }, \
+{ 0x63, 0x01, C0|C1      , "cache_lock_cycles.l1d_l2"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x63, 0x02, C0|C1      , "cache_lock_cycles.l1d"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x6C, 0x01, C0|C1|C2|C3, "io_transactions"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x01, C0|C1|C2|C3, "l1i.hits"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x02, C0|C1|C2|C3, "l1i.misses"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x03, C0|C1|C2|C3, "l1i.reads"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x04, C0|C1|C2|C3, "l1i.cycles_stalled"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x82, 0x01, C0|C1|C2|C3, "large_itlb.hit"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x01, C0|C1|C2|C3, "itlb_misses.any"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x02, C0|C1|C2|C3, "itlb_misses.walk_completed"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x04, C0|C1|C2|C3, "itlb_misses.walk_cycles"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x10, C0|C1|C2|C3, "itlb_misses.stlb_hit"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x80, C0|C1|C2|C3, "itlb_misses.large_walk_completed"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x01, C0|C1|C2|C3, "ild_stall.lcp"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x02, C0|C1|C2|C3, "ild_stall.mru"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x04, C0|C1|C2|C3, "ild_stall.iq_full"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x08, C0|C1|C2|C3, "ild_stall.regen"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x0F, C0|C1|C2|C3, "ild_stall.any"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x01, C0|C1|C2|C3, "br_inst_exec.cond"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x02, C0|C1|C2|C3, "br_inst_exec.direct"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x04, C0|C1|C2|C3, "br_inst_exec.indirect_non_call"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x07, C0|C1|C2|C3, "br_inst_exec.non_calls"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x08, C0|C1|C2|C3, "br_inst_exec.return_near"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x10, C0|C1|C2|C3, "br_inst_exec.direct_near_call"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x20, C0|C1|C2|C3, "br_inst_exec.indirect_near_call"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x30, C0|C1|C2|C3, "br_inst_exec.near_calls"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x40, C0|C1|C2|C3, "br_inst_exec.taken"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x7F, C0|C1|C2|C3, "br_inst_exec.any"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x01, C0|C1|C2|C3, "br_misp_exec.cond"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x02, C0|C1|C2|C3, "br_misp_exec.direct"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x04, C0|C1|C2|C3, "br_misp_exec.indirect_non_call"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x07, C0|C1|C2|C3, "br_misp_exec.non_calls"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x08, C0|C1|C2|C3, "br_misp_exec.return_near"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x10, C0|C1|C2|C3, "br_misp_exec.direct_near_call"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x20, C0|C1|C2|C3, "br_misp_exec.indirect_near_call"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x30, C0|C1|C2|C3, "br_misp_exec.near_calls"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x40, C0|C1|C2|C3, "br_misp_exec.taken"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x7F, C0|C1|C2|C3, "br_misp_exec.any"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x01, C0|C1|C2|C3, "resource_stalls.any"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x02, C0|C1|C2|C3, "resource_stalls.load"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x04, C0|C1|C2|C3, "resource_stalls.rs_full"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x08, C0|C1|C2|C3, "resource_stalls.store"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x10, C0|C1|C2|C3, "resource_stalls.rob_full"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x20, C0|C1|C2|C3, "resource_stalls.fpcw"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x40, C0|C1|C2|C3, "resource_stalls.mxcsr"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x80, C0|C1|C2|C3, "resource_stalls.other"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA6, 0x01, C0|C1|C2|C3, "macro_insts.fusions_decoded"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA7, 0x01, C0|C1|C2|C3, "baclear_force_iq"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA8, 0x01, C0|C1|C2|C3, "lsd.uops"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xAE, 0x01, C0|C1|C2|C3, "itlb_flush"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x01, C0|C1|C2|C3, "offcore_requests.demand.read_data"    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x02, C0|C1|C2|C3, "offcore_requests.demand.read_code"    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x04, C0|C1|C2|C3, "offcore_requests.demand.rfo"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x08, C0|C1|C2|C3, "offcore_requests.any.read"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x10, C0|C1|C2|C3, "offcore_requests.any.rfo"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x40, C0|C1|C2|C3, "offcore_requests.l1d_writeback"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x80, C0|C1|C2|C3, "offcore_requests.any"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C0|C1|C2|C3, "uops_executed.port0"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x02, C0|C1|C2|C3, "uops_executed.port1"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x04, C0|C1|C2|C3, "uops_executed.port2_core"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x08, C0|C1|C2|C3, "uops_executed.port3_core"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x10, C0|C1|C2|C3, "uops_executed.port4_core"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x1F, C0|C1|C2|C3, "uops_executed.core_active_cycles_no_port5"  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x20, C0|C1|C2|C3, "uops_executed.port5"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x3F, C0|C1|C2|C3, "uops_executed.core_active_cycles"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x40, C0|C1|C2|C3, "uops_executed.port015"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x80, C0|C1|C2|C3, "uops_executed.port234"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB2, 0x01, C0|C1|C2|C3, "offcore_requests_sq_full"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB3, 0x01, C0,          "snoopq_requests_outstanding.data"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB3, 0x02, C0,          "snoopq_requests_outstanding.invalidate"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB3, 0x04, C0,          "snoopq_requests_outstanding.code"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB4, 0x01, C0|C1|C2|C3, "snoopq_requests.code"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB4, 0x02, C0|C1|C2|C3, "snoopq_requests.data"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB4, 0x04, C0|C1|C2|C3, "snoopq_requests.invalidate"           , 0x0, ATTR_NONE, 0x0 }, \
+/* { 0xB7, 0x01, C0|C1|C2|C3, "off_core_response_0"                  , 0x0, ATTR_NONE, 0x1A6 }, ignore events that require msr_offset */ \
+{ 0xB8, 0x01, C0|C1|C2|C3, "snoop_response.hit"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB8, 0x02, C0|C1|C2|C3, "snoop_response.hite"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB8, 0x04, C0|C1|C2|C3, "snoop_response.hitm"                  , 0x0, ATTR_NONE, 0x0 }, \
+/* { 0xBB, 0x01, C0|C1|C2|C3, "off_core_response_1"                  , 0x0, ATTR_NONE, 0x1A7 }, ignore events that require msr_offset */ \
+{ 0xC0, 0x00, C0|C1|C2|C3, "inst_retired.any_p"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC0, 0x02, C0|C1|C2|C3, "inst_retired.x87"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC0, 0x04, C0|C1|C2|C3, "inst_retired.mmx"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x01, C0|C1|C2|C3, "uops_retired.any"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x02, C0|C1|C2|C3, "uops_retired.retire_slots"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x04, C0|C1|C2|C3, "uops_retired.macro_fused"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x01, C0|C1|C2|C3, "machine_clears.cycles"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x02, C0|C1|C2|C3, "machine_clears.mem_order"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x04, C0|C1|C2|C3, "machine_clears.smc"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x00, C0|C1|C2|C3, "br_inst_retired.all_branches"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x01, C0|C1|C2|C3, "br_inst_retired.conditional"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x02, C0|C1|C2|C3, "br_inst_retired.near_call"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x00, C0|C1|C2|C3, "br_misp_retired.all_branches"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x01, C0|C1|C2|C3, "br_misp_retired.conditional"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x02, C0|C1|C2|C3, "br_misp_retired.near_call"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x04, C0|C1|C2|C3, "br_misp_retired.all_branches"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x01, C0|C1|C2|C3, "ssex_uops_retired.packed_single"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x02, C0|C1|C2|C3, "ssex_uops_retired.scalar_single"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x04, C0|C1|C2|C3, "ssex_uops_retired.packed_double"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x08, C0|C1|C2|C3, "ssex_uops_retired.scalar_double"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x10, C0|C1|C2|C3, "ssex_uops_retired.vector_integer"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC8, 0x20, C0|C1|C2|C3, "itlb_miss_retired"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x01, C0|C1|C2|C3, "mem_load_retired.l1d_hit"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x02, C0|C1|C2|C3, "mem_load_retired.l2_hit"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x04, C0|C1|C2|C3, "mem_load_retired.llc_unshared_hit"    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x08, C0|C1|C2|C3, "mem_load_retired.other_core_l2_hit_hitm"    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x10, C0|C1|C2|C3, "mem_load_retired.llc_miss"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x40, C0|C1|C2|C3, "mem_load_retired.hit_lfb"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x80, C0|C1|C2|C3, "mem_load_retired.dtlb_miss"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCC, 0x01, C0|C1|C2|C3, "fp_mmx_trans.to_fp"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCC, 0x02, C0|C1|C2|C3, "fp_mmx_trans.to_mmx"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCC, 0x03, C0|C1|C2|C3, "fp_mmx_trans.any"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x01, C0|C1|C2|C3, "macro_insts.decoded"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x01, C0|C1|C2|C3, "uops_decoded.stall_cycles"            , 0x1, ATTR_INV , 0x0 }, \
+{ 0xD1, 0x02, C0|C1|C2|C3, "uops_decoded.ms"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x04, C0|C1|C2|C3, "uops_decoded.esp_folding"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x08, C0|C1|C2|C3, "uops_decoded.esp_sync"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x01, C0|C1|C2|C3, "rat_stalls.flags"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x02, C0|C1|C2|C3, "rat_stalls.registers"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x04, C0|C1|C2|C3, "rat_stalls.rob_read_port"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x08, C0|C1|C2|C3, "rat_stalls.scoreboard"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x0F, C0|C1|C2|C3, "rat_stalls.any"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD4, 0x01, C0|C1|C2|C3, "seg_rename_stalls"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD5, 0x01, C0|C1|C2|C3, "es_reg_renames"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xDB, 0x01, C0|C1|C2|C3, "uop_unfusion"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xE0, 0x01, C0|C1|C2|C3, "br_inst_decoded"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xE5, 0x01, C0|C1|C2|C3, "bpu_missed_call_ret"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xE6, 0x01, C0|C1|C2|C3, "baclear.clear"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xE6, 0x02, C0|C1|C2|C3, "baclear.bad_target"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xE8, 0x02, C0|C1|C2|C3, "bpu_clears.late"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xEC, 0x01, C0|C1|C2|C3, "thread_active"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x01, C0|C1|C2|C3, "l2_transactions.load"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x02, C0|C1|C2|C3, "l2_transactions.rfo"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x04, C0|C1|C2|C3, "l2_transactions.ifetch"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x08, C0|C1|C2|C3, "l2_transactions.prefetch"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x10, C0|C1|C2|C3, "l2_transactions.l1d_wb"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x20, C0|C1|C2|C3, "l2_transactions.fill"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x40, C0|C1|C2|C3, "l2_transactions.wb"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x80, C0|C1|C2|C3, "l2_transactions.any"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x02, C0|C1|C2|C3, "l2_lines_in.s_state"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x04, C0|C1|C2|C3, "l2_lines_in.e_state"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x07, C0|C1|C2|C3, "l2_lines_in.any"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x01, C0|C1|C2|C3, "l2_lines_out.demand_clean"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x02, C0|C1|C2|C3, "l2_lines_out.demand_dirty"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x04, C0|C1|C2|C3, "l2_lines_out.prefetch_clean"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x08, C0|C1|C2|C3, "l2_lines_out.prefetch_dirty"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x0F, C0|C1|C2|C3, "l2_lines_out.any"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF4, 0x04, C0|C1|C2|C3, "sq_misc.lru_hints"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF4, 0x10, C0|C1|C2|C3, "sq_misc.split_lock"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF6, 0x01, C0|C1|C2|C3, "sq_full_stall_cycles"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF7, 0x01, C0|C1|C2|C3, "fp_assist.all"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF7, 0x02, C0|C1|C2|C3, "fp_assist.output"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF7, 0x04, C0|C1|C2|C3, "fp_assist.input"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x01, C0|C1|C2|C3, "simd_int_64.packed_mpy"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x02, C0|C1|C2|C3, "simd_int_64.packed_shift"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x04, C0|C1|C2|C3, "simd_int_64.pack"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x08, C0|C1|C2|C3, "simd_int_64.unpack"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x10, C0|C1|C2|C3, "simd_int_64.packed_logical"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x20, C0|C1|C2|C3, "simd_int_64.packed_arith"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xFD, 0x40, C0|C1|C2|C3, "simd_int_64.shuffle_move"             , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+/*
+ * This special omission of the following events from Model 47
+ * is due to usr/src/uts/intel/pcbe/wm_pcbe.h .  There seems
+ * to be no substantiation for this treatment in the Intel SDM.
+ */
+#define       EVENTS_FAM6_MOD37_ALSO                                    \
+{ 0x0F, 0x02, C0|C1|C2|C3, "mem_uncore_retired.other_core_l2_hit" , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0F, 0x04, C0|C1|C2|C3, "mem_uncore_retired.remote_hitm"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0F, 0x08, C0|C1|C2|C3, "mem_uncore_retired.local_dram_remote_cache_hit", 0x0, ATTR_NONE, 0x0 },\
+{ 0x0F, 0x10, C0|C1|C2|C3, "mem_uncore_retired.remote_dram"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0F, 0x20, C0|C1|C2|C3, "mem_uncore_retired.other_llc_miss"    , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+/* Intel Sandy Bridge Processor */
+/*
+ * The Sandy Bridge tables are basically from Bug 16457080
+ *   libcpc counter names should be based on public Intel documentation -- Sandy Bridge
+ * and those tables are basically from the
+ * Intel SDM, January 2013, Section 19.4, Table 19-7.
+ * Additionally, there are
+ *   Table 19-8.  Model 42 only.
+ *   Table 19-9.  Model 45 only.
+ * We omit the Table 19-10 uncore events.
+ */
+
+#define EVENTS_FAM6_MOD42                                               \
+{ 0x03, 0x01, C_ALL, "ld_blocks.data_unknown"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x03, 0x02, C_ALL, "ld_blocks.store_forward"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x03, 0x08, C_ALL, "ld_blocks.no_sr"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x03, 0x10, C_ALL, "ld_blocks.all_block"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x05, 0x01, C_ALL, "misalign_mem_ref.loads"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x05, 0x02, C_ALL, "misalign_mem_ref.stores"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x01, C_ALL, "ld_blocks_partial.address_alias"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x08, C_ALL, "ld_blocks_partial.all_sta_block"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x01, C_ALL, "dtlb_load_misses.miss_causes_a_walk"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x02, C_ALL, "dtlb_load_misses.walk_completed"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x04, C_ALL, "dtlb_load_misses.walk_duration"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x10, C_ALL, "dtlb_load_misses.stlb_hit"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0D, 0x03, C_ALL, "int_misc.recovery_cycles"                          , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x0D, 0x03, C_ALL, "int_misc.recovery_stalls_count"                    , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x0D, 0x40, C_ALL, "int_misc.rat_stall_cycles"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x01, C_ALL, "uops_issued.any"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x01, C_ALL, "uops_issued.stall_cycles"                          , 0x1, ATTR_INV , 0x0 }, \
+{ 0x0E, 0x01, C_ALL, "uops_issued.core_stall_cycles"                     , 0x1, ATTR_INV | ATTR_ANY, 0x0 }, \
+{ 0x10, 0x01, C_ALL, "fp_comp_ops_exe.x87"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x10, C_ALL, "fp_comp_ops_exe.sse_fp_packed_double"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x20, C_ALL, "fp_comp_ops_exe.sse_fp_scalar_single"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x40, C_ALL, "fp_comp_ops_exe.sse_packed_single"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x80, C_ALL, "fp_comp_ops_exe.sse_scalar_double"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x11, 0x01, C_ALL, "simd_fp_256.packed_single"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x11, 0x02, C_ALL, "simd_fp_256.packed_double"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x14, 0x01, C_ALL, "arith.fpu_div_active"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x14, 0x01, C_ALL, "arith.fpu_div"                                     , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x17, 0x01, C_ALL, "insts_written_to_iq.insts"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x01, C_ALL, "l2_rqsts.demand_data_rd_hit"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x03, C_ALL, "l2_rqsts.all_demand_data_rd"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x04, C_ALL, "l2_rqsts.rfo_hits"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x08, C_ALL, "l2_rqsts.rfo_miss"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x0C, C_ALL, "l2_rqsts.all_rfo"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x10, C_ALL, "l2_rqsts.code_rd_hit"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x20, C_ALL, "l2_rqsts.code_rd_miss"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x30, C_ALL, "l2_rqsts.all_code_rd"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x40, C_ALL, "l2_rqsts.pf_hit"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x80, C_ALL, "l2_rqsts.pf_miss"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xC0, C_ALL, "l2_rqsts.all_pf"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x01, C_ALL, "l2_store_lock_rqsts.miss"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x04, C_ALL, "l2_store_lock_rqsts.hit_e"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x08, C_ALL, "l2_store_lock_rqsts.hit_m"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x0F, C_ALL, "l2_store_lock_rqsts.all"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x01, C_ALL, "l2_l1d_wb_rqsts.miss"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x02, C_ALL, "l2_l1d_wb_rqsts.hit_s"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x04, C_ALL, "l2_l1d_wb_rqsts.hit_e"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x08, C_ALL, "l2_l1d_wb_rqsts.hit_m"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x0F, C_ALL, "l2_l1d_wb_rqsts.all"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2E, 0x41, C_ALL, "longest_lat_cache.miss"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2E, 0x4F, C_ALL, "longest_lat_cache.reference"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x00, C_ALL, "cpu_clk_unhalted.thread_p"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x01, C_ALL, "cpu_clk_thread_unhalted.ref_xclk"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C2   , "l1d_pend_miss.pending"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C2   , "l1d_pend_miss.pending_cycles"                      , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C2   , "l1d_pend_miss.occurrences"                         , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x49, 0x01, C_ALL, "dtlb_store_misses.miss_causes_a_walk"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x02, C_ALL, "dtlb_store_misses.walk_completed"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x04, C_ALL, "dtlb_store_misses.walk_duration"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x10, C_ALL, "dtlb_store_misses.stlb_hit"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4C, 0x01, C_ALL, "load_hit_pre.sw_pf"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4C, 0x02, C_ALL, "load_hit_pre.hw_pf"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4E, 0x02, C_ALL, "hw_pre_req.dl1_miss"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x01, C_ALL, "l1d.replacement"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x02, C_ALL, "l1d.allocated_in_m"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x04, C_ALL, "l1d.eviction"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x08, C_ALL, "l1d.all_m_replacement"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x59, 0x20, C_ALL, "partial_rat_stalls.flags_merge_uop"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x59, 0x20, C_ALL, "partial_rat_stalls.flags_merge_uop_cycles"         , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x59, 0x40, C_ALL, "partial_rat_stalls.slow_lea_window"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x59, 0x80, C_ALL, "partial_rat_stalls.mul_single_uop"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5B, 0x0C, C0|C1|C2|C3, "resource_stalls2.all_fl_empty"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5B, 0x0F, C_ALL, "resource_stalls2.all_prf_control"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5B, 0x40, C_ALL, "resource_stalls2.bob_full"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5B, 0x4F, C_ALL, "resource_stalls2.ooo_rsrc"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5C, 0x01, C_ALL, "cpl_cycles.ring0"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5C, 0x01, C_ALL, "cpl_cycles.ring0_transition"                       , 0x0, ATTR_EDGE, 0x0 }, \
+{ 0x5C, 0x02, C_ALL, "cpl_cycles.ring123"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5E, 0x01, C_ALL, "rs_events.empty_cycles"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x01, C_ALL, "offcore_requests_outstanding.demand_data_rd"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x01, C_ALL, "offcore_requests_outstanding.demand_data_rd_cycles", 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x04, C_ALL, "offcore_requests_outstanding.demand_rfo"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x04, C_ALL, "offcore_requests_outstanding.demand_rfo_cycles"    , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x08, C_ALL, "offcore_requests_outstanding.all_data_rd"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x08, C_ALL, "offcore_requests_outstanding.all_data_rd_cycles"   , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x63, 0x01, C_ALL, "lock_cycles.split_lock_uc_lock_duration"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x63, 0x02, C_ALL, "lock_cycles.cache_lock_duration"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x02, C_ALL, "idq.empty"                                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x04, C_ALL, "idq.mite_uops"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x04, C_ALL, "idq.mite_cycles"                                   , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x08, C_ALL, "idq.dsb_uops"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x08, C_ALL, "idq.dsb_cycles"                                    , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x10, C_ALL, "idq.ms_dsb_uops"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x10, C_ALL, "idq.ms_dsb_cycles"                                 , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x10, C_ALL, "idq.ms_dsb_activations"                            , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x79, 0x20, C_ALL, "idq.ms_mite_uops"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x20, C_ALL, "idq.ms_mite_cycles"                                , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x30, C_ALL, "idq.ms_uops"                                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x30, C_ALL, "idq.ms_cycles"                                     , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x18, C_ALL, "idq.all_dsb_uops"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x18, C_ALL, "idq.all_dsb_cycles"                                , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x24, C_ALL, "idq.all_mite_uops"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x24, C_ALL, "idq.all_mite_cycles"                               , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x3C, C_ALL, "idq.mite_all_uops"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x3C, C_ALL, "idq.mite_all_cycles"                               , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x02, C_ALL, "icache.misses"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x01, C_ALL, "itlb_misses.miss_causes_a_walk"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x02, C_ALL, "itlb_misses.walk_completed"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x04, C_ALL, "itlb_misses.walk_duration"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x10, C_ALL, "itlb_misses.stlb_hit"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x01, C_ALL, "ild_stall.lcp"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x04, C_ALL, "ild_stall.iq_full"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x41, C_ALL, "br_inst_exec.nontaken_cond"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x81, C_ALL, "br_inst_exec.taken_cond"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x82, C_ALL, "br_inst_exec.taken_direct_jmp"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x84, C_ALL, "br_inst_exec.taken_indirect_jmp_non_call_ret"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x88, C_ALL, "br_inst_exec.taken_return_near"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x90, C_ALL, "br_inst_exec.taken_direct_near_call"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xA0, C_ALL, "br_inst_exec.taken_indirect_near_call"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xC1, C_ALL, "br_inst_exec.all_cond"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xFF, C_ALL, "br_inst_exec.all_branches"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x41, C_ALL, "br_misp_exec.nontaken_cond"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x81, C_ALL, "br_misp_exec.taken_cond"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x84, C_ALL, "br_misp_exec.taken_indirect_jmp_non_call_ret"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x88, C_ALL, "br_misp_exec.taken_return_near"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x90, C_ALL, "br_misp_exec.taken_direct_near_call"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0xA0, C_ALL, "br_misp_exec.taken_indirect_near_call"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0xC1, C_ALL, "br_misp_exec.all_cond"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0xFF, C_ALL, "br_misp_exec.all_branches"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.core"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x01, C_ALL, "uops_dispatched_port.port_0"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x02, C_ALL, "uops_dispatched_port.port_1"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x04, C_ALL, "uops_dispatched_port.port_2_ld"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x08, C_ALL, "uops_dispatched_port.port_2_sta"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x0C, C_ALL, "uops_dispatched_port.port_2"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x10, C_ALL, "uops_dispatched_port.port_3_ld"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x20, C_ALL, "uops_dispatched_port.port_3_sta"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x30, C_ALL, "uops_dispatched_port.port_3"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x40, C_ALL, "uops_dispatched_port.port_4"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x80, C_ALL, "uops_dispatched_port.port_5"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x01, C_ALL, "resource_stalls.any"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x02, C_ALL, "resource_stalls.lb"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x04, C_ALL, "resource_stalls.rs"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x08, C_ALL, "resource_stalls.sb"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x10, C_ALL, "resource_stalls.rob"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x20, C_ALL, "resource_stalls.fcsw"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x40, C_ALL, "resource_stalls.mxcsr"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x80, C_ALL, "resource_stalls.other"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x02, C2   , "cycle_activity.cycles_l1d_pending"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x01, C_ALL, "cycle_activity.cycles_l2_pending"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x04, C0|C1|C2|C3, "cycle_activity.cycles_no_dispatch"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xAB, 0x01, C_ALL, "dsb2mite_switches.count"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xAB, 0x02, C_ALL, "dsb2mite_switches.penalty_cycles"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xAC, 0x02, C_ALL, "dsb_fill.other_cancel"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xAC, 0x08, C_ALL, "dsb_fill.exceed_dsb_lines"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xAC, 0x0A, C_ALL, "dsb_fill.all_cancel"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xAE, 0x01, C_ALL, "itlb.itlb_flush"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x01, C_ALL, "offcore_requests.demand_data_rd"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x04, C_ALL, "offcore_requests.demand_rfo"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x08, C_ALL, "offcore_requests.all_data_rd"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C0|C1|C2|C3, "uops_dispatched.thread"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C0|C1|C2|C3, "uops_dispatched.stall_cycles"                , 0x1, ATTR_INV , 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_dispatched.core"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB2, 0x01, C_ALL, "offcore_requests_buffer.sq_full"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB6, 0x01, C_ALL, "agu_bypass_cancel.count"                           , 0x0, ATTR_NONE, 0x0 }, \
+/* { 0xB7, 0x01, C_ALL, "off_core_response_0"                               , 0x0, ATTR_NONE, 0x1A6 }, ignore events that require msr_offset */ \
+/* { 0xBB, 0x01, C_ALL, "off_core_response_1"                               , 0x0, ATTR_NONE, 0x1A7 }, ignore events that require msr_offset */ \
+{ 0xBD, 0x01, C_ALL, "tlb_flush.dtlb_thread"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBD, 0x20, C_ALL, "tlb_flush.stlb_any"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBF, 0x05, C_ALL, "l1d_blocks.bank_conflict_cycles"                   , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xC0, 0x00, C_ALL, "inst_retired.any_p"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC0, 0x01,    C1, "inst_retired.prec_dist"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC1, 0x02, C_ALL, "other_assists.itlb_miss_retired"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC1, 0x08, C_ALL, "other_assists.avx_store"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC1, 0x10, C_ALL, "other_assists.avx_to_sse"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC1, 0x20, C_ALL, "other_assists.sse_to_avx"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x01, C_ALL, "uops_retired.all"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x01, C_ALL, "uops_retired.active_cycles"                        , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x01, C_ALL, "uops_retired.stall_cycles"                         , 0x1, ATTR_INV , 0x0 }, \
+{ 0xC2, 0x02, C_ALL, "uops_retired.retire_slots"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x02, C_ALL, "machine_clears.memory_ordering"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x04, C_ALL, "machine_clears.smc"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x20, C_ALL, "machine_clears.maskmov"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x00, C_ALL, "br_inst_retired.all_branches"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x01, C_ALL, "br_inst_retired.conditional"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x02, C_ALL, "br_inst_retired.near_call"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x04, C_ALL, "br_inst_retired.all_branches"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x08, C_ALL, "br_inst_retired.near_return"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x10, C_ALL, "br_inst_retired.not_taken"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x20, C_ALL, "br_inst_retired.near_taken"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x40, C_ALL, "br_inst_retired.far_branch"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x00, C_ALL, "br_misp_retired.all_branches"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x00, C_ALL, "br_misp_retired.all_branches"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x01, C_ALL, "br_misp_retired.conditional"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x02, C_ALL, "br_misp_retired.near_call"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x04, C_ALL, "br_misp_retired.all_branches"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x10, C_ALL, "br_misp_retired.not_taken"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x20, C_ALL, "br_misp_retired.taken"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x02, C_ALL, "fp_assist.x87_output"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x04, C_ALL, "fp_assist.x87_input"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x08, C_ALL, "fp_assist.simd_output"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x10, C_ALL, "fp_assist.simd_input"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x1E, C_ALL, "fp_assist.any"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCC, 0x20, C_ALL, "rob_misc_events.lbr_inserts"                       , 0x0, ATTR_NONE, 0x0 }, \
+/* { 0xCD, 0x01, C3, "mem_trans_retired.load_latency"                    , 0x0, ATTR_NONE, 0x3F6 }, ignore events that require msr_offset */ /* See Section "MSR_PEBS_LD_LAT_THRESHOLD" */ \
+{ 0xCD, 0x02,    C3, "mem_trans_retired.precise_store"                   , 0x0, ATTR_NONE, 0x0 }, /* See Section "Precise Store Facility" */ \
+{ 0xD0, 0x11, C_ALL, "mem_uops_retired.stlb_miss_loads"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x12, C_ALL, "mem_uops_retired.stlb_miss_stores"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x21, C_ALL, "mem_uops_retired.lock_loads"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x22, C_ALL, "mem_uops_retired.lock_stores"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x41, C_ALL, "mem_uops_retired.split_loads"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x42, C_ALL, "mem_uops_retired.split_stores"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x81, C_ALL, "mem_uops_retired.all_loads"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x82, C_ALL, "mem_uops_retired.all_stores"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x01, C0|C1|C2|C3, "mem_load_uops_retired.l1_hit"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x02, C_ALL, "mem_load_uops_retired.l2_hit"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x04, C_ALL, "mem_load_uops_retired.llc_hit"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x20, C_ALL, "mem_load_uops_retired.llc_miss"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x40, C_ALL, "mem_load_uops_retired.hit_lfb"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x01, C_ALL, "mem_load_uops_llc_hit_retired.xsnp_miss"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x02, C_ALL, "mem_load_uops_llc_hit_retired.xsnp_hit"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x04, C_ALL, "mem_load_uops_llc_hit_retired.xsnp_hitm"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x08, C_ALL, "mem_load_uops_llc_hit_retired.xsnp_none"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xE6, 0x01, C_ALL, "baclears.any"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x01, C_ALL, "l2_trans.demand_data_rd"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x02, C_ALL, "l2_trans.rfo"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x04, C_ALL, "l2_trans.code_rd"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x08, C_ALL, "l2_trans.all_pf"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x10, C_ALL, "l2_trans.l1d_wb"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x20, C_ALL, "l2_trans.l2_fill"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x40, C_ALL, "l2_trans.l2_wb"                                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x80, C_ALL, "l2_trans.all_requests"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x01, C_ALL, "l2_lines_in.i"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x02, C_ALL, "l2_lines_in.s"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x04, C_ALL, "l2_lines_in.e"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x07, C_ALL, "l2_lines_in.all"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x01, C_ALL, "l2_lines_out.demand_clean"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x02, C_ALL, "l2_lines_out.demand_dirty"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x04, C_ALL, "l2_lines_out.pf_clean"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x08, C_ALL, "l2_lines_out.pf_dirty"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x0A, C_ALL, "l2_lines_out.dirty_all"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF4, 0x10, C_ALL, "sq_misc.split_lock"                                , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+#define EVENTS_FAM6_MOD42_ONLY \
+{ 0xD4, 0x02, C0|C1|C2|C3, "mem_load_uops_misc_retired.llc_miss"         , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+#define EVENTS_FAM6_MOD45_ONLY \
+/* { 0xD3, 0x01, C_ALL, "mem_load_uops_llc_miss_retired.local_dram"   , 0x0, ATTR_NONE, 0x3C9 }, ignore events that require msr_offset */ \
+/* { 0xD3, 0x04, C_ALL, "mem_load_uops_llc_miss_retired.remote_dram"  , 0x0, ATTR_NONE, 0x3C9 }, ignore events that require msr_offset */ \
+/* end of #define */
+
+/* Intel Ivy Bridge Processor */
+/*
+ * The Ivy Bridge tables are basically from Bug 16457100
+ *   libcpc counter names should be based on public Intel documentation -- Ivy Bridge
+ * and those tables are basically from the
+ * Intel SDM, January 2013, Section 19.3, Table 19-5.
+ * Additionally, there is
+ *   Table 19-6.  Model 62 only.
+ */
+
+#define EVENTS_FAM6_MOD58 \
+{ 0x03, 0x02, C_ALL, "ld_blocks.store_forward"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x05, 0x01, C_ALL, "misalign_mem_ref.loads"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x05, 0x02, C_ALL, "misalign_mem_ref.stores"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x01, C_ALL, "ld_blocks_partial.address_alias"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x81, C_ALL, "dtlb_load_misses.miss_causes_a_walk"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x82, C_ALL, "dtlb_load_misses.walk_completed"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x84, C_ALL, "dtlb_load_misses.walk_duration"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x01, C_ALL, "uops_issued.any"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x01, C_ALL, "uops_issued.stall_cycles"                          , 0x1, ATTR_INV , 0x0 }, \
+{ 0x0E, 0x01, C_ALL, "uops_issued.core_stall_cycles"                     , 0x1, ATTR_INV | ATTR_ANY, 0x0 }, \
+{ 0x0E, 0x10, C_ALL, "uops_issued.flags_merge"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x20, C_ALL, "uops_issued.slow_lea"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x40, C_ALL, "uops_issued.sIngle_mul"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x01, C_ALL, "fp_comp_ops_exe.x87"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x10, C_ALL, "fp_comp_ops_exe.sse_fp_packed_double"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x20, C_ALL, "fp_comp_ops_exe.sse_fp_scalar_single"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x40, C_ALL, "fp_comp_ops_exe.sse_packed_single"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x10, 0x80, C_ALL, "fp_comp_ops_exe.sse_scalar_double"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x11, 0x01, C_ALL, "simd_fp_256.packed_single"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x11, 0x02, C_ALL, "simd_fp_256.packed_double"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x14, 0x01, C_ALL, "arith.fpu_div_active"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x14, 0x01, C_ALL, "arith.fpu_div"                                     , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x24, 0x01, C_ALL, "l2_rqsts.demand_data_rd_hit"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x03, C_ALL, "l2_rqsts.all_demand_data_rd"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x04, C_ALL, "l2_rqsts.rfo_hits"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x08, C_ALL, "l2_rqsts.rfo_miss"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x0C, C_ALL, "l2_rqsts.all_rfo"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x10, C_ALL, "l2_rqsts.code_rd_hit"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x20, C_ALL, "l2_rqsts.code_rd_miss"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x30, C_ALL, "l2_rqsts.all_code_rd"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x40, C_ALL, "l2_rqsts.pf_hit"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x80, C_ALL, "l2_rqsts.pf_miss"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xC0, C_ALL, "l2_rqsts.all_pf"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x01, C_ALL, "l2_store_lock_rqsts.miss"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x08, C_ALL, "l2_store_lock_rqsts.hit_m"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x0F, C_ALL, "l2_store_lock_rqsts.all"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x01, C_ALL, "l2_l1d_wb_rqsts.miss"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x04, C_ALL, "l2_l1d_wb_rqsts.hit_e"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x08, C_ALL, "l2_l1d_wb_rqsts.hit_m"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x28, 0x0F, C_ALL, "l2_l1d_wb_rqsts.all"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2E, 0x41, C_ALL, "longest_lat_cache.miss"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2E, 0x4F, C_ALL, "longest_lat_cache.reference"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x00, C_ALL, "cpu_clk_unhalted.thread_p"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x01, C_ALL, "cpu_clk_thread_unhalted.ref_xclk"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C(2), "l1d_pend_miss.pending"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C(2), "l1d_pend_miss.pending_cycles"                       , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C(2), "l1d_pend_miss.occurrences"                          , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x49, 0x01, C_ALL, "dtlb_store_misses.miss_causes_a_walk"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x02, C_ALL, "dtlb_store_misses.walk_completed"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x04, C_ALL, "dtlb_store_misses.walk_duration"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x10, C_ALL, "dtlb_store_misses.stlb_hit"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4C, 0x01, C_ALL, "load_hit_pre.sw_pf"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4C, 0x02, C_ALL, "load_hit_pre.hw_pf"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x01, C_ALL, "l1d.replacement"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x58, 0x04, C_ALL, "move_elimination.int_not_eliminated"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x58, 0x08, C_ALL, "move_elimination.simd_not_eliminated"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x58, 0x01, C_ALL, "move_elimination.int_eliminated"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x58, 0x02, C_ALL, "move_elimination.simd_eliminated"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5C, 0x01, C_ALL, "cpl_cycles.ring0"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5C, 0x01, C_ALL, "cpl_cycles.ring0_trans"                            , 0x0, ATTR_EDGE, 0x0 }, \
+{ 0x5C, 0x02, C_ALL, "cpl_cycles.ring123"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5E, 0x01, C_ALL, "rs_events.empty_cycles"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5F, 0x04, C_ALL, "dtlb_load_misses.stlb_hit"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x01, C_ALL, "offcore_requests_outstanding.demand_data_rd"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x01, C_ALL, "offcore_requests_outstanding.demand_data_rd_cycles", 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x02, C_ALL, "offcore_requests_outstanding.demand_code_rd"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x02, C_ALL, "offcore_requests_outstanding.demand_code_rd_cycles", 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x04, C_ALL, "offcore_requests_outstanding.demand_rfo"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x04, C_ALL, "offcore_requests_outstanding.demand_rfo_cycles"    , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x08, C_ALL, "offcore_requests_outstanding.all_data_rd"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x08, C_ALL, "offcore_requests_outstanding.all_data_rd_cycles"   , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x63, 0x01, C_ALL, "lock_cycles.split_lock_uc_lock_duration"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x63, 0x02, C_ALL, "lock_cycles.cache_lock_duration"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x02, C_ALL, "idq.empty"                                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x04, C_ALL, "idq.mite_uops"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x04, C_ALL, "idq.mite_cycles"                                   , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x08, C_ALL, "idq.dsb_uops"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x08, C_ALL, "idq.dsb_cycles"                                    , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x10, C_ALL, "idq.ms_dsb_uops"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x10, C_ALL, "idq.ms_dsb_cycles"                                 , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x10, C_ALL, "idq.ms_dsb_activations"                            , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x79, 0x18, C_ALL, "idq.all_dsb_uops"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x18, C_ALL, "idq.all_dsb_cycles"                                , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x18, C_ALL, "idq.all_dsb_cycles_any_uops" /* synonym, from Intel SDM */   , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x18, C_ALL, "idq.all_dsb_cycles_4_uops"                         , 0x4, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x20, C_ALL, "idq.ms_mite_cycles"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x20, C_ALL, "idq.ms_mite_cycles"                                , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x24, C_ALL, "idq.all_mite_uops"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x24, C_ALL, "idq.all_mite_cycles"                               , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x24, C_ALL, "idq.all_mite_cycles_any_uops" /* synonym, from Intel SDM */  , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x24, C_ALL, "idq.all_mite_cycles_4_uops"                        , 0x4, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x30, C_ALL, "idq.ms_uops"                                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x30, C_ALL, "idq.ms_cycles"                                     , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x3C, C_ALL, "idq.mite_all_uops"  /* weird name suggested by Intel docs */   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x3C, C_ALL, "idq.mite_all_cycles"                               , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x02, C_ALL, "icache.misses"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x01, C_ALL, "itlb_misses.miss_causes_a_walk"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x02, C_ALL, "itlb_misses.walk_completed"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x04, C_ALL, "itlb_misses.walk_duration"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x10, C_ALL, "itlb_misses.stlb_hit"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x01, C_ALL, "ild_stall.lcp"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x04, C_ALL, "ild_stall.iq_full"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x41, C_ALL, "br_inst_exec.nontaken_cond"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x81, C_ALL, "br_inst_exec.taken_cond"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x82, C_ALL, "br_inst_exec.taken_direct_jmp"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x84, C_ALL, "br_inst_exec.taken_indirect_jmp_non_call_ret"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x88, C_ALL, "br_inst_exec.taken_return_near"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x90, C_ALL, "br_inst_exec.taken_direct_near_call"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xA0, C_ALL, "br_inst_exec.taken_indirect_near_call"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xFF, C_ALL, "br_inst_exec.all_branches"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x41, C_ALL, "br_misp_exec.nontaken_cond"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x81, C_ALL, "br_misp_exec.taken_cond"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x84, C_ALL, "br_misp_exec.taken_indirect_jmp_non_call_ret"      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x88, C_ALL, "br_misp_exec.taken_return_near"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x90, C_ALL, "br_misp_exec.taken_direct_near_call"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0xA0, C_ALL, "br_misp_exec.taken_indirect_near_call"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0xFF, C_ALL, "br_misp_exec.all_branches"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.core"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x01, C_ALL, "uops_dispatched_port.port_0"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x02, C_ALL, "uops_dispatched_port.port_1"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x04, C_ALL, "uops_dispatched_port.port_2_ld"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x08, C_ALL, "uops_dispatched_port.port_2_sta"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x0C, C_ALL, "uops_dispatched_port.port_2"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x10, C_ALL, "uops_dispatched_port.port_3_ld"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x20, C_ALL, "uops_dispatched_port.port_3_sta"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x30, C_ALL, "uops_dispatched_port.port_3"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x40, C_ALL, "uops_dispatched_port.port_4"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x80, C_ALL, "uops_dispatched_port.port_5"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x01, C_ALL, "resource_stalls.any"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x04, C_ALL, "resource_stalls.rs"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x08, C_ALL, "resource_stalls.sb"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x10, C_ALL, "resource_stalls.rob"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x01, C_ALL, "cycle_activity.cycles_l2_pending"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x01, C_ALL, "cycle_activity.cycles_l2_pending_core"             , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA3, 0x02, C0|C1|C2|C3, "cycle_activity.cycles_ldm_pending"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x02, C0|C1|C2|C3, "cycle_activity.cycles_ldm_pending_core"      , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA3, 0x08, C(2), "cycle_activity.cycles_l1d_pending"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x08, C(2), "cycle_activity.cycles_l1d_pending_core"             , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA3, 0x04, C_ALL, "cycle_activity.cycles_no_execute"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x04, C_ALL, "cycle_activity.cycles_no_execute_core"             , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xAB, 0x01, C_ALL, "dsb2mite_switches.count"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xAB, 0x02, C_ALL, "dsb2mite_switches.penalty_cycles"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xAC, 0x08, C_ALL, "dsb_fill.exceed_dsb_lines"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xAE, 0x01, C_ALL, "itlb.itlb_flush"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x01, C_ALL, "offcore_requests.demand_data_rd"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x02, C_ALL, "offcore_requests.demand_code_rd"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x04, C_ALL, "offcore_requests.demand_rfo"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x08, C_ALL, "offcore_requests.all_data_rd"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C_ALL, "uops_executed.thread"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C_ALL, "uops_executed.stall_cycles"                        , 0x1, ATTR_INV , 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core"                                , 0x0, ATTR_NONE, 0x0 }, \
+/* { 0xB7, 0x01, C_ALL, "offcore_response_0"                             , 0x0, ATTR_NONE, 0x1A6 }, ignore events that require msr_offset */ \
+/* { 0xBB, 0x01, C_ALL, "offcore_response_1"                             , 0x0, ATTR_NONE, 0x1A7 }, ignore events that require msr_offset */ \
+{ 0xBD, 0x01, C_ALL, "tlb_flush.dtlb_thread"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBD, 0x20, C_ALL, "tlb_flush.stlb_any"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC0, 0x00, C_ALL, "inst_retired.any_p"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC0, 0x01, C(1), "inst_retired.prec_dist"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC1, 0x08, C_ALL, "other_assists.avx_store"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC1, 0x10, C_ALL, "other_assists.avx_to_sse"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC1, 0x20, C_ALL, "other_assists.sse_to_avx"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x01, C_ALL, "uops_retired.all"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x01, C_ALL, "uops_retired.active_cycles"                        , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x01, C_ALL, "uops_retired.stall_cycles"                         , 0x1, ATTR_INV , 0x0 }, \
+{ 0xC2, 0x02, C_ALL, "uops_retired.retire_slots"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x02, C_ALL, "machine_clears.memory_ordering"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x04, C_ALL, "machine_clears.smc"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x20, C_ALL, "machine_clears.maskmov"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x00, C_ALL, "br_inst_retired.all_branches"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x01, C_ALL, "br_inst_retired.conditional"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x02, C_ALL, "br_inst_retired.near_call"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x04, C_ALL, "br_inst_retired.all_branches"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x08, C_ALL, "br_inst_retired.near_return"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x10, C_ALL, "br_inst_retired.not_taken"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x20, C_ALL, "br_inst_retired.near_taken"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x40, C_ALL, "br_inst_retired.far_branch"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x00, C_ALL, "br_misp_retired.all_branches"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x01, C_ALL, "br_misp_retired.conditional"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x02, C_ALL, "br_misp_retired.near_call"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x04, C_ALL, "br_misp_retired.all_branches"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x10, C_ALL, "br_misp_retired.not_taken"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x20, C_ALL, "br_misp_retired.taken"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x02, C_ALL, "fp_assist.x87_output"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x04, C_ALL, "fp_assist.x87_input"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x08, C_ALL, "fp_assist.simd_output"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x10, C_ALL, "fp_assist.simd_input"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x1E, C_ALL, "fp_assist.any"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCC, 0x20, C_ALL, "rob_misc_events.lbr_inserts"                       , 0x0, ATTR_NONE, 0x0 }, \
+/* { 0xCD, 0x01, C3   , "mem_trans_retired.load_latency"                    , 0x0, ATTR_NONE, 0x3F6 }, ignore events that require msr_offset */ /* See Section "MSR_PEBS_LD_LAT_THRESHOLD" */ \
+{ 0xCD, 0x02, C3   , "mem_trans_retired.precise_store"                   , 0x0, ATTR_NONE, 0x0 }, /* See Section "Precise Store Facility" */ \
+{ 0xD0, 0x11, C_ALL, "mem_uops_retired.stlb_miss_loads"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x12, C_ALL, "mem_uops_retired.stlb_miss_stores"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x21, C_ALL, "mem_uops_retired.lock_loads"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x22, C_ALL, "mem_uops_retired.lock_stores"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x41, C_ALL, "mem_uops_retired.split_loads"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x42, C_ALL, "mem_uops_retired.split_stores"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x81, C_ALL, "mem_uops_retired.all_loads"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD0, 0x82, C_ALL, "mem_uops_retired.all_stores"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x01, C_ALL, "mem_load_uops_retired.l1_hit"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x02, C_ALL, "mem_load_uops_retired.l2_hit"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x04, C_ALL, "mem_load_uops_retired.llc_hit"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x08, C_ALL, "mem_load_uops_retired.l1_miss"                     , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x10, C_ALL, "mem_load_uops_retired.l2_miss"                     , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x20, C_ALL, "mem_load_uops_retired.llc_miss"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD1, 0x40, C_ALL, "mem_load_uops_retired.hit_lfb"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x01, C_ALL, "mem_load_uops_llc_hit_retired.xsnp_miss"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x02, C_ALL, "mem_load_uops_llc_hit_retired.xsnp_hit"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x04, C_ALL, "mem_load_uops_llc_hit_retired.xsnp_hitm"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x08, C_ALL, "mem_load_uops_llc_hit_retired.xsnp_none"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD3, 0x01, C_ALL, "mem_load_uops_llc_miss_retired.local_dram"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xE6, 0x1F, C_ALL, "baclears.any"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x01, C_ALL, "l2_trans.demand_data_rd"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x02, C_ALL, "l2_trans.rfo"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x04, C_ALL, "l2_trans.code_rd"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x08, C_ALL, "l2_trans.all_pf"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x10, C_ALL, "l2_trans.l1d_wb"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x20, C_ALL, "l2_trans.l2_fill"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x40, C_ALL, "l2_trans.l2_wb"                                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x80, C_ALL, "l2_trans.all_requests"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x01, C_ALL, "l2_lines_in.i"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x02, C_ALL, "l2_lines_in.s"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x04, C_ALL, "l2_lines_in.e"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x07, C_ALL, "l2_lines_in.all"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x01, C_ALL, "l2_lines_out.demand_clean"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x02, C_ALL, "l2_lines_out.demand_dirty"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x04, C_ALL, "l2_lines_out.pf_clean"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x08, C_ALL, "l2_lines_out.pf_dirty"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x0A, C_ALL, "l2_lines_out.dirty_all"                            , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+#define EVENTS_FAM6_MOD62_ONLY \
+{ 0xD3, 0x01, C_ALL, "mem_load_uops_llc_miss_retired.local_dram"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD3, 0x04, C_ALL, "mem_load_uops_llc_miss_retired.remote_dram"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD3, 0x10, C_ALL, "mem_load_uops_llc_miss_retired.remote_hitm"        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD3, 0x20, C_ALL, "mem_load_uops_llc_miss_retired.remote_fwd"         , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+/* Intel Haswell Processor */
+/*
+ * The Haswell tables take into account Bug 17006019
+ *   libcpc counter names should be based on public Intel documentation -- Haswell
+ * and are basically from the
+ * Intel SDM, June 2013, Section 19.3, Table 19-2 and Table 19-3.
+ * We omit the Table 19-4 uncore events.
+ */
+
+#define EVENTS_FAM6_MOD60 \
+{ 0x03, 0x02, C_ALL, "ld_blocks.store_forward"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x03, 0x08, C_ALL, "ld_blocks.no_sr"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x05, 0x01, C_ALL, "misalign_mem_ref.loads"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x05, 0x02, C_ALL, "misalign_mem_ref.stores"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x01, C_ALL, "ld_blocks_partial.address_alias"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x01, C_ALL, "dtlb_load_misses.miss_causes_a_walk"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x02, C_ALL, "dtlb_load_misses.walk_completed_4k"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x04, C_ALL, "dtlb_load_misses.walk_completed_2m_4m"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x0E, C_ALL, "dtlb_load_misses.walk_completed"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x10, C_ALL, "dtlb_load_misses.walk_duration"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x20, C_ALL, "dtlb_load_misses.stlb_hit_4k"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x40, C_ALL, "dtlb_load_misses.stlb_hit_2m"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x60, C_ALL, "dtlb_load_misses.stlb_hit"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x80, C_ALL, "dtlb_load_misses.pde_cache_miss"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0D, 0x03, C_ALL, "int_misc.recovery_cycles"                          , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x0D, 0x03, C_ALL, "int_misc.recovery_cycles_occurrences"              , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x0E, 0x01, C_ALL, "uops_issued.any"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x01, C_ALL, "uops_issued.stall_cycles"                          , 0x1, ATTR_INV , 0x0 }, \
+{ 0x0E, 0x01, C_ALL, "uops_issued.core_stall_cycles"                     , 0x1, ATTR_INV | ATTR_ANY, 0x0 }, \
+{ 0x0E, 0x10, C_ALL, "uops_issued.flags_merge"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x20, C_ALL, "uops_issued.slow_lea"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x40, C_ALL, "uops_issued.single_mul"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x21, C_ALL, "l2_rqsts.demand_data_rd_miss"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x22, C_ALL, "l2_rqsts.rfo_miss"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x24, C_ALL, "l2_rqsts.code_rd_miss"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x27, C_ALL, "l2_rqsts.all_demand_miss"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x30, C_ALL, "l2_rqsts.l2_pf_miss"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x3F, C_ALL, "l2_rqsts.miss"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x41, C_ALL, "l2_rqsts.demand_data_rd_hit"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x42, C_ALL, "l2_rqsts.rfo_hit"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x44, C_ALL, "l2_rqsts.code_rd_hit"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x50, C_ALL, "l2_rqsts.l2_pf_hit"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xE1, C_ALL, "l2_rqsts.all_demand_data_rd"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xE2, C_ALL, "l2_rqsts.all_rfo"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xE4, C_ALL, "l2_rqsts.all_code_rd"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xE7, C_ALL, "l2_rqsts.all_demand_references"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xF8, C_ALL, "l2_rqsts.all_pf"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xFF, C_ALL, "l2_rqsts.references"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x27, 0x50, C_ALL, "l2_demand_rqsts.wb_hit"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2E, 0x4F, C_ALL, "longest_lat_cache.reference"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2E, 0x41, C_ALL, "longest_lat_cache.miss"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x00, C_ALL, "cpu_clk_unhalted.thread_p"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x01, C_ALL, "cpu_clk_thread_unhalted.ref_xclk"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C(2) , "l1d_pend_miss.pending"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C(2) , "l1d_pend_miss.pending_cycles"                      , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C(2) , "l1d_pend_miss.occurences"                          , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x49, 0x01, C_ALL, "dtlb_store_misses.miss_causes_a_walk"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x02, C_ALL, "dtlb_store_misses.walk_completed_4k"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x04, C_ALL, "dtlb_store_misses.walk_completed_2m_4m"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x0E, C_ALL, "dtlb_store_misses.walk_completed"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x10, C_ALL, "dtlb_store_misses.walk_duration"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x20, C_ALL, "dtlb_store_misses.stlb_hit_4k"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x40, C_ALL, "dtlb_store_misses.stlb_hit_2m"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x60, C_ALL, "dtlb_store_misses.stlb_hit"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x80, C_ALL, "dtlb_store_misses.pde_cache_miss"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4C, 0x01, C_ALL, "load_hit_pre.sw_pf"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4C, 0x02, C_ALL, "load_hit_pre.hw_pf"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x01, C_ALL, "l1d.replacement"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x54, 0x01, C_ALL, "tx_mem.abort_conflict"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x54, 0x02, C_ALL, "tx_mem.abort_capacity"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x54, 0x04, C_ALL, "tx_mem.abort_hle_store_to_elided_lock"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x54, 0x08, C_ALL, "tx_mem.abort_hle_elision_buffer_not_empty"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x54, 0x10, C_ALL, "tx_mem.abort_hle_elision_buffer_mismatch"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x54, 0x20, C_ALL, "tx_mem.abort_hle_elision_buffer_unsupported_alignment"  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x54, 0x40, C_ALL, "tx_mem.abort_hle_elision_buffer_full"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x58, 0x01, C_ALL, "move_elimination.int_eliminated"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x58, 0x02, C_ALL, "move_elimination.simd_eliminated"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x58, 0x04, C_ALL, "move_elimination.int_not_eliminated"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x58, 0x08, C_ALL, "move_elimination.simd_not_eliminated"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5C, 0x01, C_ALL, "cpl_cycles.ring0"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5C, 0x01, C_ALL, "cpl_cycles.ring0_trans"                            , 0x0, ATTR_EDGE, 0x0 }, \
+{ 0x5C, 0x02, C_ALL, "cpl_cycles.ring123"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5D, 0x01, C_ALL, "tx_exec.misc1"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5D, 0x02, C_ALL, "tx_exec.misc2"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5D, 0x04, C_ALL, "tx_exec.misc3"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5D, 0x08, C_ALL, "tx_exec.misc4"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5D, 0x10, C_ALL, "tx_exec.misc5"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5E, 0x01, C_ALL, "rs_events.empty_cycles"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x01, C_ALL, "offcore_requests_outstanding.demand_data_rd"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x01, C_ALL, "offcore_requests_outstanding.cycles_with_demand_data_rd", 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x02, C_ALL, "offcore_requests_outstanding.demand_code_rd"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x02, C_ALL, "offcore_requests_outstanding.demand_code_rd_cycles", 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x04, C_ALL, "offcore_requests_outstanding.demand_rfo"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x04, C_ALL, "offcore_requests_outstanding.demand_rfo_cycles"    , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x08, C_ALL, "offcore_requests_outstanding.all_data_rd"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x08, C_ALL, "offcore_requests_outstanding.cycles_with_data_rd"  , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x63, 0x01, C_ALL, "lock_cycles.split_lock_uc_lock_duration"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x63, 0x02, C_ALL, "lock_cycles.cache_lock_duration"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x02, C_ALL, "idq.empty"                                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x04, C_ALL, "idq.mite_uops"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x04, C_ALL, "idq.mite_cycles"                                   , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x20, C_ALL, "idq.ms_mite_uops"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x20, C_ALL, "idq.ms_mite_cycles"                                , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x24, C_ALL, "idq.all_mite_cycles_any_uops"                      , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x24, C_ALL, "idq.all_mite_cycles_4_uops"                        , 0x4, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x08, C_ALL, "idq.dsb_uops"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x08, C_ALL, "idq.dsb_cycles"                                    , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x10, C_ALL, "idq.ms_dsb_uops"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x10, C_ALL, "idq.ms_dsb_cycles"                                 , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x10, C_ALL, "idq.ms_dsb_occur"                                  , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x79, 0x18, C_ALL, "idq.all_dsb_cycles_any_uops"                       , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x18, C_ALL, "idq.all_dsb_cycles_4_uops"                         , 0x4, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x30, C_ALL, "idq.ms_uops"                                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x30, C_ALL, "idq.ms_cycles"                                     , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x3C, C_ALL, "idq.mite_all_uops"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x02, C_ALL, "icache.misses"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x01, C_ALL, "itlb_misses.miss_causes_a_walk"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x02, C_ALL, "itlb_misses.walk_completed_4k"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x04, C_ALL, "itlb_misses.walk_completed_2m_4m"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x0E, C_ALL, "itlb_misses.walk_completed"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x10, C_ALL, "itlb_misses.walk_duration"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x20, C_ALL, "itlb_misses.stlb_hit_4k"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x40, C_ALL, "itlb_misses.stlb_hit_2m"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x60, C_ALL, "itlb_misses.stlb_hit"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x01, C_ALL, "ild_stall.lcp"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x04, C_ALL, "ild_stall.iq_full"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x41, C_ALL, "br_inst_exec.nontaken_conditional"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x81, C_ALL, "br_inst_exec.taken_conditional"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x82, C_ALL, "br_inst_exec.taken_direct_jump"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x84, C_ALL, "br_inst_exec.taken_indirect_jump_non_call_ret"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x88, C_ALL, "br_inst_exec.taken_indirect_near_return"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x90, C_ALL, "br_inst_exec.taken_direct_near_call"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xA0, C_ALL, "br_inst_exec.taken_indirect_near_call"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xFF, C_ALL, "br_inst_exec.all_branches"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x41, C_ALL, "br_misp_exec.nontaken_conditional"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x81, C_ALL, "br_misp_exec.taken_conditional"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x84, C_ALL, "br_misp_exec.taken_indirect_jump_non_call_ret"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x88, C_ALL, "br_misp_exec.taken_return_near"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x90, C_ALL, "br_misp_exec.taken_direct_near_call"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0xA0, C_ALL, "br_misp_exec.taken_indirect_near_call"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0xFF, C_ALL, "br_misp_exec.all_branches"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.core"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_0_uops_deliv.core"   , 0x4, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_le_1_uop_deliv.core" , 0x3, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_le_2_uop_deliv.core" , 0x2, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_le_3_uop_deliv.core" , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_fe_was_ok"           , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x01, C_ALL, "uops_executed_port.port_0"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x02, C_ALL, "uops_executed_port.port_1"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x04, C_ALL, "uops_executed_port.port_2"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x08, C_ALL, "uops_executed_port.port_3"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x10, C_ALL, "uops_executed_port.port_4"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x20, C_ALL, "uops_executed_port.port_5"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x40, C_ALL, "uops_executed_port.port_6"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x80, C_ALL, "uops_executed_port.port_7"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x01, C_ALL, "uops_executed_port.port_0_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x02, C_ALL, "uops_executed_port.port_1_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x04, C_ALL, "uops_executed_port.port_2_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x08, C_ALL, "uops_executed_port.port_3_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x10, C_ALL, "uops_executed_port.port_4_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x20, C_ALL, "uops_executed_port.port_5_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x40, C_ALL, "uops_executed_port.port_6_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x80, C_ALL, "uops_executed_port.port_7_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA2, 0x01, C_ALL, "resource_stalls.any"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x04, C_ALL, "resource_stalls.rs"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x08, C_ALL, "resource_stalls.sb"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x10, C_ALL, "resource_stalls.rob"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x01, C_ALL, "cycle_activity.cycles_l2_pending"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x01, C_ALL, "cycle_activity.cycles_l2_pending_cycles"           , 0x2, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x02, C_ALL, "cycle_activity.cycles_ldm_pending"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x02, C_ALL, "cycle_activity.cycles_ldm_pending_cycles"          , 0x2, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x05, C_ALL, "cycle_activity.stalls_l2_pending"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x08, C(2) , "cycle_activity.cycles_l1d_pending"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x08, C(2) , "cycle_activity.cycles_l1d_pending_cycles"          , 0x8, ATTR_NONE, 0x0 }, \
+{ 0xA8, 0x01, C_ALL, "lsd.uops"                                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xAE, 0x01, C_ALL, "itlb.itlb_flush"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x01, C_ALL, "offcore_requests.demand_data_rd"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x02, C_ALL, "offcore_requests.demand_code_rd"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x04, C_ALL, "offcore_requests.demand_rfo"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x08, C_ALL, "offcore_requests.all_data_rd"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core"                                , 0x0, ATTR_NONE, 0x0 }, \
+/* { 0xB7, 0x01, C_ALL, "off_core_response_0"                               , 0x0, ATTR_NONE, 0x1A6 }, omit events requiring MSR programming */ \
+/* { 0xBB, 0x01, C_ALL, "off_core_response_1"                               , 0x0, ATTR_NONE, 0x1A7 }, omit events requiring MSR programming */ \
+{ 0xBC, 0x11, C_ALL, "page_walker_loads.dtlb_l1"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBC, 0x21, C_ALL, "page_walker_loads.itlb_l1"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBC, 0x12, C_ALL, "page_walker_loads.dtlb_l2"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBC, 0x22, C_ALL, "page_walker_loads.itlb_l2"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBC, 0x14, C_ALL, "page_walker_loads.dtlb_l3"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBC, 0x24, C_ALL, "page_walker_loads.itlb_l3"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBC, 0x18, C_ALL, "page_walker_loads.dtlb_memory"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBC, 0x28, C_ALL, "page_walker_loads.itlb_memory"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBD, 0x01, C_ALL, "tlb_flush.dtlb_thread"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBD, 0x20, C_ALL, "tlb_flush.stlb_any"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC0, 0x00, C_ALL, "inst_retired.any_p"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC0, 0x01, C(1) , "inst_retired.prec_dist"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC1, 0x08, C_ALL, "other_assists.avx_to_sse"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC1, 0x10, C_ALL, "other_assists.sse_to_avx"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC1, 0x40, C_ALL, "other_assists.any_wb_assist"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x01, C_ALL, "uops_retired.all"                                  , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC2, 0x01, C_ALL, "uops_retired.stall_cycles"                         , 0x1, ATTR_INV , 0x0 }, \
+{ 0xC2, 0x02, C_ALL, "uops_retired.retire_slots"                         , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC3, 0x02, C_ALL, "machine_clears.memory_ordering"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x04, C_ALL, "machine_clears.smc"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x20, C_ALL, "machine_clears.maskmov"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x00, C_ALL, "br_inst_retired.all_branches"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x01, C_ALL, "br_inst_retired.conditional"                       , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC4, 0x02, C_ALL, "br_inst_retired.near_call"                         , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC4, 0x04, C_ALL, "br_inst_retired.all_branches"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC4, 0x08, C_ALL, "br_inst_retired.near_return"                       , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC4, 0x10, C_ALL, "br_inst_retired.not_taken"                         , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC4, 0x20, C_ALL, "br_inst_retired.near_taken"                        , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC4, 0x40, C_ALL, "br_inst_retired.far_branch"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x00, C_ALL, "br_misp_retired.all_branches"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x01, C_ALL, "br_misp_retired.conditional"                       , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC5, 0x04, C_ALL, "br_misp_retired.all_branches"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC5, 0x20, C_ALL, "br_misp_retired.near_taken"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC8, 0x01, C_ALL, "hle_retired.start"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC8, 0x02, C_ALL, "hle_retired.commit"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC8, 0x04, C_ALL, "hle_retired.aborted"                               , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC8, 0x08, C_ALL, "hle_retired.aborted_misc1"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC8, 0x10, C_ALL, "hle_retired.aborted_misc2"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC8, 0x20, C_ALL, "hle_retired.aborted_misc3"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC8, 0x40, C_ALL, "hle_retired.aborted_misc4"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC8, 0x80, C_ALL, "hle_retired.aborted_misc5"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC9, 0x01, C_ALL, "rtm_retired.start"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC9, 0x02, C_ALL, "rtm_retired.commit"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC9, 0x04, C_ALL, "rtm_retired.aborted"                               , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC9, 0x08, C_ALL, "rtm_retired.aborted_misc1"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC9, 0x10, C_ALL, "rtm_retired.aborted_misc2"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC9, 0x20, C_ALL, "rtm_retired.aborted_misc3"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC9, 0x40, C_ALL, "rtm_retired.aborted_misc4"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC9, 0x80, C_ALL, "rtm_retired.aborted_misc5"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x02, C_ALL, "fp_assist.x87_output"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x04, C_ALL, "fp_assist.x87_input"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x08, C_ALL, "fp_assist.simd_output"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x10, C_ALL, "fp_assist.simd_input"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x1E, C_ALL, "fp_assist.any"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCC, 0x20, C_ALL, "rob_misc_events.lbr_inserts"                       , 0x0, ATTR_NONE, 0x0 }, \
+/* { 0xCD, 0x01, C_ALL, "mem_trans_retired.load_latency"                    , 0x0, ATTR_NONE, 0x3F6 }, omit events requiring MSR programming */ \
+{ 0xD0, 0x11, C_ALL, "mem_uops_retired.stlb_miss_loads"                  , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x12, C_ALL, "mem_uops_retired.stlb_miss_stores"                 , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x21, C_ALL, "mem_uops_retired.lock_loads"                       , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x22, C_ALL, "mem_uops_retired.lock_stores"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x41, C_ALL, "mem_uops_retired.split_loads"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x42, C_ALL, "mem_uops_retired.split_stores"                     , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x81, C_ALL, "mem_uops_retired.all_loads"                        , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x82, C_ALL, "mem_uops_retired.all_stores"                       , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x01, C_ALL, "mem_load_uops_retired.l1_hit"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x02, C_ALL, "mem_load_uops_retired.l2_hit"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x04, C_ALL, "mem_load_uops_retired.l3_hit"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x08, C_ALL, "mem_load_uops_retired.l1_miss"                     , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x10, C_ALL, "mem_load_uops_retired.l2_miss"                     , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x20, C_ALL, "mem_load_uops_retired.l3_miss"                     , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x40, C_ALL, "mem_load_uops_retired.hit_lfb"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xD2, 0x01, C_ALL, "mem_load_uops_l3_hit_retired.xsnp_miss"            , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD2, 0x02, C_ALL, "mem_load_uops_l3_hit_retired.xsnp_hit"             , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD2, 0x04, C_ALL, "mem_load_uops_l3_hit_retired.xsnp_hitm"            , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD2, 0x08, C_ALL, "mem_load_uops_l3_hit_retired.xsnp_none"            , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD3, 0x01, C_ALL, "mem_load_uops_l3_miss_retired.local_dram"          , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xE6, 0x1F, C_ALL, "baclears.any"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x01, C_ALL, "l2_trans.demand_data_rd"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x02, C_ALL, "l2_trans.rfo"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x04, C_ALL, "l2_trans.code_rd"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x08, C_ALL, "l2_trans.all_pf"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x10, C_ALL, "l2_trans.l1d_wb"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x20, C_ALL, "l2_trans.l2_fill"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x40, C_ALL, "l2_trans.l2_wb"                                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x80, C_ALL, "l2_trans.all_requests"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x01, C_ALL, "l2_lines_in.i"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x02, C_ALL, "l2_lines_in.s"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x04, C_ALL, "l2_lines_in.e"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x07, C_ALL, "l2_lines_in.all"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x05, C_ALL, "l2_lines_out.demand_clean"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x06, C_ALL, "l2_lines_out.demand_dirty"                         , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+/* Intel Broadwell Processor */
+/*
+ * This table is essentially taken from:
+ *   https://grok.cz.oracle.com/source/xref/on12-clone/usr/src/uts/intel/pcbe/bdw_pcbe_tbl.c
+ */
+
+#define EVENTS_FAM6_MOD61 \
+{ 0x03, 0x02, C_ALL, "ld_blocks.store_forward"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x03, 0x08, C_ALL, "ld_blocks.no_sr"                                   , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x05, 0x01, C_ALL, "misalign_mem_ref.loads"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x05, 0x02, C_ALL, "misalign_mem_ref.stores"                           , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x07, 0x01, C_ALL, "ld_blocks_partial.address_alias"                   , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x08, 0x01, C_ALL, "dtlb_load_misses.miss_causes_a_walk"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x02, C_ALL, "dtlb_load_misses.walk_completed_4k"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x04, C_ALL, "dtlb_load_misses.walk_completed_2m_4m"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x0E, C_ALL, "dtlb_load_misses.walk_completed"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x10, C_ALL, "dtlb_load_misses.walk_duration"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x20, C_ALL, "dtlb_load_misses.stlb_hit_4k"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x40, C_ALL, "dtlb_load_misses.stlb_hit_2m"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x60, C_ALL, "dtlb_load_misses.stlb_hit"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x80, C_ALL, "dtlb_load_misses.pde_cache_miss"                   , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x0D, 0x03, C_ALL, "int_misc.recovery_cycles"                          , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x0D, 0x03, C_ALL, "int_misc.recovery_cycles_any"                      , 0x1, ATTR_ANY , 0x0 }, \
+/* Private event, not public by Intel */ \
+{ 0x0D, 0x03, C_ALL, "int_misc.recovery_cycles_occurrences"              , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x0D, 0x08, C_ALL, "int_misc.rat_stall_cycles"                         , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x0E, 0x01, C_ALL, "uops_issued.any"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x10, C_ALL, "uops_issued.flags_merge"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x20, C_ALL, "uops_issued.slow_lea"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x40, C_ALL, "uops_issued.single_mul"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x01, C_ALL, "uops_issued.stall_cycles"                          , 0x1, ATTR_INV , 0x0 }, \
+{ 0x0E, 0x01, C_ALL, "uops_issued.core_stall_cycles"                     , 0x1,(ATTR_INV | ATTR_ANY), 0x0 }, \
+ \
+{ 0x14, 0x01, C_ALL, "arith.fpu_div_active"                              , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x24, 0x21, C_ALL, "l2_rqsts.demand_data_rd_miss"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x41, C_ALL, "l2_rqsts.demand_data_rd_hit"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x30, C_ALL, "l2_rqsts.l2_pf_miss"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x50, C_ALL, "l2_rqsts.l2_pf_hit"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xE1, C_ALL, "l2_rqsts.all_demand_data_rd"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xE2, C_ALL, "l2_rqsts.all_rfo"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xE4, C_ALL, "l2_rqsts.all_code_rd"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xF8, C_ALL, "l2_rqsts.all_pf"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x42, C_ALL, "l2_rqsts.rfo_hit"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x22, C_ALL, "l2_rqsts.rfo_miss"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x44, C_ALL, "l2_rqsts.code_rd_hit"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x24, C_ALL, "l2_rqsts.code_rd_miss"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x27, C_ALL, "l2_rqsts.all_demand_miss"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xE7, C_ALL, "l2_rqsts.all_demand_references"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x3F, C_ALL, "l2_rqsts.miss"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xFF, C_ALL, "l2_rqsts.references"                               , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x27, 0x50, C_ALL, "l2_demand_rqsts.wb_hit"                            , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x3C, 0x00, C_ALL, "cpu_clk_unhalted.thread_p"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x00, C_ALL, "cpu_clk_unhalted.thread_p_any"                     , 0x0, ATTR_ANY , 0x0 }, \
+{ 0x3C, 0x01, C_ALL, "cpu_clk_thread_unhalted.ref_xclk"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x01, C_ALL, "cpu_clk_thread_unhalted.ref_xclk_any"              , 0x0, ATTR_ANY , 0x0 }, \
+{ 0x3C, 0x02, C_ALL, "cpu_clk_thread_unhalted.one_thread_active"         , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x48, 0x01, C(2) , "l1d_pend_miss.pending"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C(2) , "l1d_pend_miss.pending_cycles"                      , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C(2) , "l1d_pend_miss.pending_cycles_any"                  , 0x1, ATTR_ANY , 0x0 }, \
+/* Private event, not public by Intel */ \
+{ 0x48, 0x01, C(2) , "l1d_pend_miss.occurences"                          , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x48, 0x02, C_ALL, "l1d_pend_miss.fb_full"                             , 0x1, ATTR_NONE, 0x0 }, \
+ \
+{ 0x49, 0x01, C_ALL, "dtlb_store_misses.miss_causes_a_walk"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x02, C_ALL, "dtlb_store_misses.walk_completed_4k"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x04, C_ALL, "dtlb_store_misses.walk_completed_2m_4m"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x0E, C_ALL, "dtlb_store_misses.walk_completed"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x10, C_ALL, "dtlb_store_misses.walk_duration"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x20, C_ALL, "dtlb_store_misses.stlb_hit_4k"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x40, C_ALL, "dtlb_store_misses.stlb_hit_2m"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x60, C_ALL, "dtlb_store_misses.stlb_hit"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x80, C_ALL, "dtlb_store_misses.pde_cache_miss"                  , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x4C, 0x01, C_ALL, "load_hit_pre.sw_pf"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4C, 0x02, C_ALL, "load_hit_pre.hw_pf"                                , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x4F, 0x10, C_ALL, "ept.walk_cycles"                                   , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x51, 0x01, C_ALL, "l1d.replacement"                                   , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x54, 0x01, C_ALL, "tx_mem.abort_conflict"                             , 0x0, ATTR_TSX , 0x0 }, \
+{ 0x54, 0x02, C_ALL, "tx_mem.abort_capacity_write"                       , 0x0, ATTR_TSX , 0x0 }, \
+{ 0x54, 0x04, C_ALL, "tx_mem.abort_hle_store_to_elided_lock"             , 0x0, ATTR_TSX , 0x0 }, \
+{ 0x54, 0x08, C_ALL, "tx_mem.abort_hle_elision_buffer_not_empty"         , 0x0, ATTR_TSX , 0x0 }, \
+{ 0x54, 0x10, C_ALL, "tx_mem.abort_hle_elision_buffer_mismatch"          , 0x0, ATTR_TSX , 0x0 }, \
+{ 0x54, 0x20, C_ALL, "tx_mem.abort_hle_elision_buffer_unsupported_alignment"  , 0x0, ATTR_TSX , 0x0 }, \
+{ 0x54, 0x40, C_ALL, "tx_mem.hle_elision_buffer_full"                    , 0x0, ATTR_TSX , 0x0 }, \
+ \
+{ 0x58, 0x01, C_ALL, "move_elimination.int_eliminated"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x58, 0x02, C_ALL, "move_elimination.simd_eliminated"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x58, 0x04, C_ALL, "move_elimination.int_not_eliminated"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x58, 0x08, C_ALL, "move_elimination.simd_not_eliminated"              , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x5C, 0x01, C_ALL, "cpl_cycles.ring0"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5C, 0x01, C_ALL, "cpl_cycles.ring0_trans"                            , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x5C, 0x02, C_ALL, "cpl_cycles.ring123"                                , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x5D, 0x01, C_ALL, "tx_exec.misc1"                                     , 0x0, ATTR_TSX , 0x0 }, \
+{ 0x5D, 0x02, C_ALL, "tx_exec.misc2"                                     , 0x0, ATTR_TSX , 0x0 }, \
+{ 0x5D, 0x04, C_ALL, "tx_exec.misc3"                                     , 0x0, ATTR_TSX , 0x0 }, \
+{ 0x5D, 0x08, C_ALL, "tx_exec.misc4"                                     , 0x0, ATTR_TSX , 0x0 }, \
+{ 0x5D, 0x10, C_ALL, "tx_exec.misc5"                                     , 0x0, ATTR_TSX , 0x0 }, \
+ \
+{ 0x5E, 0x01, C_ALL, "rs_events.empty_cycles"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5E, 0x01, C_ALL, "rs_events.empty_end"                               , 0x1, (ATTR_INV | ATTR_EDGE), 0x0 }, \
+ \
+{ 0x60, 0x01, C_ALL, "offcore_requests_outstanding.demand_data_rd"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x01, C_ALL, "offcore_requests_outstanding.cycles_with_demand_data_rd", 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x01, C_ALL, "offcore_requests_outstanding.demand_data_rd_ge_6 " , 0x6, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x02, C_ALL, "offcore_requests_outstanding.demand_code_rd"       , 0x0, ATTR_NONE, 0x0 }, \
+/* Private event, not public by Intel */ \
+{ 0x60, 0x02, C_ALL, "offcore_requests_outstanding.demand_code_rd_cycles", 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x04, C_ALL, "offcore_requests_outstanding.demand_rfo"           , 0x0, ATTR_NONE, 0x0 }, \
+/* Private event, not public by Intel */ \
+{ 0x60, 0x04, C_ALL, "offcore_requests_outstanding.demand_rfo_cycles"    , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x08, C_ALL, "offcore_requests_outstanding.all_data_rd"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x08, C_ALL, "offcore_requests_outstanding.cycles_with_data_rd"  , 0x1, ATTR_NONE, 0x0 }, \
+ \
+{ 0x63, 0x01, C_ALL, "lock_cycles.split_lock_uc_lock_duration"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x63, 0x02, C_ALL, "lock_cycles.cache_lock_duration"                   , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x79, 0x02, C_ALL, "idq.empty"                                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x04, C_ALL, "idq.mite_uops"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x04, C_ALL, "idq.mite_cycles"                                   , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x08, C_ALL, "idq.dsb_uops"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x08, C_ALL, "idq.dsb_cycles"                                    , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x10, C_ALL, "idq.ms_dsb_uops"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x10, C_ALL, "idq.ms_dsb_cycles"                                 , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x10, C_ALL, "idq.ms_dsb_occur"                                  , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x79, 0x18, C_ALL, "idq.all_dsb_cycles_4_uops"                         , 0x4, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x18, C_ALL, "idq.all_dsb_cycles_any_uops"                       , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x20, C_ALL, "idq.ms_mite_uops"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x24, C_ALL, "idq.all_mite_cycles_4_uops"                        , 0x4, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x24, C_ALL, "idq.all_mite_cycles_any_uops"                      , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x30, C_ALL, "idq.ms_uops"                                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x30, C_ALL, "idq.ms_cycles"                                     , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x30, C_ALL, "idq.ms_switches"                                   , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x79, 0x3C, C_ALL, "idq.mite_all_uops"                                 , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x80, 0x01, C_ALL, "icache.hit"                                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x02, C_ALL, "icache.misses"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x80, 0x04, C_ALL, "icache.ifdata_stall"                               , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x85, 0x01, C_ALL, "itlb_misses.miss_causes_a_walk"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x02, C_ALL, "itlb_misses.walk_completed_4k"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x04, C_ALL, "itlb_misses.walk_completed_2m_4m"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x0E, C_ALL, "itlb_misses.walk_completed"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x10, C_ALL, "itlb_misses.walk_duration"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x20, C_ALL, "itlb_misses.stlb_hit_4k"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x40, C_ALL, "itlb_misses.stlb_hit_2m"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x60, C_ALL, "itlb_misses.stlb_hit"                              , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x87, 0x01, C_ALL, "ild_stall.lcp"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x04, C_ALL, "ild_stall.iq_full"                                 , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x88, 0x41, C_ALL, "br_inst_exec.nontaken_conditional"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x81, C_ALL, "br_inst_exec.taken_conditional"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x82, C_ALL, "br_inst_exec.taken_direct_jump"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x84, C_ALL, "br_inst_exec.taken_indirect_jump_non_call_ret"     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x88, C_ALL, "br_inst_exec.taken_indirect_near_return"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0x90, C_ALL, "br_inst_exec.taken_direct_near_call"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xA0, C_ALL, "br_inst_exec.taken_indirect_near_call"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xC1, C_ALL, "br_inst_exec.all_conditional"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xC2, C_ALL, "br_inst_exec.all_direct_jmp"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xC4, C_ALL, "br_inst_exec.all_indirect_jump_non_call_ret"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xC8, C_ALL, "br_inst_exec.all_indirect_near_return"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xD0, C_ALL, "br_inst_exec.all_direct_near_call"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x88, 0xFF, C_ALL, "br_inst_exec.all_branches"                         , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0x89, 0x41, C_ALL, "br_misp_exec.nontaken_conditional"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x81, C_ALL, "br_misp_exec.taken_conditional"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0x84, C_ALL, "br_misp_exec.taken_indirect_jump_non_call_ret"     , 0x0, ATTR_NONE, 0x0 }, \
+/* Private event, not public by Intel */ \
+{ 0x89, 0x88, C_ALL, "br_misp_exec.taken_return_near"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0xC1, C_ALL, "br_misp_exec.all_conditional"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0xC4, C_ALL, "br_misp_exec.all_indirect_jump_non_call_ret"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0xA0, C_ALL, "br_misp_exec.taken_indirect_near_call"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x89, 0xFF, C_ALL, "br_misp_exec.all_branches"                         , 0x0, ATTR_NONE, 0x0 }, \
+ \
+/* Use Cmask to qualify uop b/w */ \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.core"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_0_uops_deliv.core"   , 0x4, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_le_1_uop_deliv.core" , 0x3, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_le_2_uop_deliv.core" , 0x2, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_le_3_uop_deliv.core" , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_fe_was_ok"           , 0x1, ATTR_INV , 0x0 }, \
+ \
+{ 0xA0, 0x03, C_ALL, "uop_dispatches_cancelled.simd_prf"                 , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0xA1, 0x01, C_ALL, "uops_executed_port.port_0"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x02, C_ALL, "uops_executed_port.port_1"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x04, C_ALL, "uops_executed_port.port_2"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x08, C_ALL, "uops_executed_port.port_3"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x10, C_ALL, "uops_executed_port.port_4"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x20, C_ALL, "uops_executed_port.port_5"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x40, C_ALL, "uops_executed_port.port_6"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x80, C_ALL, "uops_executed_port.port_7"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x01, C_ALL, "uops_executed_port.port_0_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x02, C_ALL, "uops_executed_port.port_1_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x04, C_ALL, "uops_executed_port.port_2_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x08, C_ALL, "uops_executed_port.port_3_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x10, C_ALL, "uops_executed_port.port_4_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x20, C_ALL, "uops_executed_port.port_5_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x40, C_ALL, "uops_executed_port.port_6_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+{ 0xA1, 0x80, C_ALL, "uops_executed_port.port_7_core"                    , 0x0, ATTR_ANY , 0x0 }, \
+ \
+{ 0xA2, 0x01, C_ALL, "resource_stalls.any"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x04, C_ALL, "resource_stalls.rs"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x08, C_ALL, "resource_stalls.sb"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x10, C_ALL, "resource_stalls.rob"                               , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0xA3, 0x01, C_ALL, "cycle_activity.cycles_l2_pending"                  , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x02, C_ALL, "cycle_activity.cycles_ldm_pending"                 , 0x2, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x04, C_ALL, "cycle_activity.cycles_no_execute"                  , 0x4, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x05, C_ALL, "cycle_activity.stalls_l2_pending"                  , 0x5, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x06, C_ALL, "cycle_activity.stalls_ldm_pending"                 , 0x6, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x08, C(2) , "cycle_activity.cycles_l1d_pending"                 , 0x8, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x0C, C(2) , "cycle_activity.stalls_l1d_pending"                 , 0xC, ATTR_NONE, 0x0 }, \
+ \
+{ 0xA8, 0x01, C_ALL, "lsd.uops"                                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA8, 0x01, C_ALL, "lsd.cycles_active"                                 , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xA8, 0x01, C_ALL, "lsd.cycles_4_uops"                                 , 0x4, ATTR_NONE, 0x0 }, \
+ \
+{ 0xAB, 0x02, C_ALL, "dsb2mite_switches.penalty_cycles"                  , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0xAE, 0x01, C_ALL, "itlb.itlb_flush"                                   , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0xB0, 0x01, C_ALL, "offcore_requests.demand_data_rd"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x02, C_ALL, "offcore_requests.demand_code_rd"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x04, C_ALL, "offcore_requests.demand_rfo"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x08, C_ALL, "offcore_requests.all_data_rd"                      , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0xB1, 0x01, C_ALL, "uops_executed.thread"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C_ALL, "uops_executed.stall_cycles"                        , 0x1, ATTR_INV , 0x0 }, \
+{ 0xB1, 0x01, C_ALL, "uops_executed.cycles_ge_1_uop_exec"                , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C_ALL, "uops_executed.cycles_ge_2_uops_exec"               , 0x2, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C_ALL, "uops_executed.cycles_ge_3_uops_exec"               , 0x3, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C_ALL, "uops_executed.cycles_ge_4_uops_exec"               , 0x4, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core_cycles_none"                    , 0x0, ATTR_INV , 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core_cycles_ge_1"                    , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core_cycles_ge_2"                    , 0x2, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core_cycles_ge_3"                    , 0x3, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core_cycles_ge_4"                    , 0x4, ATTR_NONE, 0x0 }, \
+ \
+{ 0xB2, 0x01, C_ALL, "offcore_requests_buffer.sq_full"                   , 0x0, ATTR_NONE, 0x0 }, \
+ \
+/* \
+ * See Section "Off-core Response Performance Monitoring" \
+ * \
+ * Though these two off_core events support all counters, only 1 of \
+ * them can be used at any given time. This is due to the extra MSR \
+ * programming required. \
+ */ \
+/* { 0xB7, 0x01, C_ALL, "offcore_response_0"                                , 0x0, ATTR_NONE, OFFCORE_RSP_0 }, omit events requiring MSR programming */ \
+/* { 0xBB, 0x01, C_ALL, "offcore_response_1"                                , 0x0, ATTR_NONE, OFFCORE_RSP_1 }, omit events requiring MSR programming */ \
+ \
+{ 0xBC, 0x11, C_ALL, "page_walker_loads.dtlb_l1"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBC, 0x21, C_ALL, "page_walker_loads.itlb_l1"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBC, 0x12, C_ALL, "page_walker_loads.dtlb_l2"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBC, 0x22, C_ALL, "page_walker_loads.itlb_l2"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBC, 0x14, C_ALL, "page_walker_loads.dtlb_l3"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBC, 0x24, C_ALL, "page_walker_loads.itlb_l3"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBC, 0x18, C_ALL, "page_walker_loads.dtlb_memory"                     , 0x0, ATTR_NONE, 0x0 }, \
+/* itlb_memory is not in the Intel SDM or spreadsheet for Broadwell;  "cputrack -h" does have it though */ \
+{ 0xBC, 0x28, C_ALL, "page_walker_loads.itlb_memory"                     , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0xBD, 0x01, C_ALL, "tlb_flush.dtlb_thread"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBD, 0x20, C_ALL, "tlb_flush.stlb_any"                                , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0xC0, 0x00, C_ALL, "inst_retired.any_p"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC0, 0x02, C_ALL, "inst_retired.x87"                                  , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0xC1, 0x08, C_ALL, "other_assists.avx_to_sse"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC1, 0x10, C_ALL, "other_assists.sse_to_avx"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC1, 0x40, C_ALL, "other_assists.any_wb_assist"                       , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0xC2, 0x01, C_ALL, "uops_retired.all"                                  , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC2, 0x01, C_ALL, "uops_retired.stall_cycles"                         , 0x1, ATTR_INV , 0x0 }, \
+{ 0xC2, 0x01, C_ALL, "uops_retired.total_cycles"                         , 0xA, ATTR_INV , 0x0 }, \
+{ 0xC2, 0x01, C_ALL, "uops_retired.core_stall_cycles"                    , 0x1, (ATTR_INV | ATTR_ANY), 0x0 }, \
+{ 0xC2, 0x02, C_ALL, "uops_retired.retire_slots"                         , 0x0, ATTR_PEBS, 0x0 }, \
+ \
+{ 0xC3, 0x01, C_ALL, "machine_clears.cycles"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x01, C_ALL, "machine_clears.count"                              , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0xC3, 0x02, C_ALL, "machine_clears.memory_ordering"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x04, C_ALL, "machine_clears.smc"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x20, C_ALL, "machine_clears.maskmov"                            , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0xC4, 0x01, C_ALL, "br_inst_retired.conditional"                       , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC4, 0x02, C_ALL, "br_inst_retired.near_call"                         , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC4, 0x08, C_ALL, "br_inst_retired.near_return"                       , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC4, 0x10, C_ALL, "br_inst_retired.not_taken"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x20, C_ALL, "br_inst_retired.near_taken"                        , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC4, 0x40, C_ALL, "br_inst_retired.far_branch"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x02, C_ALL, "br_inst_retired.near_call_r3"                      , 0x0, ATTR_PEBS, 0x0 }, \
+ \
+{ 0xC5, 0x01, C_ALL, "br_misp_retired.conditional"                       , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC5, 0x20, C_ALL, "br_misp_retired.near_taken"                        , 0x0, ATTR_PEBS, 0x0 }, \
+ \
+{ 0xC7, 0x01, C_ALL, "fp_arith_inst_retired.scalar_double"               , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC7, 0x02, C_ALL, "fp_arith_inst_retired.scalar_single"               , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC7, 0x03, C_ALL, "fp_arith_inst_retired.scalar"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC7, 0x04, C_ALL, "fp_arith_inst_retired.128b_packed_double"          , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC7, 0x08, C_ALL, "fp_arith_inst_retired.128b_packed_single"          , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC7, 0x10, C_ALL, "fp_arith_inst_retired.256b_packed_double"          , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC7, 0x15, C_ALL, "fp_arith_inst_retired.double"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC7, 0x20, C_ALL, "fp_arith_inst_retired.256b_packed_single"          , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC7, 0x2A, C_ALL, "fp_arith_inst_retired.single"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC7, 0x3C, C_ALL, "fp_arith_inst_retired.packed"                      , 0x0, ATTR_PEBS, 0x0 }, \
+ \
+{ 0xC8, 0x01, C_ALL, "hle_retired.start"                                 , 0x0, ATTR_TSX , 0x0 }, \
+{ 0xC8, 0x02, C_ALL, "hle_retired.commit"                                , 0x0, ATTR_TSX , 0x0 }, \
+{ 0xC8, 0x04, C_ALL, "hle_retired.aborted"                               , 0x0, ATTR_PEBS | ATTR_TSX, 0x0 }, \
+{ 0xC8, 0x08, C_ALL, "hle_retired.aborted_misc1"                         , 0x0, ATTR_TSX , 0x0 }, \
+{ 0xC8, 0x10, C_ALL, "hle_retired.aborted_misc2"                         , 0x0, ATTR_TSX , 0x0 }, \
+{ 0xC8, 0x20, C_ALL, "hle_retired.aborted_misc3"                         , 0x0, ATTR_TSX , 0x0 }, \
+{ 0xC8, 0x40, C_ALL, "hle_retired.aborted_misc4"                         , 0x0, ATTR_TSX , 0x0 }, \
+{ 0xC8, 0x80, C_ALL, "hle_retired.aborted_misc5"                         , 0x0, ATTR_TSX , 0x0 }, \
+ \
+{ 0xC9, 0x01, C_ALL, "rtm_retired.start"                                 , 0x0, ATTR_TSX , 0x0 }, \
+{ 0xC9, 0x02, C_ALL, "rtm_retired.commit"                                , 0x0, ATTR_TSX , 0x0 }, \
+{ 0xC9, 0x04, C_ALL, "rtm_retired.aborted"                               , 0x0, ATTR_PEBS | ATTR_TSX, 0x0 }, \
+{ 0xC9, 0x08, C_ALL, "rtm_retired.aborted_misc1"                         , 0x0, ATTR_TSX , 0x0 }, \
+{ 0xC9, 0x10, C_ALL, "rtm_retired.aborted_misc2"                         , 0x0, ATTR_TSX , 0x0 }, \
+{ 0xC9, 0x20, C_ALL, "rtm_retired.aborted_misc3"                         , 0x0, ATTR_TSX , 0x0 }, \
+{ 0xC9, 0x40, C_ALL, "rtm_retired.aborted_misc4"                         , 0x0, ATTR_TSX , 0x0 }, \
+{ 0xC9, 0x80, C_ALL, "rtm_retired.aborted_misc5"                         , 0x0, ATTR_TSX , 0x0 }, \
+ \
+{ 0xCA, 0x02, C_ALL, "fp_assist.x87_output"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x04, C_ALL, "fp_assist.x87_input"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x08, C_ALL, "fp_assist.simd_output"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x10, C_ALL, "fp_assist.simd_input"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCA, 0x1E, C_ALL, "fp_assist.any"                                     , 0x1, ATTR_NONE, 0x0 }, \
+ \
+{ 0xCC, 0x20, C_ALL, "rob_misc_events.lbr_inserts"                       , 0x0, ATTR_NONE, 0x0 }, \
+ \
+/* See Section "MSR_PEBS_LD_LAT_THRESHOLD" */ \
+/* { 0xCD, 0x01, C(3) , "mem_trans_retired.load_latency"                    , 0x0, ATTR_PEBS_ONLY_LD_LAT, PEBS_LD_LAT_THRESHOLD }, omit events requiring MSR programming */ \
+ \
+/* \
+ * Event 0xD0 must be combined with umasks 0x1(loads) or 0x2(stores) \
+ */ \
+{ 0xD0, 0x11, C_ALL, "mem_uops_retired.stlb_miss_loads"                  , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x12, C_ALL, "mem_uops_retired.stlb_miss_stores"                 , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x21, C_ALL, "mem_uops_retired.lock_loads"                       , 0x0, ATTR_PEBS, 0x0 }, \
+/* Private event, not public by Intel */ \
+{ 0xD0, 0x22, C_ALL, "mem_uops_retired.lock_stores"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x41, C_ALL, "mem_uops_retired.split_loads"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x42, C_ALL, "mem_uops_retired.split_stores"                     , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x81, C_ALL, "mem_uops_retired.all_loads"                        , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x82, C_ALL, "mem_uops_retired.all_stores"                       , 0x0, ATTR_PEBS, 0x0 }, \
+ \
+{ 0xD1, 0x01, C_ALL, "mem_load_uops_retired.l1_hit"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x02, C_ALL, "mem_load_uops_retired.l2_hit"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x04, C_ALL, "mem_load_uops_retired.l3_hit"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x08, C_ALL, "mem_load_uops_retired.l1_miss"                     , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x10, C_ALL, "mem_load_uops_retired.l2_miss"                     , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x20, C_ALL, "mem_load_uops_retired.l3_miss"                     , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x40, C_ALL, "mem_load_uops_retired.hit_lfb"                     , 0x0, ATTR_PEBS, 0x0 }, \
+ \
+{ 0xD2, 0x01, C_ALL, "mem_load_uops_l3_hit_retired.xsnp_miss"            , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD2, 0x02, C_ALL, "mem_load_uops_l3_hit_retired.xsnp_hit"             , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD2, 0x04, C_ALL, "mem_load_uops_l3_hit_retired.xsnp_hitm"            , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD2, 0x08, C_ALL, "mem_load_uops_l3_hit_retired.xsnp_none"            , 0x0, ATTR_PEBS, 0x0 }, \
+ \
+{ 0xD3, 0x01, C_ALL, "mem_load_uops_l3_miss_retired.local_dram"          , 0x0, ATTR_PEBS, 0x0 }, \
+ \
+/* The mem_load_l4_miss_retired events are not in "cputrack -h" output nor in the Intel spreadsheet. */ \
+/* { 0xD5, 0x01, C_ALL, "mem_load_l4_miss_retired.local_hit"                , 0x0, ATTR_NONE, 0x0 }, */ \
+/* { 0xD5, 0x04, C_ALL, "mem_load_l4_miss_retired.local_miss"               , 0x0, ATTR_NONE, 0x0 }, */ \
+ \
+{ 0xE6, 0x1F, C_ALL, "baclears.any"                                      , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0xF0, 0x01, C_ALL, "l2_trans.demand_data_rd"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x02, C_ALL, "l2_trans.rfo"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x04, C_ALL, "l2_trans.code_rd"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x08, C_ALL, "l2_trans.all_pf"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x10, C_ALL, "l2_trans.l1d_wb"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x20, C_ALL, "l2_trans.l2_fill"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x40, C_ALL, "l2_trans.l2_wb"                                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x80, C_ALL, "l2_trans.all_requests"                             , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0xF1, 0x01, C_ALL, "l2_lines_in.i"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x02, C_ALL, "l2_lines_in.s"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x04, C_ALL, "l2_lines_in.e"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x07, C_ALL, "l2_lines_in.all"                                   , 0x0, ATTR_NONE, 0x0 }, \
+ \
+{ 0xF2, 0x05, C_ALL, "l2_lines_out.demand_clean"                         , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+
+/* Intel Skylake Processor */
+/*
+ * This table is essentially taken from:
+ *   https://grok.cz.oracle.com/source/xref/on12-clone/usr/src/uts/intel/pcbe/skl_pcbe_tbl.c
+ * Also:
+ *   https://grok.cz.oracle.com/source/xref/on12-clone/usr/src/uts/intel/pcbe/fam6_pcbe.h
+ * { 0xc0, 0x00, C_ALL, "inst_retired.any_p" },                \
+ * { 0x3c, 0x01, C_ALL, "cpu_clk_unhalted.ref_p" },    \
+ * { 0x2e, 0x4f, C_ALL, "longest_lat_cache.reference" },       \
+ * { 0x2e, 0x41, C_ALL, "longest_lat_cache.miss" },    \
+ * { 0xc4, 0x00, C_ALL, "br_inst_retired.all_branches" },      \
+ * { 0xc5, 0x00, C_ALL, "br_misp_retired.all_branches" }
+ * And:
+ * https://grok.cz.oracle.com/source/xref/on12-clone/usr/src/uts/intel/pcbe/core_pcbe.c
+ *     { 0x3c, 0x00, C_ALL, "cpu_clk_unhalted.core" },
+ *     { 0x3c, 0x00, C_ALL, "cpu_clk_unhalted.thread_p" },
+ */
+#define EVENTS_FAM6_MOD78 \
+{ 0x03, 0x02, C_ALL, "ld_blocks.store_forward"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x03, 0x08, C_ALL, "ld_blocks.no_sr"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x07, 0x01, C_ALL, "ld_blocks_partial.address_alias"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x01, C_ALL, "dtlb_load_misses.miss_causes_a_walk"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x02, C_ALL, "dtlb_load_misses.walk_completed_4k"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x04, C_ALL, "dtlb_load_misses.walk_completed_2m_4m"             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x08, C_ALL, "dtlb_load_misses.walk_completed_1g"                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x0E, C_ALL, "dtlb_load_misses.walk_completed"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x10, C_ALL, "dtlb_load_misses.walk_pending"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x10, C_ALL, "dtlb_load_misses.walk_active"                      , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x08, 0x20, C_ALL, "dtlb_load_misses.stlb_hit"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0D, 0x01, C_ALL, "int_misc.recovery_cycles"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0D, 0x01, C_ALL, "int_misc.recovery_cycles_any"                      , 0x0, ATTR_ANY, 0x0 }, \
+{ 0x0D, 0x80, C_ALL, "int_misc.clear_resteer_cycles"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x01, C_ALL, "uops_issued.any"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x01, C_ALL, "uops_issued.stall_cycles"                          , 0x1, ATTR_INV, 0x0 }, \
+{ 0x0E, 0x02, C_ALL, "uops_issued.vector_width_mismatch"                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x0E, 0x20, C_ALL, "uops_issued.slow_lea"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x14, 0x01, C_ALL, "arith.divider_active"                              , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x21, C_ALL, "l2_rqsts.demand_data_rd_miss"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x22, C_ALL, "l2_rqsts.rfo_miss"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x24, C_ALL, "l2_rqsts.code_rd_miss"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x27, C_ALL, "l2_rqsts.all_demand_miss"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x38, C_ALL, "l2_rqsts.pf_miss"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x3F, C_ALL, "l2_rqsts.miss"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x41, C_ALL, "l2_rqsts.demand_data_rd_hit"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x42, C_ALL, "l2_rqsts.rfo_hit"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0x44, C_ALL, "l2_rqsts.code_rd_hit"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xD8, C_ALL, "l2_rqsts.pf_hit"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xE1, C_ALL, "l2_rqsts.all_demand_data_rd"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xE2, C_ALL, "l2_rqsts.all_rfo"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xE4, C_ALL, "l2_rqsts.all_code_rd"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xE7, C_ALL, "l2_rqsts.all_demand_references"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xF8, C_ALL, "l2_rqsts.all_pf"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x24, 0xFF, C_ALL, "l2_rqsts.references"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2e, 0x4f, C_ALL, "longest_lat_cache.reference"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x2e, 0x41, C_ALL, "longest_lat_cache.miss"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3c, 0x00, C_ALL, "cpu_clk_unhalted.thread_p"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x00, C_ALL, "cpu_clk_unhalted.thread_p_any"                     , 0x0, ATTR_ANY, 0x0 }, \
+{ 0x3C, 0x00, C_ALL, "cpu_clk_unhalted.ring0_trans"                      , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x3C, 0x01, C_ALL, "cpu_clk_unhalted.ref_p"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x01, C_ALL, "cpu_clk_thread_unhalted.ref_xclk"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x3C, 0x01, C_ALL, "cpu_clk_thread_unhalted.ref_xclk_any"              , 0x0, ATTR_ANY, 0x0 }, \
+{ 0x3C, 0x02, C_ALL, "cpu_clk_thread_unhalted.one_thread_active"         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C_ALL, "l1d_pend_miss.pending"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C_ALL, "l1d_pend_miss.pending_cycles"                      , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x48, 0x01, C_ALL, "l1d_pend_miss.pending_cycles_any"                  , 0x1, ATTR_ANY, 0x0 }, \
+{ 0x48, 0x02, C_ALL, "l1d_pend_miss.fb_full"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x01, C_ALL, "dtlb_store_misses.miss_causes_a_walk"              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x02, C_ALL, "dtlb_store_misses.walk_completed_4k"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x04, C_ALL, "dtlb_store_misses.walk_completed_2m_4m"            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x08, C_ALL, "dtlb_store_misses.walk_completed_1g"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x0E, C_ALL, "dtlb_store_misses.walk_completed"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x10, C_ALL, "dtlb_store_misses.walk_pending"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x10, C_ALL, "dtlb_store_misses.walk_active"                     , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x49, 0x20, C_ALL, "dtlb_store_misses.stlb_hit"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4C, 0x01, C_ALL, "load_hit_pre.sw_pf"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x4F, 0x10, C_ALL, "ept.walk_pending"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x51, 0x01, C_ALL, "l1d.replacement"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x54, 0x01, C_ALL, "tx_mem.abort_conflict"                             , 0x0, ATTR_TSX, 0x0 }, \
+{ 0x54, 0x02, C_ALL, "tx_mem.abort_capacity"                             , 0x0, ATTR_TSX, 0x0 }, \
+{ 0x54, 0x04, C_ALL, "tx_mem.abort_hle_store_to_elided_lock"             , 0x0, ATTR_TSX, 0x0 }, \
+{ 0x54, 0x08, C_ALL, "tx_mem.abort_hle_elision_buffer_not_empty"         , 0x0, ATTR_TSX, 0x0 }, \
+{ 0x54, 0x10, C_ALL, "tx_mem.abort_hle_elision_buffer_mismatch"          , 0x0, ATTR_TSX, 0x0 }, \
+{ 0x54, 0x20, C_ALL, "tx_mem.abort_hle_elision_buffer_unsupported_alignment",   0x0, ATTR_TSX, 0x0 }, \
+{ 0x54, 0x40, C_ALL, "tx_mem.hle_elision_buffer_full"                    , 0x0, ATTR_TSX, 0x0 }, \
+{ 0x5D, 0x01, C_ALL, "tx_exec.misc1"                                     , 0x0, ATTR_TSX, 0x0 }, \
+{ 0x5D, 0x02, C_ALL, "tx_exec.misc2"                                     , 0x0, ATTR_TSX, 0x0 }, \
+{ 0x5D, 0x04, C_ALL, "tx_exec.misc3"                                     , 0x0, ATTR_TSX, 0x0 }, \
+{ 0x5D, 0x08, C_ALL, "tx_exec.misc4"                                     , 0x0, ATTR_TSX, 0x0 }, \
+{ 0x5D, 0x10, C_ALL, "tx_exec.misc5"                                     , 0x0, ATTR_TSX, 0x0 }, \
+{ 0x5E, 0x01, C_ALL, "rs_events.empty_cycles"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x5E, 0x01, C_ALL, "rs_events.empty_end"                               , 0x1, (ATTR_INV | ATTR_EDGE), 0x0 }, \
+{ 0x60, 0x01, C_ALL, "offcore_requests_outstanding.demand_data_rd"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x01, C_ALL, "offcore_requests_outstanding.cycles_with_demand_data_rd", 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x01, C_ALL, "offcore_requests_outstanding.demand_data_rd_ge_6"  , 0x6, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x02, C_ALL, "offcore_requests_outstanding.demand_code_rd"       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x02, C_ALL, "offcore_requests_outstanding.cycles_with_demand_code_rd", 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x04, C_ALL, "offcore_requests_outstanding.demand_rfo"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x04, C_ALL, "offcore_requests_outstanding.cycles_with_demand_rfo",0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x08, C_ALL, "offcore_requests_outstanding.all_data_rd"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x08, C_ALL, "offcore_requests_outstanding.cycles_with_data_rd"  , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x10, C_ALL, "offcore_requests_outstanding.l3_miss_demand_data_rd",0x0, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x10, C_ALL, "offcore_requests_outstanding.cycles_with_l3_miss_demand_data_rd", 0x1, ATTR_NONE, 0x0 }, \
+{ 0x60, 0x10, C_ALL, "offcore_requests_outstanding.l3_miss_demand_data_rd_ge_6",0x6, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x04, C_ALL, "idq.mite_uops"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x04, C_ALL, "idq.mite_cycles"                                   , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x08, C_ALL, "idq.dsb_uops"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x08, C_ALL, "idq.dsb_cycles"                                    , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x10, C_ALL, "idq.ms_dsb_cycles"                                 , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x18, C_ALL, "idq.all_dsb_cycles_4_uops"                         , 0x4, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x18, C_ALL, "idq.all_dsb_cycles_any_uops"                       , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x20, C_ALL, "idq.ms_mite_uops"                                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x24, C_ALL, "idq.all_mite_cycles_4_uops"                        , 0x4, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x24, C_ALL, "idq.all_mite_cycles_any_uops"                      , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x30, C_ALL, "idq.ms_uops"                                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x30, C_ALL, "idq.ms_cycles"                                     , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x79, 0x30, C_ALL, "idq.ms_switches"                                   , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0x80, 0x04, C_ALL, "icache_16b.ifdata_stall"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x83, 0x01, C_ALL, "icache_64b.iftag_hit"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x83, 0x02, C_ALL, "icache_64b.iftag_miss"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x83, 0x04, C_ALL, "icache_64b.iftag_stall"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x01, C_ALL, "itlb_misses.miss_causes_a_walk"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x02, C_ALL, "itlb_misses.walk_completed_4k"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x04, C_ALL, "itlb_misses.walk_completed_2m_4m"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x08, C_ALL, "itlb_misses.walk_completed_1g"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x0E, C_ALL, "itlb_misses.walk_completed"                        , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x10, C_ALL, "itlb_misses.walk_pending"                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x10, C_ALL, "itlb_misses.walk_active"                           , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x85, 0x20, C_ALL, "itlb_misses.stlb_hit"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x87, 0x01, C_ALL, "ild_stall.lcp"                                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.core"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_0_uops_deliv.core"   , 0x4, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_le_1_uop_deliv.core" , 0x3, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_le_2_uop_deliv.core" , 0x2, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_le_3_uop_deliv.core" , 0x1, ATTR_NONE, 0x0 }, \
+{ 0x9C, 0x01, C_ALL, "idq_uops_not_delivered.cycles_fe_was_ok"           , 0x1, ATTR_INV, 0x0 }, \
+{ 0xA1, 0x01, C_ALL, "uops_dispatched_port.port_0"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x02, C_ALL, "uops_dispatched_port.port_1"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x04, C_ALL, "uops_dispatched_port.port_2"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x08, C_ALL, "uops_dispatched_port.port_3"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x10, C_ALL, "uops_dispatched_port.port_4"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x20, C_ALL, "uops_dispatched_port.port_5"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x40, C_ALL, "uops_dispatched_port.port_6"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA1, 0x80, C_ALL, "uops_dispatched_port.port_7"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x01, C_ALL, "resource_stalls.any"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA2, 0x08, C_ALL, "resource_stalls.sb"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x01, C_ALL, "cycle_activity.cycles_l2_miss"                     , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x02, C_ALL, "cycle_activity.cycles_l3_miss"                     , 0x2, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x04, C_ALL, "cycle_activity.stalls_total"                       , 0x4, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x05, C_ALL, "cycle_activity.stalls_l2_miss"                     , 0x5, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x06, C_ALL, "cycle_activity.stalls_l3_miss"                     , 0x6, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x08, C_ALL, "cycle_activity.cycles_l1d_miss"                    , 0x8, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x0C, C_ALL, "cycle_activity.stalls_l1d_miss"                    , 0xC, ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x10, C_ALL, "cycle_activity.cycles_mem_any"                     , 0x10,ATTR_NONE, 0x0 }, \
+{ 0xA3, 0x14, C_ALL, "cycle_activity.stalls_mem_any"                     , 0x14,ATTR_NONE, 0x0 }, \
+{ 0xA6, 0x01, C_ALL, "exe_activity.exe_bound_0_ports"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA6, 0x02, C_ALL, "exe_activity.1_ports_util"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA6, 0x04, C_ALL, "exe_activity.2_ports_util"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA6, 0x08, C_ALL, "exe_activity.3_ports_util"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA6, 0x10, C_ALL, "exe_activity.4_ports_util"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA6, 0x40, C_ALL, "exe_activity.bound_on_stores"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA8, 0x01, C_ALL, "lsd.uops"                                          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xA8, 0x01, C_ALL, "lsd.cycles_active"                                 , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xA8, 0x01, C_ALL, "lsd.cycles_4_uops"                                 , 0x4, ATTR_NONE, 0x0 }, \
+{ 0xAB, 0x02, C_ALL, "dsb2mite_switches.penalty_cycles"                  , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xAE, 0x01, C_ALL, "itlb.itlb_flush"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x01, C_ALL, "offcore_requests.demand_data_rd"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x02, C_ALL, "offcore_requests.demand_code_rd"                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x04, C_ALL, "offcore_requests.demand_rfo"                       , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x08, C_ALL, "offcore_requests.all_data_rd"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x10, C_ALL, "offcore_requests.l3_miss_demand_data_rd"           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB0, 0x80, C_ALL, "offcore_requests.all_requests"                     , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C_ALL, "uops_executed.thread"                              , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C_ALL, "uops_executed.cycles_ge_1_uop_exec"                , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C_ALL, "uops_executed.cycles_ge_2_uops_exec"               , 0x2, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C_ALL, "uops_executed.cycles_ge_3_uops_exec"               , 0x3, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C_ALL, "uops_executed.cycles_ge_4_uops_exec"               , 0x4, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x01, C_ALL, "uops_executed.stall_cycles"                        , 0x1, ATTR_INV, 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core_cycles_none"                    , 0x1, ATTR_INV, 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core_cycles_ge_1"                    , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core_cycles_ge_2"                    , 0x2, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core_cycles_ge_3"                    , 0x3, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x02, C_ALL, "uops_executed.core_cycles_ge_4"                    , 0x4, ATTR_NONE, 0x0 }, \
+{ 0xB1, 0x10, C_ALL, "uops_executed.x87"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xB2, 0x01, C_ALL, "offcore_requests_buffer.sq_full"                   , 0x0, ATTR_NONE, 0x0 }, \
+\
+       /* \
+        * See Section "Off-core Response Performance Monitoring" \
+        * \
+        * Though these two off_core events support all counters, only 1 of \
+        * them can be used at any given time. This is due to the extra MSR \
+        * programming required. \
+        */ \
+/* { 0xB7, 0x01, C_ALL, "offcore_response_0"                             , 0x0, ATTR_NONE, OFFCORE_RSP_0 }, omit events requiring MSR programming */ \
+/* { 0xBB, 0x01, C_ALL, "offcore_response_1"                             , 0x0, ATTR_NONE, OFFCORE_RSP_1 }, omit events requiring MSR programming */ \
+{ 0xBD, 0x01, C_ALL, "tlb_flush.dtlb_thread"                             , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xBD, 0x20, C_ALL, "tlb_flush.stlb_any"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc0, 0x00, C_ALL, "inst_retired.any_p"                                , 0x0, ATTR_NONE, 0x0 }, \
+/* { 0xC0, 0x1, C(1), "inst_retired.prec_dist"                              , 0x0, ATTR_PEBS_ONLY, 0x0 }, omit PEBS-only events */ \
+/* { 0xC0, 0x1, (C(0) | C(2) | C(3)), "inst_retired.total_cycles_ps"        , 0x0A, (ATTR_PEBS_ONLY | ATTR_INV), 0x0 }, omit PEBS-only events */ \
+{ 0xC1, 0x3F, C_ALL, "other_assists.any"                                 , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC2, 0x01, C_ALL, "uops_retired.stall_cycles"                         , 0x1, ATTR_INV, 0x0 }, \
+{ 0xC2, 0x01, C_ALL, "uops_retired.total_cycles"                         , 0x0A, ATTR_INV, 0x0 }, \
+{ 0xC2, 0x02, C_ALL, "uops_retired.retire_slots"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x01, C_ALL, "machine_clears.count"                              , 0x1, ATTR_EDGE, 0x0 }, \
+{ 0xC3, 0x02, C_ALL, "machine_clears.memory_ordering"                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC3, 0x04, C_ALL, "machine_clears.smc"                                , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xc4, 0x00, C_ALL, "br_inst_retired.all_branches"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x01, C_ALL, "br_inst_retired.conditional"                       , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC4, 0x02, C_ALL, "br_inst_retired.near_call"                         , 0x0, ATTR_PEBS, 0x0 }, \
+/* { 0xC4, 0x04, C_ALL, "br_inst_retired.all_branches_pebs"                 , 0x0, ATTR_PEBS_ONLY, 0x0 }, omit PEBS-only events */ \
+{ 0xC4, 0x08, C_ALL, "br_inst_retired.near_return"                       , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC4, 0x10, C_ALL, "br_inst_retired.not_taken"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC4, 0x20, C_ALL, "br_inst_retired.near_taken"                        , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC4, 0x40, C_ALL, "br_inst_retired.far_branch"                        , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xc5, 0x00, C_ALL, "br_misp_retired.all_branches"                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC5, 0x01, C_ALL, "br_misp_retired.conditional"                       , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xC5, 0x02, C_ALL, "br_misp_retired.near_call"                         , 0x0, ATTR_PEBS, 0x0 }, \
+/* { 0xC5, 0x04, C_ALL, "br_misp_retired.all_branches_pebs"                 , 0x0, ATTR_PEBS_ONLY, 0x0 }, omit PEBS-only events */ \
+{ 0xC5, 0x20, C_ALL, "br_misp_retired.near_taken"                        , 0x0, ATTR_PEBS, 0x0 }, \
+/* { 0xC6, 0x01, C_ALL, "frontend_retired"                                  , 0x0, ATTR_PEBS, MSR_PEBS_FRONTEND}, omit events requiring MSR programming */ \
+{ 0xC7, 0x01, C_ALL, "fp_arith_inst_retired.scalar_double"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x02, C_ALL, "fp_arith_inst_retired.scalar_single"               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x04, C_ALL, "fp_arith_inst_retired.128b_packed_double"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x08, C_ALL, "fp_arith_inst_retired.128b_packed_single"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x10, C_ALL, "fp_arith_inst_retired.256b_packed_double"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC7, 0x20, C_ALL, "fp_arith_inst_retired.256b_packed_single"          , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xC8, 0x01, C_ALL, "hle_retired.start"                                 , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xC8, 0x02, C_ALL, "hle_retired.commit"                                , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xC8, 0x04, C_ALL, "hle_retired.aborted"                               , 0x0, ATTR_PEBS | ATTR_TSX, 0x0 }, \
+{ 0xC8, 0x08, C_ALL, "hle_retired.aborted_mem"                           , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xC8, 0x10, C_ALL, "hle_retired.aborted_timer"                         , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xC8, 0x20, C_ALL, "hle_retired.aborted_unfriendly"                    , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xC8, 0x40, C_ALL, "hle_retired.aborted_memtype"                       , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xC8, 0x80, C_ALL, "hle_retired.aborted_events"                        , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xC9, 0x01, C_ALL, "rtm_retired.start"                                 , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xC9, 0x02, C_ALL, "rtm_retired.commit"                                , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xC9, 0x04, C_ALL, "rtm_retired.aborted"                               , 0x0, ATTR_PEBS | ATTR_TSX, 0x0 }, \
+{ 0xC9, 0x08, C_ALL, "rtm_retired.aborted_mem"                           , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xC9, 0x10, C_ALL, "rtm_retired.aborted_timer"                         , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xC9, 0x20, C_ALL, "rtm_retired.aborted_unfriendly"                    , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xC9, 0x40, C_ALL, "rtm_retired.aborted_memtype"                       , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xC9, 0x80, C_ALL, "rtm_retired.aborted_events"                        , 0x0, ATTR_TSX, 0x0 }, \
+{ 0xCA, 0x1E, C_ALL, "fp_assist.any"                                     , 0x1, ATTR_NONE, 0x0 }, \
+{ 0xCB, 0x01, C_ALL, "hw_interrupts.received"                            , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xCC, 0x20, C_ALL, "rob_misc_events.lbr_inserts"                       , 0x0, ATTR_NONE, 0x0 }, \
+/* { 0xCD, 0x01, C_ALL, "mem_trans_retired.load_latency"                    , 0x0, ATTR_PEBS_ONLY_LD_LAT, PEBS_LD_LAT_THRESHOLD }, omit events requiring MSR programming */ \
+{ 0xD0, 0x11, C_ALL, "mem_inst_retired.stlb_miss_loads"                 , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x12, C_ALL, "mem_inst_retired.stlb_miss_stores"                 , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x21, C_ALL, "mem_inst_retired.lock_loads"                       , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x41, C_ALL, "mem_inst_retired.split_loads"                      , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x42, C_ALL, "mem_inst_retired.split_stores"                     , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x81, C_ALL, "mem_inst_retired.all_loads"                        , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD0, 0x82, C_ALL, "mem_inst_retired.all_stores"                       , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x01, C_ALL, "mem_load_retired.l1_hit"                           , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x02, C_ALL, "mem_load_retired.l2_hit"                           , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x04, C_ALL, "mem_load_retired.l3_hit"                           , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x08, C_ALL, "mem_load_retired.l1_miss"                          , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x10, C_ALL, "mem_load_retired.l2_miss"                          , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x20, C_ALL, "mem_load_retired.l3_miss"                          , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD1, 0x40, C_ALL, "mem_load_retired.fb_hit"                           , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD2, 0x01, C_ALL, "mem_load_l3_hit_retired.xsnp_miss"                 , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD2, 0x02, C_ALL, "mem_load_l3_hit_retired.xsnp_hit"                  , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD2, 0x04, C_ALL, "mem_load_l3_hit_retired.xsnp_hitm"                 , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD2, 0x08, C_ALL, "mem_load_l3_hit_retired.xsnp_none"                 , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xD4, 0x04, C_ALL, "mem_load_misc_retired.uc"                          , 0x0, ATTR_PEBS, 0x0 }, \
+{ 0xE6, 0x01, C_ALL, "baclears.any"                                      , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF0, 0x40, C_ALL, "l2_trans.l2_wb"                                    , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF1, 0x1F, C_ALL, "l2_lines_in.all"                                   , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x01, C_ALL, "l2_lines_out.silent"                               , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x02, C_ALL, "l2_lines_out.non_silent"                           , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF2, 0x04, C_ALL, "l2_lines_out.useless_hwpf"                         , 0x0, ATTR_NONE, 0x0 }, \
+{ 0xF4, 0x10, C_ALL, "sq_misc.split_lock"                                , 0x0, ATTR_NONE, 0x0 }, \
+/* end of #define */
+
+#define NT_END {0, 0, 0, NULL, 0x0, ATTR_NONE, 0x0 } /* end-of-table */
+
+static const struct events_table_t *events_table = NULL;
+
+const struct events_table_t events_fam6_mod23[] = {
+  ARCH_EVENTS
+  EVENTS_FAM6_MOD23
+  NT_END
+};
+
+const struct events_table_t events_fam6_mod28[] = {
+  ARCH_EVENTS
+  EVENTS_FAM6_MOD28
+  NT_END
+};
+
+const struct events_table_t events_fam6_mod26[] = {
+  ARCH_EVENTS
+  EVENTS_FAM6_MOD26
+  NT_END
+};
+
+const struct events_table_t events_fam6_mod46[] = {
+  ARCH_EVENTS
+  EVENTS_FAM6_MOD26
+  EVENTS_FAM6_MOD46_ONLY
+  NT_END
+};
+
+const struct events_table_t events_fam6_mod37[] = {
+  ARCH_EVENTS
+  EVENTS_FAM6_MOD37
+  EVENTS_FAM6_MOD37_ALSO
+  NT_END
+};
+
+const struct events_table_t events_fam6_mod47[] = {
+  ARCH_EVENTS
+  EVENTS_FAM6_MOD37
+  NT_END
+};
+
+const struct events_table_t events_fam6_mod42[] = {
+  ARCH_EVENTS
+  EVENTS_FAM6_MOD42
+  EVENTS_FAM6_MOD42_ONLY
+  NT_END
+};
+
+const struct events_table_t events_fam6_mod45[] = {
+  ARCH_EVENTS
+  EVENTS_FAM6_MOD42
+  EVENTS_FAM6_MOD45_ONLY
+  NT_END
+};
+
+const struct events_table_t events_fam6_mod58[] = {
+  ARCH_EVENTS
+  EVENTS_FAM6_MOD58
+  NT_END
+};
+
+const struct events_table_t events_fam6_mod62[] = {
+  ARCH_EVENTS
+  EVENTS_FAM6_MOD58
+  EVENTS_FAM6_MOD62_ONLY
+  NT_END
+};
+
+const struct events_table_t events_fam6_mod60[] = {
+  ARCH_EVENTS
+  EVENTS_FAM6_MOD60
+  NT_END
+};
+
+const struct events_table_t events_fam6_mod61[] = {
+  ARCH_EVENTS
+  EVENTS_FAM6_MOD61
+  NT_END
+};
+
+const struct events_table_t events_fam6_mod78[] = {
+  ARCH_EVENTS
+  EVENTS_FAM6_MOD78
+  NT_END
+};
+
+const struct events_table_t events_fam6_unknown[] = {
+  ARCH_EVENTS
+  NT_END
+};
+
+const struct events_table_t events_fam_arm[] = {
+//     ARCH_EVENTS
+//    *eventnum = pevent->eventselect;
+//    *eventnum |= (pevent->unitmask << PERFCTR_UMASK_SHIFT);
+//    *eventnum |= (pevent->attrs << 16);
+//    *eventnum |= (pevent->cmask << 24);
+// eventselect, unitmask, supported_counters, name, cmask, attrs, msr_offset
+
+// Hardware event
+#define HWE(nm, id)     { id, 0, C_ALL, nm, PERF_TYPE_HARDWARE, 0, 0 },
+  HWE("branch-instructions",    PERF_COUNT_HW_BRANCH_INSTRUCTIONS)
+  HWE("branch-misses",          PERF_COUNT_HW_BRANCH_MISSES)
+  HWE("bus-cycles",             PERF_COUNT_HW_BUS_CYCLES)
+  HWE("cache-misses",           PERF_COUNT_HW_CACHE_MISSES)
+  HWE("cache-references",       PERF_COUNT_HW_CACHE_REFERENCES)
+  HWE("cycles",                 PERF_COUNT_HW_CPU_CYCLES)
+  HWE("instructions",           PERF_COUNT_HW_INSTRUCTIONS)
+  HWE("ref-cycles",             PERF_COUNT_HW_REF_CPU_CYCLES)
+  HWE("stalled-cycles-backend", PERF_COUNT_HW_STALLED_CYCLES_BACKEND)
+  HWE("stalled-cycles-frontend", PERF_COUNT_HW_STALLED_CYCLES_FRONTEND)
+
+// Software event
+#define SWE(nm, id)     { id, 0, C_ALL, nm, PERF_TYPE_SOFTWARE, 0, 0 },
+  SWE("alignment-faults",       PERF_COUNT_SW_ALIGNMENT_FAULTS)
+  SWE("context-switches",       PERF_COUNT_SW_CONTEXT_SWITCHES)
+  SWE("cpu-clock",              PERF_COUNT_SW_CPU_CLOCK)
+  SWE("cpu-migrations",         PERF_COUNT_SW_CPU_MIGRATIONS)
+  SWE("emulation-faults",       PERF_COUNT_SW_EMULATION_FAULTS)
+  SWE("major-faults",           PERF_COUNT_SW_PAGE_FAULTS_MAJ)
+  SWE("minor-faults",           PERF_COUNT_SW_PAGE_FAULTS_MIN)
+  SWE("page-faults",            PERF_COUNT_SW_PAGE_FAULTS)
+  SWE("task-clock",             PERF_COUNT_SW_TASK_CLOCK)
+
+// Hardware cache event
+#define HWCE(nm, id, op, res)   { id | (op << 8) | (res << 16), 0, C_ALL, nm, PERF_TYPE_HW_CACHE, 0, 0 },
+  HWCE("L1-dcache-load-misses", PERF_COUNT_HW_CACHE_L1D,  PERF_COUNT_HW_CACHE_OP_READ,  PERF_COUNT_HW_CACHE_RESULT_MISS)
+  HWCE("L1-dcache-loads",       PERF_COUNT_HW_CACHE_L1D,  PERF_COUNT_HW_CACHE_OP_READ,  PERF_COUNT_HW_CACHE_RESULT_ACCESS)
+  HWCE("L1-dcache-store-misses",PERF_COUNT_HW_CACHE_L1D,  PERF_COUNT_HW_CACHE_RESULT_MISS, PERF_COUNT_HW_CACHE_RESULT_ACCESS)
+  HWCE("L1-dcache-stores",      PERF_COUNT_HW_CACHE_L1D,  PERF_COUNT_HW_CACHE_OP_WRITE, PERF_COUNT_HW_CACHE_RESULT_ACCESS)
+  HWCE("L1-icache-load-misses", PERF_COUNT_HW_CACHE_L1I,  PERF_COUNT_HW_CACHE_OP_READ,  PERF_COUNT_HW_CACHE_RESULT_MISS)
+  HWCE("L1-icache-loads",       PERF_COUNT_HW_CACHE_L1I,  PERF_COUNT_HW_CACHE_OP_READ,  PERF_COUNT_HW_CACHE_RESULT_ACCESS)
+//    HWCE("branch-load-misses",)
+//    HWCE("branch-loads",)
+  HWCE("dTLB-load-misses",      PERF_COUNT_HW_CACHE_DTLB, PERF_COUNT_HW_CACHE_OP_READ,  PERF_COUNT_HW_CACHE_RESULT_MISS)
+  HWCE("dTLB-loads",            PERF_COUNT_HW_CACHE_DTLB, PERF_COUNT_HW_CACHE_OP_READ,  PERF_COUNT_HW_CACHE_RESULT_ACCESS)
+  HWCE("iTLB-load-misses",      PERF_COUNT_HW_CACHE_ITLB, PERF_COUNT_HW_CACHE_OP_READ,  PERF_COUNT_HW_CACHE_RESULT_MISS)
+  HWCE("iTLB-loads",            PERF_COUNT_HW_CACHE_ITLB, PERF_COUNT_HW_CACHE_OP_READ,  PERF_COUNT_HW_CACHE_RESULT_ACCESS)
+
+  NT_END
+};
+
+static int
+core_pcbe_init (void)
+{
+  switch (cpuid_getvendor ())
+    {
+    case ARM_CPU_IMP_ARM:
+    case ARM_CPU_IMP_BRCM:
+    case ARM_CPU_IMP_CAVIUM:
+    case ARM_CPU_IMP_APM:
+    case ARM_CPU_IMP_QCOM:
+      snprintf (core_impl_name, sizeof (core_impl_name), "%s", AARCH64_VENDORSTR_ARM);
+      events_table = events_fam_arm;
+      num_gpc = 4;  // MEZ: a real implementation is needed
+      num_ffc = 0;
+      total_pmc = num_gpc + num_ffc;
+      return 0;
+    case X86_VENDOR_Intel:
+      break;
+    default:
+      return -1;
+    }
+
+#if defined(__i386__) || defined(__x86_64)
+  /* No Architectural Performance Monitoring Leaf returned by CPUID */
+  if (get_cpuid_info ()->cpi_maxeax < 0xa)
+    return (-1);
+
+  /* Obtain the Architectural Performance Monitoring Leaf */
+  cpuid_regs_t cp;
+  my_cpuid (0xa, &cp);
+  uint32_t versionid = cp.eax & 0xFF;
+
+  /*
+   * Fixed-Function Counters (FFC)
+   *
+   * All Family 6 Model 15 and Model 23 processors have fixed-function
+   * counters.  These counters were made Architectural with
+   * Family 6 Model 15 Stepping 9.
+   */
+  switch (versionid)
+    {
+    case 0:
+      return -1;
+    case 2:
+      num_ffc = cp.edx & 0x1F;
+      /*
+       * Some processors have an errata (AW34) where
+       * versionid is reported as 2 when actually 1.
+       * In this case, fixed-function counters are
+       * model-specific as in Version 1.
+       */
+      if (num_ffc != 0)
+       break;
+      /* FALLTHROUGH */
+    case 1:
+      num_ffc = 3;
+      versionid = 1;
+      break;
+    default:
+      num_ffc = cp.edx & 0x1F;
+      break;
+    }
+  if (num_ffc >= 64)
+    return (-1);
+  uint64_t known_ffc_num = sizeof (ffc_names) / sizeof (char *) - 1; /* -1 for EOT */
+  if (num_ffc > known_ffc_num)
+    /*
+     * The system seems to have more fixed-function counters than
+     * what this PCBE is able to handle correctly.  Default to the
+     * maximum number of fixed-function counters that this driver
+     * is aware of.
+     */
+    num_ffc = known_ffc_num;
+
+  /*
+   * General Purpose Counters (GPC)
+   */
+  num_gpc = (cp.eax >> 8) & 0xFF;
+  if (num_gpc >= 64)
+    return (-1);
+  total_pmc = num_gpc + num_ffc;
+  if (total_pmc > 64)   /* Too wide for the overflow bitmap */
+    return (-1);
+
+  uint_t cpuid_model = cpuid_getmodel ();
+
+  /* GPC events for Family 6 Models 15 & 23 only */
+  if ((cpuid_getfamily () == 6) &&
+      ((cpuid_model == 15) || (cpuid_model == 23)))
+    (void) snprintf (core_impl_name, IMPL_NAME_LEN, "Core Microarchitecture");
+  else
+    (void) snprintf (core_impl_name, IMPL_NAME_LEN,
+                    "Intel Arch PerfMon v%d on Family %d Model %d",
+                    versionid, cpuid_getfamily (), cpuid_model);
+  /*
+   * Process architectural and non-architectural events using GPC
+   */
+  if (num_gpc > 0)
+    {
+      switch (cpuid_model)
+       {
+       case 15: /* Core 2 */
+       case 23:
+         events_table = events_fam6_mod23;
+         break;
+       case 28: /* Atom */
+         events_table = events_fam6_mod28;
+         break;
+       case 37: /* Westmere */
+       case 44:
+         events_table = events_fam6_mod37;
+         break;
+       case 47:
+         events_table = events_fam6_mod47;
+         break;
+       case 26: /* Nehalem */
+       case 30:
+       case 31:
+         events_table = events_fam6_mod26;
+         break;
+       case 46:
+         events_table = events_fam6_mod46;
+         break;
+       case 42: /* Sandy Bridge */
+         events_table = events_fam6_mod42;
+         break;
+       case 45:
+         events_table = events_fam6_mod45;
+         break;
+       case 58: /* Ivy Bridge */
+         events_table = events_fam6_mod58;
+         break;
+       case 62:
+         events_table = events_fam6_mod62;
+         break;
+       case 60: /* Haswell */
+       case 63:
+       case 69:
+       case 70:
+         events_table = events_fam6_mod60;
+         break;
+       case 61: /* Broadwell */
+       case 71:
+       case 79:
+       case 86:
+         events_table = events_fam6_mod61;
+         break;
+       case 78: /* Skylake */
+       case 85:
+       case 94:
+         events_table = events_fam6_mod78;
+         break;
+       default: /* unknown */
+         events_table = events_fam6_unknown;
+       }
+    }
+  /*
+   * Fixed-function Counters (FFC) are already listed individually in
+   * ffc_names[]
+   */
+#endif
+  return 0;
+}
+
+static uint_t
+core_pcbe_ncounters ()
+{
+  return total_pmc;
+}
+
+static const char *
+core_pcbe_impl_name (void)
+{
+  return core_impl_name;
+}
+
+static const char *
+core_pcbe_cpuref (void)
+{
+#if defined(__aarch64__)
+  return "";
+#elif defined(__i386__) || defined(__x86_64)
+  switch (cpuid_getmodel ())
+    {
+    case 60: /* Haswell */
+    case 63:
+    case 69:
+    case 70:
+      return GTXT ("See Chapter 19 of the \"Intel 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide, Part 2\"\nOrder Number: 253669-047US, June 2013");
+    case 61: /* Broadwell */
+    case 71:
+    case 79:
+    case 86:
+    case 78: /* Skylake */
+    case 85:
+    case 94:
+      return GTXT ("See Chapter 19 of the \"Intel 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide\"");
+    default:
+      return
+      GTXT ("See Chapter 19 of the \"Intel 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide, Part 2\"\nOrder Number: 253669-045US, January 2013");
+    }
+#endif
+}
+
+static int
+core_pcbe_get_events (hwcf_hwc_cb_t *hwc_cb)
+{
+  int count = 0;
+  const struct events_table_t *pevent;
+  for (pevent = events_table; pevent && pevent->name; pevent++)
+    for (uint_t jj = 0; jj < num_gpc; jj++)
+      if (C (jj) & pevent->supported_counters)
+       {
+         hwc_cb (jj, pevent->name);
+         count++;
+       }
+
+  for (int ii = 0; ii < sizeof (ffc_names) / sizeof (*ffc_names) && ffc_names[ii]; ii++)
+    {
+      hwc_cb (ii + num_gpc, ffc_names[ii]);
+      count++;
+    }
+  /* add generic events here */
+  return count;
+}
+
+static int
+core_pcbe_get_eventnum (const char *eventname, uint_t pmc, eventsel_t *eventnum,
+                       eventsel_t *valid_umask, uint_t *pmc_sel)
+{
+  const struct events_table_t* pevent;
+  *valid_umask = 0x0; /* by default, don't allow user umask */
+  *pmc_sel = pmc; /* by default, use the requested pmc */
+
+  /* search non-ffc table */
+  for (pevent = events_table; pevent && pevent->name; pevent++)
+    {
+      if (strcmp (eventname, pevent->name) == 0)
+       {
+         *eventnum = pevent->eventselect;
+         *eventnum |= (pevent->unitmask << PERFCTR_UMASK_SHIFT);
+         *eventnum |= (pevent->attrs << 16);
+         *eventnum |= (pevent->cmask << 24);
+
+         if (pevent->msr_offset)
+           {
+             /*
+              * Should also handle any pevent->msr_offset.
+              * Can check libcpc's usr/src/uts/intel/pcbe/snb_pcbe.h,
+              * function snb_gpc_configure().
+              *
+              * Actually, we should probably error out here
+              * until the appropriate support has been added.
+              * Also, we can comment out events that require
+              * msr_offset so that they aren't even listed.
+              */
+           }
+         if (!pevent->unitmask)
+           *valid_umask = 0xff; /* allow umask if nothing set */
+         return 0;
+       }
+    }
+
+  /* search ffc table */
+  for (int ii = 0; ii < sizeof (ffc_names) / sizeof (*ffc_names) && ffc_names[ii]; ii++)
+    {
+      if (strcmp (eventname, ffc_names[ii]) == 0)
+       {
+         *eventnum = 0;
+         *pmc_sel = ii | PERFCTR_FIXED_MAGIC;
+         return 0;
+       }
+    }
+  *eventnum = (eventsel_t) - 1;
+  return -1;
+}
+
+static hdrv_pcbe_api_t hdrv_pcbe_core_api = {
+  core_pcbe_init,
+  core_pcbe_ncounters,
+  core_pcbe_impl_name,
+  core_pcbe_cpuref,
+  core_pcbe_get_events,
+  core_pcbe_get_eventnum
+};
diff --git a/gprofng/common/cpu_frequency.h b/gprofng/common/cpu_frequency.h
new file mode 100644 (file)
index 0000000..b46b54d
--- /dev/null
@@ -0,0 +1,303 @@
+/* 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        _CPU_FREQUENCY_H
+#define        _CPU_FREQUENCY_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include <alloca.h>
+#include <unistd.h> /* processor_info_t        */
+#include <fcntl.h>
+
+  typedef unsigned char uint8_t;
+
+#define MAXSTRLEN               1024
+  /*
+   * This file provide the api to detect Intel CPU frequency variation features
+   */
+
+#define COL_CPUFREQ_NONE        0x0000
+#define COL_CPUFREQ_SCALING     0x0001
+#define COL_CPUFREQ_TURBO       0x0002
+
+#if defined(__i386__) || defined(__x86_64)
+  // XXXX This is a rough table to estimate frequency increment due to intel turbo boost.
+  // CPU with different stepping and different core number have different turbo increment.
+  //  It is used internally here, and is not implemented on SPARC
+
+  // YLM: one can use cputrack to estimate max turbo frequency
+  // example: for a cpu-bound app that runs for > 10 seconds, count cycles for 10 seconds:
+  //     cputrack -T 10 -v -c cpu_clk_unhalted.thread_p a.out
+
+  static int
+  get_max_turbo_freq (int model)
+  {
+    switch (model)
+      {
+       // Nehalem
+      case 30:// Core i7-870: 2/2/4/5
+       return 2 * 133333;
+      case 26:// Xeon L5520: 1/1/1/2
+       return 2 * 133333;
+      case 46:// Xeon E7540: 2
+       return 2 * 133333;
+       // Westmere
+      case 37:// Core i5-520M: 2/4
+       return 2 * 133333;
+      case 44:// Xeon E5620: 1/1/2/2
+       return 2 * 133333;
+      case 47:// Xeon E7-2820: 1/1/1/2
+       return 1 * 133333;
+       // Sandy Bridge
+      case 42:// Core i5-2500: 1/2/3/4
+       return 3 * 100000;
+       // http://ark.intel.com/products/64584/Intel-Xeon-Processor-E5-2660-20M-Cache-2_20-GHz-8_00-GTs-Intel-QPI
+      case 45:// Xeon E5-2660 GenuineIntel 206D7 family 6 model 45 step 7 clock 2200 MHz
+       return 8 * 100000;
+       // Ivy Bridge
+      case 58:// Core i7-3770: 3/4/5/5
+       return 4 * 100000;
+      case 62:// Xeon E5-2697: 3/3/3/3/3/3/3/4/5/6/7/8
+       return 7 * 100000;
+       // Haswell
+      case 60:
+       return 789000; // empirically we see 3189 MHz - 2400 MHz
+      case 63:
+       return 1280000; // empirically we see 3580 MHz - 2300 MHz for single-threaded
+       //  return  500000;   // empirically we see 2800 MHz - 2300 MHz for large throughput
+       // Broadwell
+       // where are these values listed?
+       // maybe try https://en.wikipedia.org/wiki/Broadwell_%28microarchitecture%29#Server_processors
+      case 61:
+       return 400000;
+      case 71:
+       return 400000;
+      case 79:
+       return 950000; // empirically we see (3550-2600) MHz for single-threaded on x6-2a
+      case 85:
+       return 1600000; // X7: empirically see ~3.7GHz with single thread, baseline is 2.1Ghz  Return 3,700,000-2,100,000
+      case 31: // Nehalem?
+      case 28: // Atom
+      case 69: // Haswell
+      case 70: // Haswell
+      case 78: // Skylake
+      case 94: // Skylake
+      default:
+       return 0;
+      }
+  }
+#endif
+
+  /*
+   * parameter: mode, pointer to a 8bit mode indicator
+   * return: max cpu frequency in MHz
+   */
+  //YXXX Updating this function?  Check similar cut/paste code in:
+  // collctrl.cc::Coll_Ctrl()
+  // collector.c::log_header_write()
+  // cpu_frequency.h::get_cpu_frequency()
+
+  static int
+  get_cpu_frequency (uint8_t *mode)
+  {
+    int ret_freq = 0;
+    if (mode != NULL)
+      *mode = COL_CPUFREQ_NONE;
+    FILE *procf = fopen ("/proc/cpuinfo", "r");
+    if (procf != NULL)
+      {
+       char temp[1024];
+       int cpu = -1;
+#if defined(__i386__) || defined(__x86_64)
+       int model = -1;
+       int family = -1;
+#endif
+       while (fgets (temp, 1024, procf) != NULL)
+         {
+           if (strncmp (temp, "processor", strlen ("processor")) == 0)
+             {
+               char *val = strchr (temp, ':');
+               cpu = val ? atoi (val + 1) : -1;
+             }
+#if defined(__i386__) || defined(__x86_64)
+           else if (strncmp (temp, "model", strlen ("model")) == 0
+                    && strstr (temp, "name") == 0)
+             {
+               char *val = strchr (temp, ':');
+               model = val ? atoi (val + 1) : -1;
+             }
+           else if (strncmp (temp, "cpu family", strlen ("cpu family")) == 0)
+             {
+               char *val = strchr (temp, ':');
+               family = val ? atoi (val + 1) : -1;
+             }
+#endif
+           else if (strncmp (temp, "cpu MHz", strlen ("cpu MHz")) == 0)
+             {
+               char *val = strchr (temp, ':');
+               int mhz = val ? atoi (val + 1) : 0; /* reading it as int is fine */
+               char scaling_freq_file[MAXSTRLEN + 1];
+               snprintf (scaling_freq_file, sizeof (scaling_freq_file),
+                         "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_driver", cpu);
+               int intel_pstate = 0;
+               int no_turbo = 0;
+               if (access (scaling_freq_file, R_OK) == 0)
+                 {
+                   FILE *cpufreqd = fopen (scaling_freq_file, "r");
+                   if (cpufreqd != NULL)
+                     {
+                       if (fgets (temp, 1024, cpufreqd) != NULL
+                           && strncmp (temp, "intel_pstate", sizeof ("intel_pstate") - 1) == 0)
+                         intel_pstate = 1;
+                       fclose (cpufreqd);
+                     }
+                 }
+               snprintf (scaling_freq_file, sizeof (scaling_freq_file),
+                         "/sys/devices/system/cpu/intel_pstate/no_turbo");
+               if (access (scaling_freq_file, R_OK) == 0)
+                 {
+                   FILE *pstatent = fopen (scaling_freq_file, "r");
+                   if (pstatent != NULL)
+                     {
+                       if (fgets (temp, 1024, pstatent) != NULL)
+                         if (strncmp (temp, "1", sizeof ("1") - 1) == 0)
+                           no_turbo = 1;
+                       fclose (pstatent);
+                     }
+                 }
+
+               snprintf (scaling_freq_file, sizeof (scaling_freq_file),
+                         "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor", cpu);
+               int frequency_scaling = 0;
+               int turbo_mode = 0;
+               if (access (scaling_freq_file, R_OK) == 0)
+                 {
+                   FILE *cpufreqf = fopen (scaling_freq_file, "r");
+                   if (cpufreqf != NULL)
+                     {
+                       if (fgets (temp, 1024, cpufreqf) != NULL)
+                         {
+                           int ondemand = 0;
+                           if (strncmp (temp, "ondemand", sizeof ("ondemand") - 1) == 0)
+                             ondemand = 1;
+                           int performance = 0;
+                           if (strncmp (temp, "performance", sizeof ("performance") - 1) == 0)
+                             performance = 1;
+                           int powersave = 0;
+                           if (strncmp (temp, "powersave", sizeof ("powersave") - 1) == 0)
+                             powersave = 1;
+                           if (intel_pstate || ondemand || performance)
+                             {
+                               snprintf (scaling_freq_file, sizeof (scaling_freq_file),
+                                         "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_max_freq", cpu);
+                               if (access (scaling_freq_file, R_OK) == 0)
+                                 {
+                                   FILE * cpufreqf_max;
+                                   if ((cpufreqf_max = fopen (scaling_freq_file, "r")) != NULL)
+                                     {
+                                       if (fgets (temp, 1024, cpufreqf_max) != NULL)
+                                         {
+                                           int tmpmhz = atoi (temp);
+                                           snprintf (scaling_freq_file, sizeof (scaling_freq_file),
+                                                     "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_available_frequencies", cpu);
+                                           if (intel_pstate)
+                                             {
+                                               frequency_scaling = 1;
+                                               turbo_mode = !no_turbo;
+                                               if (powersave)
+                                                 // the system might have been relatively cold
+                                                 // so we might do better with scaling_max_freq
+                                                 mhz = (int) (((double) tmpmhz / 1000.0) + 0.5);
+                                             }
+                                           else if (access (scaling_freq_file, R_OK) == 0)
+                                             {
+                                               FILE * cpufreqf_ava;
+                                               if ((cpufreqf_ava = fopen (scaling_freq_file, "r")) != NULL)
+                                                 {
+                                                   if (fgets (temp, 1024, cpufreqf_ava) != NULL)
+                                                     {
+                                                       if (strchr (temp, ' ') != strrchr (temp, ' ') && ondemand)
+                                                         frequency_scaling = 1;
+                                                       if (tmpmhz > 1000)
+                                                         {
+#if defined(__i386__) || defined(__x86_64)
+                                                           if (family == 6)
+                                                             {
+                                                               // test turbo mode
+                                                               char non_turbo_max_freq[1024];
+                                                               snprintf (non_turbo_max_freq, sizeof (non_turbo_max_freq),
+                                                                         "%d", tmpmhz - 1000);
+                                                               if (strstr (temp, non_turbo_max_freq))
+                                                                 {
+                                                                   turbo_mode = 1;
+                                                                   tmpmhz = (tmpmhz - 1000) + get_max_turbo_freq (model);
+                                                                 }
+                                                             }
+#endif
+                                                         }
+                                                     }
+                                                   fclose (cpufreqf_ava);
+                                                 }
+                                               mhz = (int) (((double) tmpmhz / 1000.0) + 0.5);
+                                             }
+                                         }
+                                       fclose (cpufreqf_max);
+                                     }
+                                 }
+                             }
+                         }
+                       fclose (cpufreqf);
+                     }
+                 }
+               if (mhz > ret_freq)
+                 ret_freq = mhz;
+               if (frequency_scaling && mode != NULL)
+                 *mode |= COL_CPUFREQ_SCALING;
+               if (turbo_mode && mode != NULL)
+                 *mode |= COL_CPUFREQ_TURBO;
+             }
+           else if (strncmp (temp, "Cpu", 3) == 0 && temp[3] != '\0' &&
+                    strncmp (strchr (temp + 1, 'C') ? strchr (temp + 1, 'C') : (temp + 4), "ClkTck", 6) == 0)
+             { // sparc-Linux
+               char *val = strchr (temp, ':');
+               if (val)
+                 {
+                   unsigned long long freq;
+                   sscanf (val + 2, "%llx", &freq);
+                   int mhz = (unsigned int) (((double) freq) / 1000000.0 + 0.5);
+                   if (mhz > ret_freq)
+                     ret_freq = mhz;
+                 }
+             }
+         }
+       fclose (procf);
+      }
+    return ret_freq;
+  }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  /*_CPU_FREQUENCY_H*/
diff --git a/gprofng/common/cpuid.c b/gprofng/common/cpuid.c
new file mode 100644 (file)
index 0000000..211e09a
--- /dev/null
@@ -0,0 +1,203 @@
+/* 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.  */
+
+#if defined(__i386__) || defined(__x86_64)
+#include <cpuid.h>  /* GCC-provided */
+#elif defined(__aarch64__)
+#define ATTRIBUTE_UNUSED __attribute__((unused))
+
+static inline uint_t __attribute_const__
+__get_cpuid (unsigned int op ATTRIBUTE_UNUSED, unsigned int *eax,
+            unsigned int *ebx ATTRIBUTE_UNUSED,
+            unsigned int *ecx ATTRIBUTE_UNUSED, unsigned int *edx ATTRIBUTE_UNUSED)
+{
+  // CPUID bit assignments:
+  // [31:24] IMPLEMENTER (0x50 - ARM_CPU_IMP_APM)
+  // [23:20] VARIANT indicates processor revision (0x2 = Revision 2)
+  // [19:16] Constant (Reads as 0xF)
+  // [15:04] PARTNO indicates part number (0xC23 = Cortex-M3)
+  // [03:00] REVISION indicates patch release (0x0 = Patch 0)
+  //    unsigned long v = 0;
+  //    __asm volatile ("MRS %[result], MPIDR_EL1" : [result] "=r" (v));
+  //    Tprintf(DBG_LT0, "cpuid.c:%d read_cpuid_id() MPIDR_EL1=0x%016lx\n", __LINE__, v);
+  uint_t res = 0;
+  __asm volatile ("MRS %[result], MIDR_EL1" : [result] "=r" (*eax));
+  Tprintf (DBG_LT0, "cpuid.c:%d read_cpuid_id() MIDR_EL1=0x%016x\n", __LINE__, *eax);
+  return res;
+}
+#endif
+
+/*
+ * Various routines to handle identification
+ * and classification of x86 processors.
+ */
+
+#define IS_GLOBAL /* externally visible */
+#define        X86_VENDOR_Intel        0
+#define        X86_VENDORSTR_Intel     "GenuineIntel"
+#define        X86_VENDOR_IntelClone   1
+#define        X86_VENDOR_AMD          2
+#define        X86_VENDORSTR_AMD       "AuthenticAMD"
+
+#define BITX(u, h, l)       (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
+#define CPI_FAMILY_XTD(reg) BITX(reg, 27, 20)
+#define CPI_MODEL_XTD(reg)  BITX(reg, 19, 16)
+#define CPI_TYPE(reg)       BITX(reg, 13, 12)
+#define CPI_FAMILY(reg)     BITX(reg, 11, 8)
+#define CPI_STEP(reg)       BITX(reg, 3, 0)
+#define CPI_MODEL(reg)      BITX(reg, 7, 4)
+#define IS_EXTENDED_MODEL_INTEL(model)  ((model) == 0x6 || (model) >= 0xf)
+
+
+typedef struct
+{
+  unsigned int eax;
+  unsigned int ebx;
+  unsigned int ecx;
+  unsigned int edx;
+} cpuid_regs_t;
+
+typedef struct
+{
+  unsigned int cpi_model;
+  unsigned int cpi_family;
+  unsigned int cpi_vendor;        /* enum of cpi_vendorstr */
+  unsigned int cpi_maxeax;        /* fn 0: %eax */
+  char cpi_vendorstr[13];         /* fn 0: %ebx:%ecx:%edx */
+} cpuid_info_t;
+
+
+#if defined(__i386__) || defined(__x86_64)
+static uint_t
+cpuid_vendorstr_to_vendorcode (char *vendorstr)
+{
+  if (strcmp (vendorstr, X86_VENDORSTR_Intel) == 0)
+    return X86_VENDOR_Intel;
+  else if (strcmp (vendorstr, X86_VENDORSTR_AMD) == 0)
+    return X86_VENDOR_AMD;
+  else
+    return X86_VENDOR_IntelClone;
+}
+
+static int
+my_cpuid (unsigned int op, cpuid_regs_t *regs)
+{
+  regs->eax = regs->ebx = regs->ecx = regs->edx = 0;
+  int ret = __get_cpuid (op, &regs->eax, &regs->ebx, &regs->ecx, &regs->edx);
+  TprintfT (DBG_LT1, "my_cpuid: __get_cpuid(0x%x, 0x%x, 0x%x, 0x%x, 0x%x) returns %d\n",
+           op, regs->eax, regs->ebx, regs->ecx, regs->edx, ret);
+  return ret;
+}
+#endif
+
+static cpuid_info_t *
+get_cpuid_info ()
+{
+  static int cpuid_inited = 0;
+  static cpuid_info_t cpuid_info;
+  cpuid_info_t *cpi = &cpuid_info;
+  if (cpuid_inited)
+    return cpi;
+  cpuid_inited = 1;
+
+#if defined(__aarch64__)
+  // CPUID bit assignments:
+  // [31:24] IMPLEMENTER (0x50 - ARM_CPU_IMP_APM)
+  // [23:20] VARIANT indicates processor revision (0x2 = Revision 2)
+  // [19:16] Constant (Reads as 0xF)
+  // [15:04] PARTNO indicates part number (0xC23 = Cortex-M3)
+  // [03:00] REVISION indicates patch release (0x0 = Patch 0)
+  uint_t reg = 0;
+  __asm volatile ("MRS %[result], MIDR_EL1" : [result] "=r" (reg));
+  cpi->cpi_vendor = reg >> 24;
+  cpi->cpi_model = (reg >> 4) & 0xfff;
+  switch (cpi->cpi_vendor)
+    {
+    case ARM_CPU_IMP_APM:
+    case ARM_CPU_IMP_ARM:
+    case ARM_CPU_IMP_CAVIUM:
+    case ARM_CPU_IMP_BRCM:
+    case ARM_CPU_IMP_QCOM:
+      strncpy (cpi->cpi_vendorstr, AARCH64_VENDORSTR_ARM, sizeof (cpi->cpi_vendorstr));
+      break;
+    default:
+      strncpy (cpi->cpi_vendorstr, "UNKNOWN ARM", sizeof (cpi->cpi_vendorstr));
+      break;
+    }
+  Tprintf (DBG_LT0, "cpuid.c:%d read_cpuid_id() MIDR_EL1==0x%016x cpi_vendor=%d cpi_model=%d\n",
+          __LINE__, (unsigned int) reg, cpi->cpi_vendor, cpi->cpi_model);
+
+#elif defined(__i386__) || defined(__x86_64)
+  cpuid_regs_t regs;
+  my_cpuid (0, &regs);
+  cpi->cpi_maxeax = regs.eax;
+  ((uint32_t *) cpi->cpi_vendorstr)[0] = regs.ebx;
+  ((uint32_t *) cpi->cpi_vendorstr)[1] = regs.edx;
+  ((uint32_t *) cpi->cpi_vendorstr)[2] = regs.ecx;
+  cpi->cpi_vendorstr[12] = 0;
+  cpi->cpi_vendor = cpuid_vendorstr_to_vendorcode (cpi->cpi_vendorstr);
+
+  my_cpuid (1, &regs);
+  cpi->cpi_model = CPI_MODEL (regs.eax);
+  cpi->cpi_family = CPI_FAMILY (regs.eax);
+  if (cpi->cpi_family == 0xf)
+    cpi->cpi_family += CPI_FAMILY_XTD (regs.eax);
+
+  /*
+   * Beware: AMD uses "extended model" iff base *FAMILY* == 0xf.
+   * Intel, and presumably everyone else, uses model == 0xf, as
+   * one would expect (max value means possible overflow).  Sigh.
+   */
+  switch (cpi->cpi_vendor)
+    {
+    case X86_VENDOR_Intel:
+      if (IS_EXTENDED_MODEL_INTEL (cpi->cpi_family))
+       cpi->cpi_model += CPI_MODEL_XTD (regs.eax) << 4;
+      break;
+    case X86_VENDOR_AMD:
+      if (CPI_FAMILY (cpi->cpi_family) == 0xf)
+       cpi->cpi_model += CPI_MODEL_XTD (regs.eax) << 4;
+      break;
+    default:
+      if (cpi->cpi_model == 0xf)
+       cpi->cpi_model += CPI_MODEL_XTD (regs.eax) << 4;
+      break;
+    }
+#endif
+  return cpi;
+}
+
+static inline uint_t
+cpuid_getvendor ()
+{
+  return get_cpuid_info ()->cpi_vendor;
+}
+
+static inline uint_t
+cpuid_getfamily ()
+{
+  return get_cpuid_info ()->cpi_family;
+}
+
+static inline uint_t
+cpuid_getmodel ()
+{
+  return get_cpuid_info ()->cpi_model;
+}
diff --git a/gprofng/common/gp-defs.h b/gprofng/common/gp-defs.h
new file mode 100644 (file)
index 0000000..440bfb1
--- /dev/null
@@ -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.  */
+
+#ifndef _GP_DEFS_H_
+#define _GP_DEFS_H_
+
+/* Define the ARCH and WSIZE predicates */
+/*
+ * The way we define and use predicates is similar to the
+ * standard #assert with one important exception:
+ * if an argument of a predicate is not known the result
+ * is 'false' and we want a compile time error to avoid
+ * silent results from typos like ARCH(INTEL), COMPILER(gnu),
+ * etc.
+ */
+#define ARCH(x)             TOK_A_##x(ARCH)
+#define TOK_A_Aarch64(x)    x##_Aarch64
+#define TOK_A_SPARC(x)      x##_SPARC
+#define TOK_A_Intel(x)      x##_Intel
+
+#define WSIZE(x)            TOK_W_##x(WSIZE)
+#define TOK_W_32(x)         x##_32
+#define TOK_W_64(x)         x##_64
+
+#if defined(sparc) || defined(__sparcv9)
+#define ARCH_SPARC          1
+#elif defined(__i386__) || defined(__x86_64)
+#define ARCH_Intel          1
+#elif defined(__aarch64__)
+#define ARCH_Aarch64        1
+#else
+#error "Undefined platform"
+#endif
+
+#if defined(__sparcv9) || defined(__x86_64) || defined(__aarch64__)
+#define WSIZE_64            1
+#else
+#define WSIZE_32            1
+#endif
+
+#endif
diff --git a/gprofng/common/gp-experiment.h b/gprofng/common/gp-experiment.h
new file mode 100644 (file)
index 0000000..040c2d1
--- /dev/null
@@ -0,0 +1,186 @@
+/* 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 _EXPERIMENT_H
+#define _EXPERIMENT_H
+
+/* version numbers define experiment format */
+#define SUNPERF_VERNUM          12
+#define SUNPERF_VERNUM_MINOR    4
+
+/* backward compatibility down to: */
+#define SUNPERF_VERNUM_LEAST    12
+
+#include "Emsgnum.h" /* for COL_ERROR_*, etc. symbols */
+
+#define SP_REMOTE_PROTOCOL_VERSION "12.4.1"
+
+#define SP_GROUP_HEADER         "#analyzer experiment group"
+
+/* Experiment name macro definitions */
+
+/* for descendant experiments */
+#define DESCENDANT_EXPT_KEY     ".er/_"
+#define IS_DESC_EXPT(exptname)  (strstr(exptname,DESCENDANT_EXPT_KEY) != NULL)
+#define IS_FNDR_EXPT(exptname)  (strstr(exptname,DESCENDANT_EXPT_KEY) == NULL)
+
+/* File name definitions */
+#define SP_ARCHIVES_DIR         "archives"
+#define SP_ARCHIVE_LOG_FILE     "archive.log"
+#define SP_LOG_FILE             "log.xml"
+#define SP_NOTES_FILE           "notes"
+#define SP_IFREQ_FILE           "ifreq"
+#define SP_MAP_FILE             "map.xml"
+#define SP_LABELS_FILE          "labels.xml"
+#define SP_DYNTEXT_FILE         "dyntext"
+#define SP_OVERVIEW_FILE        "overview"
+#define SP_PROFILE_FILE         "profile"
+#define SP_SYNCTRACE_FILE       "synctrace"
+#define SP_IOTRACE_FILE         "iotrace"
+#define SP_OMPTRACE_FILE        "omptrace"
+#define SP_MPVIEW_FILE          "mpview.dat3"
+#define SP_HWCNTR_FILE          "hwcounters"
+#define SP_HEAPTRACE_FILE       "heaptrace"
+#define SP_JCLASSES_FILE        "jclasses"
+#define SP_DYNAMIC_CLASSES      "jdynclasses"
+#define SP_RACETRACE_FILE       "dataraces"
+#define SP_DEADLOCK_FILE        "deadlocks"
+#define SP_FRINFO_FILE          "frameinfo"
+#define SP_WARN_FILE            "warnings.xml"
+
+#define SP_LIBCOLLECTOR_NAME    "libgp-collector.so"
+#define SP_LIBAUDIT_NAME        "libcollect-ng.so"
+
+/* XML tags */
+#define SP_TAG_COLLECTOR        "collector"
+#define SP_TAG_CPU              "cpu"
+#define SP_TAG_DATAPTR          "dataptr"
+#define SP_TAG_EVENT            "event"
+#define SP_TAG_EXPERIMENT       "experiment"
+#define SP_TAG_FIELD            "field"
+#define SP_TAG_PROCESS          "process"
+#define SP_TAG_PROFILE          "profile"
+#define SP_TAG_PROFDATA         "profdata"
+#define SP_TAG_PROFPCKT         "profpckt"
+#define SP_TAG_SETTING          "setting"
+#define SP_TAG_STATE            "state"
+#define SP_TAG_SYSTEM           "system"
+#define SP_TAG_POWERM           "powerm"
+#define SP_TAG_FREQUENCY        "frequency"
+#define SP_TAG_DTRACEFATAL      "dtracefatal"
+
+/* records for log and loadobjects files */
+/* note that these are in alphabetical order */
+#define SP_JCMD_ARCH            "architecture"
+#define SP_JCMD_ARCHIVE         "archive_run"
+#define SP_JCMD_ARGLIST         "arglist"
+#define SP_JCMD_BLKSZ           "blksz"
+#define SP_JCMD_CERROR          "cerror"
+#define SP_JCMD_CLASS_LOAD      "class_load"
+#define SP_JCMD_CLASS_UNLOAD    "class_unload"
+#define SP_JCMD_COLLENV         "collenv"
+#define SP_JCMD_COMMENT         "comment"
+#define SP_JCMD_CPUID           "cpuid"
+#define SP_JCMD_CWARN           "cwarn"
+#define SP_JCMD_CWD             "cwd"
+#define SP_JCMD_CVERSION        "cversion"
+#define SP_JCMD_DATARACE        "datarace"
+#define SP_JCMD_DEADLOCK        "deadlock"
+#define SP_JCMD_DELAYSTART      "delay_start"
+#define SP_JCMD_DESC_START      "desc_start"
+#define SP_JCMD_DESC_STARTED    "desc_started"
+#define SP_JCMD_DVERSION        "dversion"
+#define SP_JCMD_EXEC_START      "exec_start"
+#define SP_JCMD_EXEC_ERROR      "exec_error"
+#define SP_JCMD_EXIT            "exit"
+#define SP_JCMD_EXPT_DURATION   "exp_duration"
+#define SP_JCMD_FAKETIME        "faketime"
+#define SP_JCMD_FN_LOAD         "fn_load"
+#define SP_JCMD_FN_UNLOAD       "fn_unload"
+#define SP_JCMD_FUN_MAP         "fun_map"
+#define SP_JCMD_FUN_UNMAP       "fun_unmap"
+#define SP_JCMD_HEAPTRACE       "heaptrace"
+#define SP_JCMD_HOSTNAME        "hostname"
+#define SP_JCMD_HWC_DEFAULT     "hwc_default"
+#define SP_JCMD_HW_COUNTER      "hwcounter"
+#define SP_JCMD_HW_SIM_CTR      "hwsimctr"
+#define SP_JCMD_IOTRACE         "iotrace"
+#define SP_JCMD_JCM_LOAD        "jcm_load"
+#define SP_JCMD_JCM_UNLOAD      "jcm_unload"
+#define SP_JCMD_JCM_MAP         "jcm_map"
+#define SP_JCMD_JCM_UNMAP       "jcm_unmap"
+#define SP_JCMD_JTHREND         "jthread_end"
+#define SP_JCMD_JTHRSTART       "jthread_start"
+#define SP_JCMD_GCEND           "gc_end"
+#define SP_JCMD_GCSTART         "gc_start"
+#define SP_JCMD_JVERSION        "jversion"
+//#define SP_JCMD_KPROFILE        "kprofile"    /* TBR */
+#define SP_JCMD_LIMIT           "limit"
+#define SP_JCMD_LINETRACE       "linetrace"
+#define SP_JCMD_LO_OPEN         "lo_open"
+#define SP_JCMD_LO_CLOSE        "lo_close"
+#define SP_JCMD_MOD_OPEN        "mod_open"
+#define SP_JCMD_MPIEXP          "MPIexperiment"
+#define SP_JCMD_MPI_NO_TRACE    "MPI_no_trace"
+#define SP_JCMD_MPIOMPVER       "mpi_openmpi_version"
+#define SP_JCMD_MPITRACEVER     "mpi_trace_version"
+#define SP_JCMD_MPIPP           "mpipp"
+#define SP_JCMD_MPIPPERR        "mpipp_err"
+#define SP_JCMD_MPIPPWARN       "mpipp_warn"
+#define SP_JCMD_MPISTATE        "mpistate"
+#define SP_JCMD_MPITRACE        "mpitrace" /* backwards compat only */
+#define SP_JCMD_MPVIEW          "mpview"
+#define SP_JCMD_MSGTRACE        "msgtrace"
+#define SP_JCMD_NOIDLE          "noidle"
+#define SP_JCMD_OMPTRACE        "omptrace"
+#define SP_JCMD_OS              "os"
+#define SP_JCMD_PAGESIZE        "pagesize"
+#define SP_JCMD_PAUSE           "pause"
+#define SP_JCMD_PAUSE_SIG       "pause_signal"
+#define SP_JCMD_PROFILE         "profile"
+#define SP_JCMD_RESUME          "resume"
+#define SP_JCMD_RUN             "run"
+#define SP_JCMD_SAMPLE          "sample"
+#define SP_JCMD_SAMPLE_PERIOD   "sample_period"
+#define SP_JCMD_SAMPLE_SIG      "sample_signal"
+#define SP_JCMD_SEGMENT_MAP     "seg_map"
+#define SP_JCMD_SEGMENT_UNMAP   "seg_unmap"
+#define SP_JCMD_SRCHPATH        "search_path"
+#define SP_JCMD_STACKBASE       "stackbase"
+#define SP_JCMD_SUNPERF         "sunperf"
+#define SP_JCMD_SYNCTRACE       "synctrace"
+#define SP_JCMD_TERMINATE       "terminate"
+#define SP_JCMD_THREAD_PAUSE    "thread_pause"
+#define SP_JCMD_THREAD_RESUME   "thread_resume"
+#define SP_JCMD_USERNAME        "username"
+#define SP_JCMD_VERSION         "version"
+#define SP_JCMD_WSIZE           "wsize"
+
+/* strings naming memory-segments */
+#define SP_MAP_ANON             "Anon"
+#define SP_MAP_HEAP             "Heap"
+#define SP_MAP_STACK            "Stack"
+#define SP_MAP_SHMEM            "SHMid"
+#define SP_MAP_UNRESOLVABLE     "Unresolvable"
+
+#define SP_UNKNOWN_NAME         "(unknown)"
+
+#define MAX_STACKDEPTH 2048
+#endif /* _EXPERIMENT_H */
diff --git a/gprofng/common/gp-time.h b/gprofng/common/gp-time.h
new file mode 100644 (file)
index 0000000..7755370
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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 _GP_TIME_H_
+#define _GP_TIME_H_
+
+#include <sys/time.h>
+
+typedef long long hrtime_t;
+typedef struct timespec timestruc_t;
+
+#define ITIMER_REALPROF ITIMER_PROF
+#define NANOSEC     1000000000
+#define MICROSEC    1000000
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+  hrtime_t gethrtime (void);
+  hrtime_t gethrvtime (void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/gprofng/common/hwc_cpus.h b/gprofng/common/hwc_cpus.h
new file mode 100644 (file)
index 0000000..ff7b303
--- /dev/null
@@ -0,0 +1,198 @@
+/* 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: cpu types */
+
+#ifndef __HWC_CPUS_H
+#define __HWC_CPUS_H
+
+#define MAX_PICS    20 /* Max # of HW ctrs that can be enabled simultaneously */
+
+  /* type for specifying CPU register number */
+  typedef int regno_t;
+#define REGNO_ANY       ((regno_t)-1)
+#define REGNO_INVALID   ((regno_t)-2)
+
+  /* --- Utilities for use with regno_t and reg_list[] --- */
+#define REG_LIST_IS_EMPTY(reg_list) (!(reg_list) || (reg_list)[0] == REGNO_ANY)
+#define REG_LIST_EOL(regno)         ((regno)==REGNO_ANY)
+#define REG_LIST_SINGLE_VALID_ENTRY(reg_list) \
+  (((reg_list) && (reg_list)[1] == REGNO_ANY && \
+      (reg_list)[0] != REGNO_ANY ) ? (reg_list)[0] : REGNO_ANY)
+
+  /* enum for specifying unknown or uninitialized CPU */
+  enum
+  {
+    CPUVER_GENERIC = 0,
+    CPUVER_UNDEFINED = -1
+  };
+
+  // Note: changing an values below may make older HWC experiments unreadable.
+  // --- Sun/Oracle SPARC ---
+#define CPC_ULTRA1              1000
+#define CPC_ULTRA2              1001
+#define CPC_ULTRA3              1002
+#define CPC_ULTRA3_PLUS         1003
+#define CPC_ULTRA3_I            1004
+#define CPC_ULTRA4_PLUS         1005 /* Panther */
+#define CPC_ULTRA4              1017 /* Jaguar */
+#define CPC_ULTRA_T1            1100 /* Niagara1 */
+#define CPC_ULTRA_T2            1101 /* Niagara2 */
+#define CPC_ULTRA_T2P           1102
+#define CPC_ULTRA_T3            1103
+#define CPC_SPARC_T4            1104
+#define CPC_SPARC_T5            1110
+#define CPC_SPARC_T6            1120
+// #define CPC_SPARC_T7         1130 // use CPC_SPARC_M7
+#define CPC_SPARC_M4            1204 /* Obsolete */
+#define CPC_SPARC_M5            1210
+#define CPC_SPARC_M6            1220
+#define CPC_SPARC_M7            1230
+#define CPC_SPARC_M8            1240
+
+  // --- Intel ---
+  // Pentium
+#define CPC_PENTIUM             2000
+#define CPC_PENTIUM_MMX         2001
+#define CPC_PENTIUM_PRO         2002
+#define CPC_PENTIUM_PRO_MMX     2003
+#define CPC_PENTIUM_4           2017
+#define CPC_PENTIUM_4_HT        2027
+
+  // Core Microarchitecture (Merom/Menryn)
+#define CPC_INTEL_CORE2         2028
+#define CPC_INTEL_NEHALEM       2040
+#define CPC_INTEL_WESTMERE      2042
+#define CPC_INTEL_SANDYBRIDGE   2045
+#define CPC_INTEL_IVYBRIDGE     2047
+#define CPC_INTEL_ATOM          2050 /* Atom*/
+#define CPC_INTEL_HASWELL       2060
+#define CPC_INTEL_BROADWELL     2070
+#define CPC_INTEL_SKYLAKE       2080
+#define CPC_INTEL_UNKNOWN       2499
+#define CPC_AMD_K8C             2500 /* Opteron, Athlon... */
+#define CPC_AMD_FAM_10H         2501 /* Barcelona, Shanghai... */
+#define CPC_AMD_FAM_11H         2502 /* Griffin... */
+#define CPC_AMD_FAM_15H         2503
+#define CPC_KPROF               3003 // OBSOLETE (To support 12.3 and earlier)
+#define CPC_FOX                 3004 /* pseudo-chip */
+
+  // --- Fujitsu ---
+#define CPC_SPARC64_III     3000
+#define CPC_SPARC64_V       3002
+#define CPC_SPARC64_VI      4003 /* OPL-C */
+#define CPC_SPARC64_VII     4004 /* Jupiter */
+#define CPC_SPARC64_X       4006 /* Athena */
+#define CPC_SPARC64_XII     4010 /* Athena++ */
+
+// aarch64. Constants from arch/arm64/include/asm/cputype.h
+enum {
+    ARM_CPU_IMP_ARM     = 0x41,
+    ARM_CPU_IMP_BRCM    = 0x42,
+    ARM_CPU_IMP_CAVIUM  = 0x43,
+    ARM_CPU_IMP_APM     = 0x50,
+    ARM_CPU_IMP_QCOM    = 0x51
+};
+
+#define        AARCH64_VENDORSTR_ARM   "ARM"
+
+  /* strings below must match those returned by cpc_getcpuver() */
+  typedef struct
+  {
+    int cpc2_cpuver;
+    const char * cpc2_cciname;
+  } libcpc2_cpu_lookup_t;
+#define LIBCPC2_CPU_LOOKUP_LIST \
+  {CPC_AMD_K8C               , "AMD Opteron & Athlon64"}, \
+  {CPC_AMD_FAM_10H           , "AMD Family 10h"}, \
+  {CPC_AMD_FAM_11H           , "AMD Family 11h"}, \
+  {CPC_AMD_FAM_15H           , "AMD Family 15h Model 01h"}, \
+  {CPC_AMD_FAM_15H           , "AMD Family 15h Model 02h"},/*future*/ \
+  {CPC_AMD_FAM_15H           , "AMD Family 15h Model 03h"},/*future*/ \
+  {CPC_PENTIUM_4_HT          , "Pentium 4 with HyperThreading"}, \
+  {CPC_PENTIUM_4             , "Pentium 4"}, \
+  {CPC_PENTIUM_PRO_MMX       , "Pentium Pro with MMX, Pentium II"}, \
+  {CPC_PENTIUM_PRO           , "Pentium Pro, Pentium II"}, \
+  {CPC_PENTIUM_MMX           , "Pentium with MMX"}, \
+  {CPC_PENTIUM               , "Pentium"}, \
+  {CPC_INTEL_CORE2           , "Core Microarchitecture"}, \
+    /* Merom:  F6M15: Clovertown, Kentsfield, Conroe, Merom, Woodcrest */ \
+    /* Merom:  F6M22: Merom Conroe */ \
+    /* Penryn: F6M23: Yorkfield, Wolfdale, Penryn, Harpertown */ \
+    /* Penryn: F6M29: Dunnington */ \
+  {CPC_INTEL_NEHALEM         , "Intel Arch PerfMon v3 on Family 6 Model 26"},/*Bloomfield, Nehalem EP*/ \
+  {CPC_INTEL_NEHALEM         , "Intel Arch PerfMon v3 on Family 6 Model 30"},/*Clarksfield, Lynnfield, Jasper Forest*/ \
+  {CPC_INTEL_NEHALEM         , "Intel Arch PerfMon v3 on Family 6 Model 31"},/*(TBD)*/ \
+  {CPC_INTEL_NEHALEM         , "Intel Arch PerfMon v3 on Family 6 Model 46"},/*Nehalem EX*/ \
+  {CPC_INTEL_WESTMERE        , "Intel Arch PerfMon v3 on Family 6 Model 37"},/*Arrandale, Clarskdale*/ \
+  {CPC_INTEL_WESTMERE        , "Intel Arch PerfMon v3 on Family 6 Model 44"},/*Gulftown, Westmere EP*/ \
+  {CPC_INTEL_WESTMERE        , "Intel Arch PerfMon v3 on Family 6 Model 47"},/*Westmere EX*/ \
+  {CPC_INTEL_SANDYBRIDGE     , "Intel Arch PerfMon v3 on Family 6 Model 42"},/*Sandy Bridge*/ \
+  {CPC_INTEL_SANDYBRIDGE     , "Intel Arch PerfMon v3 on Family 6 Model 45"},/*Sandy Bridge E, SandyBridge-EN, SandyBridge EP*/ \
+  {CPC_INTEL_IVYBRIDGE       , "Intel Arch PerfMon v3 on Family 6 Model 58"},/*Ivy Bridge*/ \
+  {CPC_INTEL_IVYBRIDGE       , "Intel Arch PerfMon v3 on Family 6 Model 62"},/*(TBD)*/ \
+  {CPC_INTEL_ATOM            , "Intel Arch PerfMon v3 on Family 6 Model 28"},/*Atom*/ \
+  {CPC_INTEL_HASWELL         , "Intel Arch PerfMon v3 on Family 6 Model 60"},/*Haswell*/ \
+  {CPC_INTEL_HASWELL         , "Intel Arch PerfMon v3 on Family 6 Model 63"},/*Haswell*/ \
+  {CPC_INTEL_HASWELL         , "Intel Arch PerfMon v3 on Family 6 Model 69"},/*Haswell*/ \
+  {CPC_INTEL_HASWELL         , "Intel Arch PerfMon v3 on Family 6 Model 70"},/*Haswell*/ \
+  {CPC_INTEL_BROADWELL       , "Intel Arch PerfMon v3 on Family 6 Model 61"},/*Broadwell*/ \
+  {CPC_INTEL_BROADWELL       , "Intel Arch PerfMon v3 on Family 6 Model 71"},/*Broadwell*/ \
+  {CPC_INTEL_BROADWELL       , "Intel Arch PerfMon v3 on Family 6 Model 79"},/*Broadwell*/ \
+  {CPC_INTEL_BROADWELL       , "Intel Arch PerfMon v3 on Family 6 Model 86"},/*Broadwell*/ \
+  {CPC_INTEL_SKYLAKE         , "Intel Arch PerfMon v4 on Family 6 Model 78"},/*Skylake*/ \
+  {CPC_INTEL_SKYLAKE         , "Intel Arch PerfMon v4 on Family 6 Model 85"},/*Skylake*/ \
+  {CPC_INTEL_SKYLAKE         , "Intel Arch PerfMon v4 on Family 6 Model 94"},/*Skylake*/ \
+  {CPC_INTEL_UNKNOWN         , "Intel Arch PerfMon"},/*Not yet in table*/ \
+  {CPC_SPARC64_III           , "SPARC64 III"/*?*/}, \
+  {CPC_SPARC64_V             , "SPARC64 V"/*?*/}, \
+  {CPC_SPARC64_VI            , "SPARC64 VI"}, \
+  {CPC_SPARC64_VII           , "SPARC64 VI & VII"}, \
+  {CPC_SPARC64_X             , "SPARC64 X"}, \
+  {CPC_SPARC64_XII           , "SPARC64 XII"}, \
+  {CPC_ULTRA_T1              , "UltraSPARC T1"}, \
+  {CPC_ULTRA_T2              , "UltraSPARC T2"}, \
+  {CPC_ULTRA_T2P             , "UltraSPARC T2+"}, \
+  {CPC_ULTRA_T3              , "SPARC T3"},  \
+  {CPC_SPARC_T4              , "SPARC T4"},  \
+  {CPC_SPARC_M4              , "SPARC M4"},  \
+  {CPC_SPARC_T5              , "SPARC T5"},  \
+  {CPC_SPARC_M5              , "SPARC M5"},  \
+  {CPC_SPARC_T6              , "SPARC T6"},  \
+  {CPC_SPARC_M6              , "SPARC M6"},  \
+  {CPC_SPARC_M7              , "SPARC T7"},  \
+  {CPC_SPARC_M7              , "SPARC 3e40"},  \
+  {CPC_SPARC_M7              , "SPARC M7"},  \
+  {CPC_SPARC_M8              , "SPARC 3e50"},  \
+  {CPC_ULTRA4_PLUS           , "UltraSPARC IV+"}, \
+  {CPC_ULTRA4                , "UltraSPARC IV"}, \
+  {CPC_ULTRA3_I              , "UltraSPARC IIIi"}, \
+  {CPC_ULTRA3_I              , "UltraSPARC IIIi & IIIi+"}, \
+  {CPC_ULTRA3_PLUS           , "UltraSPARC III+"}, \
+  {CPC_ULTRA3_PLUS           , "UltraSPARC III+ & IV"}, \
+  {CPC_ULTRA3                , "UltraSPARC III"}, \
+  {CPC_ULTRA2                , "UltraSPARC I&II"}, \
+  {CPC_ULTRA1                , "UltraSPARC I&II"}, \
+  {ARM_CPU_IMP_APM           , AARCH64_VENDORSTR_ARM}, \
+  {0, NULL}
+  /* init like this:
+     static libcpc2_cpu_lookup_t cpu_table[]={LIBCPC2_CPU_LOOKUP_LIST};
+   */
+#endif
diff --git a/gprofng/common/hwcdrv.c b/gprofng/common/hwcdrv.c
new file mode 100644 (file)
index 0000000..caab983
--- /dev/null
@@ -0,0 +1,1454 @@
+/* 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 <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/syscall.h>
+#include <linux/perf_event.h>
+
+#include "hwcdrv.h"
+
+/*---------------------------------------------------------------------------*/
+/* macros */
+#define IS_GLOBAL /* Mark global symbols */
+
+#include "cpuid.c" /* ftns for identifying a chip */
+
+static hdrv_pcbe_api_t hdrv_pcbe_core_api;
+static hdrv_pcbe_api_t hdrv_pcbe_opteron_api;
+static hdrv_pcbe_api_t *hdrv_pcbe_drivers[] = {
+  &hdrv_pcbe_core_api,
+  &hdrv_pcbe_opteron_api,
+  NULL
+};
+#include "opteron_pcbe.c" /* CPU-specific code */
+#include "core_pcbe.c" /* CPU-specific code  */
+
+extern hwcdrv_api_t hwcdrv_pcl_api;
+IS_GLOBAL hwcdrv_api_t *hwcdrv_drivers[] = {
+  &hwcdrv_pcl_api,
+  NULL
+};
+
+/*---------------------------------------------------------------------------*/
+
+/* utils for drivers */
+IS_GLOBAL int
+hwcdrv_assign_all_regnos (Hwcentry* entries[], unsigned numctrs)
+{
+  unsigned int pmc_assigned[MAX_PICS];
+  unsigned idx;
+  for (int ii = 0; ii < MAX_PICS; ii++)
+    pmc_assigned[ii] = 0;
+
+  /* assign the HWCs that we already know about */
+  for (idx = 0; idx < numctrs; idx++)
+    {
+      regno_t regno = entries[idx]->reg_num;
+      if (regno == REGNO_ANY)
+       {
+         /* check to see if list of possible registers only contains one entry */
+         regno = REG_LIST_SINGLE_VALID_ENTRY (entries[idx]->reg_list);
+       }
+      if (regno != REGNO_ANY)
+       {
+         if (regno < 0 || regno >= MAX_PICS || !regno_is_valid (entries[idx], regno))
+           {
+             logerr (GTXT ("For counter #%d, register %d is out of range\n"), idx + 1, regno); /*!*/
+             return HWCFUNCS_ERROR_HWCARGS;
+           }
+         TprintfT (DBG_LT2, "hwcfuncs_assign_regnos(): preselected: idx=%d, regno=%d\n", idx, regno);
+         entries[idx]->reg_num = regno; /* assigning back to entries */
+         pmc_assigned[regno] = 1;
+       }
+    }
+
+  /* assign HWCs that are currently REGNO_ANY */
+  for (idx = 0; idx < numctrs; idx++)
+    {
+      if (entries[idx]->reg_num == REGNO_ANY)
+       {
+         int assigned = 0;
+         regno_t *reg_list = entries[idx]->reg_list;
+         for (; reg_list && *reg_list != REGNO_ANY; reg_list++)
+           {
+             regno_t regno = *reg_list;
+             if (regno < 0 || regno >= MAX_PICS)
+               {
+                 logerr (GTXT ("For counter #%d, register %d is out of range\n"), idx + 1, regno); /*!*/
+                 return HWCFUNCS_ERROR_HWCARGS;
+               }
+             if (pmc_assigned[regno] == 0)
+               {
+                 TprintfT (DBG_LT2, "hwcfuncs_assign_regnos(): assigned:   idx=%d, regno=%d\n", idx, regno);
+                 entries[idx]->reg_num = regno; /* assigning back to entries */
+                 pmc_assigned[regno] = 1;
+                 assigned = 1;
+                 break;
+               }
+           }
+         if (!assigned)
+           {
+             logerr (GTXT ("Counter '%s' could not be bound to a register\n"),
+                     entries[idx]->name ? entries[idx]->name : "<NULL>");
+             return HWCFUNCS_ERROR_HWCARGS;
+           }
+       }
+    }
+  return 0;
+}
+
+IS_GLOBAL int
+hwcdrv_lookup_cpuver (const char * cpcN_cciname)
+{
+  libcpc2_cpu_lookup_t *plookup;
+  static libcpc2_cpu_lookup_t cpu_table[] = {
+    LIBCPC2_CPU_LOOKUP_LIST
+  };
+  if (cpcN_cciname == NULL)
+    return CPUVER_UNDEFINED;
+
+  /* search table for name */
+  for (plookup = cpu_table; plookup->cpc2_cciname; plookup++)
+    {
+      int n = strlen (plookup->cpc2_cciname);
+      if (!strncmp (plookup->cpc2_cciname, cpcN_cciname, n))
+       return plookup->cpc2_cpuver;
+    }
+  /* unknown, but does have a descriptive string */
+  TprintfT (DBG_LT0, "hwcfuncs: CPC2: WARNING: Id of processor '%s' "
+           "could not be determined\n",
+           cpcN_cciname);
+  return CPUVER_GENERIC;
+}
+
+/*---------------------------------------------------------------------------*/
+/* utils to generate x86 register definitions on Linux */
+
+/*
+ *  This code is structured as though we're going to initialize the
+ *  HWC by writing the Intel MSR register directly.  That is, we
+ *  assume the lowest 16 bits of the event number will have the event
+ *  and that higher bits will set attributes.
+ *
+ *  While SPARC is different, we can nonetheless use basically the
+ *  same "x86"-named functions:
+ *
+ *  - The event code will still be 16 bits.  It will still
+ *    be in the lowest 16 bits of the event number.  Though
+ *    perf_event_code() on SPARC will expect those bits to
+ *    shifted, hwcdrv_pcl.c can easily perform that shift.
+ *
+ *  - On SPARC we support only two attributes, "user" and "system",
+ *    which hwcdrv_pcl.c already converts to the "exclude_user"
+ *    and "exclude_kernel" fields expected by perf_event_open().
+ *    "user" and "system" are stored in event bits 16 and 17.
+ *    For M8, a 4-bit mask of supported PICs is stored in bits [23:20].
+ */
+
+IS_GLOBAL hwcdrv_get_eventnum_fn_t *hwcdrv_get_x86_eventnum = 0;
+
+static const attr_info_t perfctr_sparc_attrs[] = {
+  {NTXT ("user"),   0, 0x01, 16}, //usr
+  {NTXT ("system"), 0, 0x01, 17}, //os
+  {NULL, 0, 0x00, 0},
+};
+static const attr_info_t perfctr_x64_attrs[] = {/* ok for Core2 & later */
+  {NTXT ("umask"),  0, 0xff, 8},
+  {NTXT ("user"),   0, 0x01, 16}, //usr
+  //{NTXT("nouser"),  1, 0x01, 16}, //usr (inverted)
+  {NTXT ("system"), 0, 0x01, 17}, //os
+  {NTXT ("edge"),   0, 0x01, 18},
+  {NTXT ("pc"),     0, 0x01, 19},
+  {NTXT ("inv"),    0, 0x01, 23},
+  {NTXT ("cmask"),  0, 0xff, 24},
+  {NULL, 0, 0x00, 0},
+};
+const attr_info_t *perfctr_attrs_table = perfctr_x64_attrs;
+
+static const eventsel_t perfctr_evntsel_enable_bits = (0x01 << 16) | /* usr */
+    // (0xff <<  0) |   /* event*/
+    // (0xff <<  8) |   /* umask */
+    // (0x01 << 17) |   /* os */
+    // (0x01 << 18) |   /* edge */
+    // (0x01 << 19) |   /* pc */
+    (0x01 << 20) |      /* int */
+    // (0x01 << 21) |   /* reserved */
+    (0x01 << 22) |      /* enable */
+    // (0x01 << 23) |   /* inv */
+    // (0xff << 24) |   /* cmask */
+    0;
+
+static int
+myperfctr_get_x86_eventnum (const char *eventname, uint_t pmc,
+                           eventsel_t *eventsel, eventsel_t *valid_umask,
+                           uint_t *pmc_sel)
+{
+  if (hwcdrv_get_x86_eventnum &&
+      !hwcdrv_get_x86_eventnum (eventname, pmc, eventsel, valid_umask, pmc_sel))
+    return 0;
+
+  /* check for numerically-specified counters */
+  char * endptr;
+  uint64_t num = strtoull (eventname, &endptr, 0);
+  if (*eventname && !*endptr)
+    {
+      *eventsel = EXTENDED_EVNUM_2_EVSEL (num);
+      *valid_umask = 0xff; /* allow any umask (unused for SPARC?) */
+      *pmc_sel = pmc;
+      return 0;
+    }
+
+  /* name does not specify a numeric value */
+  *eventsel = (eventsel_t) - 1;
+  *valid_umask = 0x0;
+  *pmc_sel = pmc;
+  return -1;
+}
+
+static int
+mask_shift_set (eventsel_t *presult, eventsel_t invalue,
+               eventsel_t mask, eventsel_t shift)
+{
+  if (invalue & ~mask)
+    return -1; /* invalue attempts to set bits outside of mask */
+  *presult &= ~(mask << shift); /* clear all the mask bits */
+  *presult |= (invalue << shift); /* set bits according to invalue */
+  return 0;
+}
+
+static int
+set_x86_attr_bits (eventsel_t *result_mask, eventsel_t evnt_valid_umask,
+                  hwcfuncs_attr_t attrs[], int nattrs, const char*nameOnly)
+{
+  eventsel_t evntsel = *result_mask;
+  for (int ii = 0; ii < (int) nattrs; ii++)
+    {
+      const char *attrname = attrs[ii].ca_name;
+      eventsel_t attrval = (eventsel_t) attrs[ii].ca_val;
+      const char *tmpname;
+      int attr_found = 0;
+      for (int jj = 0; (tmpname = perfctr_attrs_table[jj].attrname); jj++)
+       {
+         if (strcmp (attrname, tmpname) == 0)
+           {
+             if (strcmp (attrname, "umask") == 0)
+               {
+                 if (attrval & ~evnt_valid_umask)
+                   {
+                     logerr (GTXT ("for `%s', allowable umask bits are: 0x%llx\n"),
+                             nameOnly, (long long) evnt_valid_umask);
+                     return -1;
+                   }
+               }
+             if (mask_shift_set (&evntsel,
+                                 perfctr_attrs_table[jj].is_inverted ? (attrval^1) : attrval,
+                                 perfctr_attrs_table[jj].mask,
+                                 perfctr_attrs_table[jj].shift))
+               {
+                 logerr (GTXT ("`%s' attribute `%s' could not be set to 0x%llx\n"),
+                         nameOnly, attrname, (long long) attrval);
+                 return -1;
+               }
+             TprintfT (DBG_LT2, "hwcfuncs: Counter %s, attribute %s set to 0x%llx\n",
+                       nameOnly, attrname, (long long) attrval);
+             attr_found = 1;
+             break;
+           }
+       }
+      if (!attr_found)
+       {
+         logerr (GTXT ("attribute `%s' is invalid\n"), attrname);
+         return -1;
+       }
+    }
+  *result_mask = evntsel;
+  return 0;
+}
+
+IS_GLOBAL int
+hwcfuncs_get_x86_eventsel (unsigned int regno, const char *int_name,
+                          eventsel_t *return_event, uint_t *return_pmc_sel)
+{
+  hwcfuncs_attr_t attrs[HWCFUNCS_MAX_ATTRS + 1];
+  unsigned nattrs = 0;
+  char *nameOnly = NULL;
+  eventsel_t evntsel = 0; // event number
+  eventsel_t evnt_valid_umask = 0;
+  uint_t pmc_sel = 0;
+  int rc = -1;
+  *return_event = 0;
+  *return_pmc_sel = 0;
+  void *attr_mem = hwcfuncs_parse_attrs (int_name, attrs, HWCFUNCS_MAX_ATTRS,
+                                  &nattrs, NULL);
+  if (!attr_mem)
+    {
+      logerr (GTXT ("out of memory, could not parse attributes\n"));
+      return -1;
+    }
+  hwcfuncs_parse_ctr (int_name, NULL, &nameOnly, NULL, NULL, NULL);
+  if (regno == REGNO_ANY)
+    {
+      logerr (GTXT ("reg# could not be determined for `%s'\n"), nameOnly);
+      goto attr_wrapup;
+    }
+
+  /* look up evntsel */
+  if (myperfctr_get_x86_eventnum (nameOnly, regno,
+                                 &evntsel, &evnt_valid_umask, &pmc_sel))
+    {
+      logerr (GTXT ("counter `%s' is not valid\n"), nameOnly);
+      goto attr_wrapup;
+    }
+  TprintfT (DBG_LT1, "hwcfuncs: event=0x%llx pmc=0x%x '%s' nattrs = %u\n",
+           (long long) evntsel, pmc_sel, nameOnly, nattrs);
+
+  /* determine event attributes */
+  eventsel_t evnt_attrs = perfctr_evntsel_enable_bits;
+  if (set_x86_attr_bits (&evnt_attrs, evnt_valid_umask, attrs, nattrs, nameOnly))
+    goto attr_wrapup;
+  if (evntsel & evnt_attrs)
+    TprintfT (DBG_LT0, "hwcfuncs: ERROR - evntsel & enable bits overlap: 0x%llx 0x%llx 0x%llx\n",
+             (long long) evntsel, (long long) evnt_attrs,
+             (long long) (evntsel & evnt_attrs));
+  *return_event = evntsel | evnt_attrs;
+  *return_pmc_sel = pmc_sel;
+  rc = 0;
+
+attr_wrapup:
+  free (attr_mem);
+  free (nameOnly);
+  return rc;
+}
+
+#ifdef __x86_64__
+#define syscall_instr          "syscall"
+#define syscall_clobber        "rcx", "r11", "memory"
+#endif
+#ifdef __i386__
+#define syscall_instr          "int $0x80"
+#define syscall_clobber        "memory"
+#endif
+
+static inline int
+perf_event_open (struct perf_event_attr *hw_event_uptr, pid_t pid,
+                int cpu, int group_fd, unsigned long flags)
+{
+  /* It seems that perf_event_open() sometimes fails spuriously,
+   * even while an immediate retry succeeds.
+   * So, let's try a few retries if the call fails just to be sure.
+   */
+  int rc;
+  for (int retry = 0; retry < 5; retry++)
+    {
+      rc = syscall (__NR_perf_event_open, hw_event_uptr, pid, cpu, group_fd, flags);
+      if (rc != -1)
+       return rc;
+    }
+  return rc;
+}
+
+/*---------------------------------------------------------------------------*/
+/* macros & fwd prototypes */
+
+#define HWCDRV_API      static /* Mark functions used by hwcdrv API */
+
+HWCDRV_API int hwcdrv_start (void);
+HWCDRV_API int hwcdrv_free_counters ();
+
+static pid_t
+hwcdrv_gettid (void)
+{
+#ifndef LIBCOLLECTOR_SRC
+  return syscall (__NR_gettid);
+#elif defined(intel)
+  pid_t r;
+  __asm__ __volatile__(syscall_instr
+                      : "=a" (r) : "0" (__NR_gettid)
+                      : syscall_clobber);
+  return r;
+#else
+  return syscall (__NR_gettid); // FIXUP_XXX_SPARC_LINUX // write gettid in asm
+#endif
+}
+
+/*---------------------------------------------------------------------------*/
+/* types */
+
+#define NPAGES_PER_BUF  1 // number of pages to be used for perf_event samples
+// must be a power of 2
+
+/*---------------------------------------------------------------------------*/
+
+/* typedefs */
+
+typedef struct
+{ // event (hwc) definition
+  unsigned int reg_num; // PMC assignment, potentially for detecting conflicts
+  eventsel_t eventsel;          // raw event bits (Intel/AMD)
+  uint64_t counter_preload;     // number of HWC events before signal
+  struct perf_event_attr hw;    // perf_event definition
+  hrtime_t min_time;            // minimum time we're targeting between events
+  char *name;
+} perf_event_def_t;
+
+typedef struct
+{ // runtime state of perf_event buffer
+  void *buf;                    // pointer to mmapped buffer
+  size_t pagesz;                // size of pages
+} buffer_state_t;
+
+typedef struct
+{ // runtime state of counter values
+  uint64_t prev_ena_ts;         // previous perf_event "enabled" time
+  uint64_t prev_run_ts;         // previous perf_event "running" time
+  uint64_t prev_value;          // previous HWC value
+} counter_value_state_t;
+
+typedef struct
+{ // per-counter information
+  perf_event_def_t *ev_def;     // global HWC definition for one counter
+  int fd;                       // perf_event fd
+  buffer_state_t buf_state;     // perf_event buffer's state
+  counter_value_state_t value_state; // counter state
+  int needs_restart;            // workaround for dbx failure to preserve si_fd
+  uint64_t last_overflow_period;
+  hrtime_t last_overflow_time;
+} counter_state_t;
+
+typedef struct
+{ // per-thread context
+  counter_state_t *ctr_list;
+  int signal_fd;                // fd that caused the most recent signal
+  pthread_t tid;                // for debugging signal delivery problems
+} hdrv_pcl_ctx_t;
+
+/*---------------------------------------------------------------------------*/
+
+/* static variables */
+static struct
+{
+  int library_ok;
+  int internal_open_called;
+  hwcfuncs_tsd_get_fn_t find_vpc_ctx;
+  unsigned hwcdef_cnt;      /* number of *active* hardware counters */
+  hwcdrv_get_events_fn_t *get_events;
+} hdrv_pcl_state;
+
+static hwcdrv_about_t hdrv_pcl_about = {.cpcN_cpuver = CPUVER_UNDEFINED};
+static perf_event_def_t global_perf_event_def[MAX_PICS];
+
+#define COUNTERS_ENABLED()      (hdrv_pcl_state.hwcdef_cnt)
+
+
+/* perf_event buffer formatting and handling */
+static void
+reset_buf (buffer_state_t *bufstate)
+{
+  TprintfT (0, "hwcdrv: ERROR: perf_event reset_buf() called!\n");
+  struct perf_event_mmap_page *metadata = bufstate->buf;
+  if (metadata)
+    metadata->data_tail = metadata->data_head;
+}
+
+static int
+skip_buf (buffer_state_t *bufstate, size_t sz)
+{
+  TprintfT (DBG_LT1, "hwcdrv: WARNING: perf_event skip_buf called!\n");
+  struct perf_event_mmap_page *metadata = bufstate->buf;
+  if (metadata == NULL)
+    return -1;
+  size_t pgsz = bufstate->pagesz;
+  size_t bufsz = NPAGES_PER_BUF*pgsz;
+  uint64_t d_tail = metadata->data_tail;
+  uint64_t d_head = metadata->data_head;
+
+  // validate request size
+  if (sz > d_head - d_tail || sz >= bufsz)
+    {
+      reset_buf (bufstate);
+      return -1;
+    }
+  metadata->data_tail = d_tail + sz; // advance tail
+  return 0;
+}
+
+static int
+read_buf (buffer_state_t *bufstate, void *buf, size_t sz)
+{
+  struct perf_event_mmap_page *metadata = bufstate->buf;
+  if (metadata == NULL)
+    return -1;
+  size_t pgsz = bufstate->pagesz;
+  size_t bufsz = NPAGES_PER_BUF*pgsz;
+  uint64_t d_tail = metadata->data_tail;
+  uint64_t d_head = metadata->data_head;
+
+  // validate request size
+  if (sz > d_head - d_tail || sz >= bufsz)
+    {
+      reset_buf (bufstate);
+      return -1;
+    }
+  char *buf_base = ((char *) metadata) + pgsz; // start of data buffer
+  uint64_t start_pos = d_tail & (bufsz - 1); // char offset into data buffer
+  size_t nbytes = sz;
+  if (start_pos + sz > bufsz)
+    {
+      // will wrap past end of buffer
+      nbytes = bufsz - start_pos;
+      memcpy (buf, buf_base + start_pos, nbytes);
+      start_pos = 0; // wrap to start
+      buf = (void *) (((char *) buf) + nbytes);
+      nbytes = sz - nbytes;
+    }
+  memcpy (buf, buf_base + start_pos, nbytes);
+  metadata->data_tail += sz;
+  return 0;
+}
+
+static int
+read_u64 (buffer_state_t *bufstate, uint64_t *value)
+{
+  return read_buf (bufstate, value, sizeof (uint64_t));
+}
+
+static int
+read_sample (counter_state_t *ctr_state, int msgsz, uint64_t *rvalue,
+            uint64_t *rlost)
+{
+  // returns count of bytes read
+  buffer_state_t *bufstate = &ctr_state->buf_state;
+  counter_value_state_t *cntstate = &ctr_state->value_state;
+  int readsz = 0;
+
+  // PERF_SAMPLE_IP
+  uint64_t ipc = 0;
+  int rc = read_u64 (bufstate, &ipc);
+  if (rc)
+    return -1;
+  readsz += sizeof (uint64_t);
+
+  // PERF_SAMPLE_READ: value
+  uint64_t value = 0;
+  rc = read_u64 (bufstate, &value);
+  if (rc)
+    return -2;
+  readsz += sizeof (uint64_t);
+
+  /* Bug 20806896
+   * Old Linux kernels (e.g. 2.6.32) on certain systems return enabled and
+   * running times in the sample data that correspond to the metadata times
+   *     metadata->time_enabled
+   *     metadata->time_running
+   * from the PREVIOUS (not current) sample.  Probably just ignore this bug
+   * since it's on old kernels and we only use the enabled and running times
+   * to construct loss_estimate.
+   */
+  // PERF_SAMPLE_READ: PERF_FORMAT_ENABLED
+  uint64_t enabled_time = 0;
+  rc = read_u64 (bufstate, &enabled_time);
+  if (rc)
+    return -3;
+  readsz += sizeof (uint64_t);
+
+  // PERF_SAMPLE_READ: PERF_FORMAT_RUNNING
+  uint64_t running_time = 0;
+  rc = read_u64 (bufstate, &running_time);
+  if (rc)
+    return -4;
+  readsz += sizeof (uint64_t);
+
+  uint64_t value_delta = value - cntstate->prev_value;
+  uint64_t enabled_delta = enabled_time - cntstate->prev_ena_ts;
+  uint64_t running_delta = running_time - cntstate->prev_run_ts;
+  cntstate->prev_value = value;
+  cntstate->prev_ena_ts = enabled_time;
+  cntstate->prev_run_ts = running_time;
+
+  // 24830461 need workaround for Linux anomalous HWC skid overrun
+  int set_error_flag = 0;
+  if (value_delta > 2 * ctr_state->last_overflow_period + 2000 /* HWC_SKID_TOLERANCE */)
+    set_error_flag = 1;
+
+  uint64_t loss_estimate = 0; // estimate loss of events caused by multiplexing
+  if (running_delta == enabled_delta)
+    {
+      // counter was running 100% of time, no multiplexing
+    }
+  else if (running_delta == 0)
+    loss_estimate = 1; // token amount to aid in debugging perfctr oddities
+  else if ((running_delta > enabled_delta) || (enabled_delta & 0x1000000000000000ll))
+    {
+      // running should be smaller than enabled, can't estimate
+      /*
+       * 21418391 HWC can have a negative count
+       *
+       * We've also seen enabled not only be smaller than running
+       * but in fact go negative.  Guard against this.
+       */
+      loss_estimate = 2; // token amount to aid in debugging perfctr oddities
+    }
+  else
+    {
+      // counter was running less than 100% of time
+      // Example: ena=7772268 run=6775669 raw_value=316004 scaled_value=362483 loss_est=46479
+      uint64_t scaled_delta = (double) value_delta * enabled_delta / running_delta;
+      value_delta = scaled_delta;
+#if 0
+      // We should perhaps warn the user that multiplexing is going on,
+      // but hwcdrv_pcl.c doesn't know about the collector_interface, SP_JCMD_COMMENT, or COL_COMMENT_* values.
+      // For now we simply don't report.
+      // Perhaps we should address the issue not here but in the caller collector_sigemt_handler(),
+      // but at that level "lost" has a meaning that's considerably broader than just multiplexing.
+      collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s %d -> %d</event>\n",
+                                    SP_JCMD_COMMENT, COL_COMMENT_HWCADJ, global_perf_event_def[idx].name,
+                                    ctr_list[idx].last_overflow_period, new_period);
+#endif
+    }
+  TprintfT ((loss_estimate || set_error_flag) ? DBG_LT1 : DBG_LT3,
+           "hwcdrv: '%s' ipc=0x%llx ena=%llu run=%llu "
+           "value_delta=%lld(0x%llx) loss_est=%llu %s error_flag='%s'\n",
+           ctr_state->ev_def->name, (long long) ipc,
+           (long long) enabled_delta, (long long) running_delta,
+           (long long) value_delta, (long long) value_delta,
+           (unsigned long long) loss_estimate,
+           loss_estimate ? ", WARNING - SCALED" : "",
+           set_error_flag ? ", ERRORFLAG" : "");
+  if (set_error_flag == 1)
+    value_delta |= (1ULL << 63)     /* HWCVAL_ERR_FLAG */;
+  *rvalue = value_delta;
+  *rlost = loss_estimate;
+  if (readsz != msgsz)
+    {
+      TprintfT (0, "hwcdrv: ERROR: perf_event sample not fully parsed\n");
+      return -5;
+    }
+  return 0;
+}
+
+static void
+dump_perf_event_attr (struct perf_event_attr *at)
+{
+  TprintfT (DBG_LT2, "dump_perf_event_attr:  size=%d  type=%d  sample_period=%lld\n"
+           "  config=0x%llx  config1=0x%llx  config2=0x%llx  wakeup_events=%lld __reserved_1=%lld\n",
+           (int) at->size, (int) at->type, (unsigned long long) at->sample_period,
+           (unsigned long long) at->config, (unsigned long long) at->config1,
+           (unsigned long long) at->config2, (unsigned long long) at->wakeup_events,
+           (unsigned long long) at->__reserved_1);
+#define DUMP_F(fld) if (at->fld) TprintfT(DBG_LT2, "  %-10s : %lld\n", #fld, (long long) at->fld)
+  DUMP_F (disabled);
+  DUMP_F (inherit);
+  DUMP_F (pinned);
+  DUMP_F (exclusive);
+  DUMP_F (exclude_user);
+  DUMP_F (exclude_kernel);
+  DUMP_F (exclude_hv);
+  DUMP_F (exclude_idle);
+  //    DUMP_F(xmmap);
+  DUMP_F (comm);
+  DUMP_F (freq);
+  DUMP_F (inherit_stat);
+  DUMP_F (enable_on_exec);
+  DUMP_F (task);
+  DUMP_F (watermark);
+}
+
+static void
+init_perf_event (struct perf_event_attr *hw, uint64_t event, uint64_t period)
+{
+  memset (hw, 0, sizeof (struct perf_event_attr));
+  hw->size = sizeof (struct perf_event_attr); // fwd/bwd compat
+
+#if defined(__i386__) || defined(__x86_64)
+  //note: Nehalem/Westmere OFFCORE_RESPONSE in upper 32 bits
+  hw->config = event;
+  hw->type = PERF_TYPE_RAW;     // hw/sw/trace/raw...
+#elif defined(__aarch64__)
+  hw->type = (event >> 24) & 7;
+  hw->config = event & 0xff;
+#elif defined(sparc)
+  //SPARC needs to be shifted up 16 bits
+  hw->config = (event & 0xFFFF) << 16;  // uint64_t event
+  uint64_t regs = (event >> 20) & 0xf;  // see sparc_pcbe.c
+  hw->config |= regs << 4;  // for M8, supported PICs need to be placed at bits [7:4]
+  hw->type = PERF_TYPE_RAW; // hw/sw/trace/raw...
+#endif
+
+  hw->sample_period = period;
+  hw->sample_type = PERF_SAMPLE_IP | PERF_SAMPLE_READ |
+         // PERF_SAMPLE_TID            |
+         // PERF_SAMPLE_TIME           | // possibly interesting
+         // PERF_SAMPLE_ADDR           |
+         PERF_SAMPLE_READ | // HWC value
+         // PERF_SAMPLE_CALLCHAIN      | // interesting
+         // PERF_SAMPLE_ID             |
+         // PERF_SAMPLE_CPU            | // possibly interesting
+         // PERF_SAMPLE_PERIOD         |
+         // PERF_SAMPLE_STREAM_ID      |
+         // PERF_SAMPLE_RAW            |
+         0;
+  hw->read_format =
+         PERF_FORMAT_TOTAL_TIME_ENABLED | // detect when hwc not scheduled
+         PERF_FORMAT_TOTAL_TIME_RUNNING | // detect when hwc not scheduled
+         // PERF_FORMAT_ID             |
+         // PERF_FORMAT_GROUP          |
+         0;
+  hw->disabled = 1; /* off by default */
+
+  // Note: the following override config.priv bits!
+  hw->exclude_user = (event & (1 << 16)) == 0;      /* don't count user */
+  hw->exclude_kernel = (event & (1 << 17)) == 0;    /* ditto kernel */
+  hw->exclude_hv = 1;       /* ditto hypervisor */
+  hw->wakeup_events = 1;    /* wakeup every n events */
+  dump_perf_event_attr (hw);
+}
+
+static int
+start_one_ctr (int ii, size_t pgsz, hdrv_pcl_ctx_t * pctx, char *error_string)
+{
+  // pe_attr should have been initialized in hwcdrv_create_counters()
+  struct perf_event_attr pe_attr;
+  memcpy (&pe_attr, &global_perf_event_def[ii].hw, sizeof (pe_attr));
+
+  // but we adjust the period, so make sure that pctx->ctr_list[ii].last_overflow_period has been set
+  pe_attr.sample_period = pctx->ctr_list[ii].last_overflow_period;
+
+  int hwc_fd = perf_event_open (&pe_attr, pctx->tid, -1, -1, 0);
+  if (hwc_fd == -1)
+    {
+      TprintfT (DBG_LT1, "%s idx=%d perf_event_open failed, errno=%d\n",
+               error_string, ii, errno);
+      return 1;
+    }
+
+  size_t buffer_area_sz = (NPAGES_PER_BUF + 1) * pgsz; // add a page for metadata
+  void * buf = mmap (NULL, buffer_area_sz, //YXXX is this a safe call?
+                    PROT_READ | PROT_WRITE, MAP_SHARED, hwc_fd, 0);
+  if (buf == MAP_FAILED)
+    {
+      TprintfT (0, "sz = %ld, pgsz = %ld\n  err=%s idx=%d mmap failed: %s\n",
+               (long) buffer_area_sz, (long) pgsz, error_string, ii, strerror (errno));
+      return 1;
+    }
+  pctx->ctr_list[ii].ev_def = &global_perf_event_def[ii]; // why do we set ev_def?  we never seem to use it
+  pctx->ctr_list[ii].fd = hwc_fd;
+  pctx->ctr_list[ii].buf_state.buf = buf;
+  pctx->ctr_list[ii].buf_state.pagesz = pgsz;
+  pctx->ctr_list[ii].value_state.prev_ena_ts = 0;
+  pctx->ctr_list[ii].value_state.prev_run_ts = 0;
+  pctx->ctr_list[ii].value_state.prev_value = 0;
+  pctx->ctr_list[ii].last_overflow_time = gethrtime ();
+
+  /* set async mode */
+  long flags = fcntl (hwc_fd, F_GETFL, 0) | O_ASYNC;
+  int rc = fcntl (hwc_fd, F_SETFL, flags);
+  if (rc == -1)
+    {
+      TprintfT (0, "%s idx=%d O_ASYNC failed\n", error_string, ii);
+      return 1;
+    }
+
+  /*
+   * set lwp ownership of the fd
+   * See BUGS section of "man perf_event_open":
+   *     The F_SETOWN_EX option to fcntl(2) is needed to properly get
+   *     overflow signals in threads.  This was introduced in Linux 2.6.32.
+   * Legacy references:
+   *     see http://lkml.org/lkml/2009/8/4/128
+   *     google man fcntl F_SETOWN_EX -conflict
+   *       "From Linux 2.6.32 onward, use F_SETOWN_EX to target
+   *       SIGIO and SIGURG signals at a particular thread."
+   *     http://icl.cs.utk.edu/papi/docs/da/d2a/examples__v2_8x_2self__smpl__multi_8c.html
+   *     See 2010 CSCADS presentation by Eranian
+   */
+  struct f_owner_ex fowner_ex;
+  fowner_ex.type = F_OWNER_TID;
+  fowner_ex.pid = pctx->tid;
+  rc = fcntl (hwc_fd, F_SETOWN_EX, (unsigned long) &fowner_ex);
+  if (rc == -1)
+    {
+      TprintfT (0, "%s idx=%d F_SETOWN failed\n", error_string, ii);
+      return 1;
+    }
+
+  /* Use sigio so handler can determine FD via siginfo->si_fd. */
+  rc = fcntl (hwc_fd, F_SETSIG, SIGIO);
+  if (rc == -1)
+    {
+      TprintfT (0, "%s idx=%d F_SETSIG failed\n", error_string, ii);
+      return 1;
+    }
+  return 0;
+}
+
+static int
+stop_one_ctr (int ii, counter_state_t *ctr_list)
+{
+  int hwc_rc = 0;
+  if (-1 == ioctl (ctr_list[ii].fd, PERF_EVENT_IOC_DISABLE, 1))
+    {
+      TprintfT (0, "hwcdrv: ERROR: PERF_EVENT_IOC_DISABLE #%d failed: errno=%d\n", ii, errno);
+      hwc_rc = HWCFUNCS_ERROR_GENERIC;
+    }
+  void *buf = ctr_list[ii].buf_state.buf;
+  if (buf)
+    {
+      size_t bufsz = (NPAGES_PER_BUF + 1) * ctr_list[ii].buf_state.pagesz;
+      ctr_list[ii].buf_state.buf = NULL;
+      int tmprc = munmap (buf, bufsz);
+      if (tmprc)
+       {
+         TprintfT (0, "hwcdrv: ERROR: munmap() #%d failed: errno=%d\n", ii, errno);
+         hwc_rc = HWCFUNCS_ERROR_GENERIC;
+       }
+    }
+  if (-1 == close (ctr_list[ii].fd))
+    {
+      TprintfT (0, "hwcdrv: ERROR: close(fd) #%d failed: errno=%d\n", ii, errno);
+      hwc_rc = HWCFUNCS_ERROR_GENERIC;
+    }
+  return hwc_rc;
+}
+
+/* HWCDRV_API for thread-specific actions */
+HWCDRV_API int
+hwcdrv_lwp_init (void)
+{
+  return hwcdrv_start ();
+}
+
+HWCDRV_API void
+hwcdrv_lwp_fini (void)
+{
+  hwcdrv_free_counters ();  /* also sets pctx->ctr_list=NULL; */
+}
+
+/* open */
+static int
+hdrv_pcl_internal_open ()
+{
+  if (hdrv_pcl_state.internal_open_called)
+    {
+      TprintfT (0, "hwcdrv: WARNING: hdrv_pcl_internal_open: already called\n");
+      return HWCFUNCS_ERROR_ALREADY_CALLED;
+    }
+
+  // determine if PCL is available
+  perf_event_def_t tmp_event_def;
+  memset (&tmp_event_def, 0, sizeof (tmp_event_def));
+  struct perf_event_attr *pe_attr = &tmp_event_def.hw;
+  init_perf_event (pe_attr, 0, 0);
+  pe_attr->type = PERF_TYPE_HARDWARE; // specify abstracted HW event
+  pe_attr->config = PERF_COUNT_HW_INSTRUCTIONS; // specify abstracted insts
+  int hwc_fd = perf_event_open (pe_attr,
+                               0, // pid/tid, 0 is self
+                               -1, // cpu, -1 is per-thread mode
+                               -1, // group_fd, -1 is root
+                               0); // flags
+  if (hwc_fd == -1)
+    {
+      TprintfT (DBG_LT1, "hwcdrv: WARNING: hdrv_pcl_internal_open:"
+               " perf_event_open() failed, errno=%d\n", errno);
+      goto internal_open_error;
+    }
+
+  /* see if the PCL is new enough to know about F_SETOWN_EX */
+  struct f_owner_ex fowner_ex;
+  fowner_ex.type = F_OWNER_TID;
+  fowner_ex.pid = hwcdrv_gettid (); // "pid=tid" is correct w/F_OWNER_TID
+  if (fcntl (hwc_fd, F_SETOWN_EX, (unsigned long) &fowner_ex) == -1)
+    {
+      TprintfT (DBG_LT1, "hwcdrv: WARNING: hdrv_pcl_internal_open: "
+               "F_SETOWN failed, errno=%d\n", errno);
+      close (hwc_fd);
+      goto internal_open_error;
+    }
+  close (hwc_fd);
+
+  hdrv_pcl_state.internal_open_called = 1;
+  hdrv_pcl_state.library_ok = 1; // set to non-zero to show it's initted
+  hdrv_pcl_about.cpcN_cpuver = CPUVER_UNDEFINED;
+  TprintfT (DBG_LT2, "hwcdrv: hdrv_pcl_internal_open()\n");
+  for (int ii = 0; hdrv_pcbe_drivers[ii]; ii++)
+    {
+      hdrv_pcbe_api_t *ppcbe = hdrv_pcbe_drivers[ii];
+      if (!ppcbe->hdrv_pcbe_init ())
+       {
+         hdrv_pcl_about.cpcN_cciname = ppcbe->hdrv_pcbe_impl_name ();
+         hdrv_pcl_about.cpcN_cpuver = hwcdrv_lookup_cpuver (hdrv_pcl_about.cpcN_cciname);
+         if (hdrv_pcl_about.cpcN_cpuver == CPUVER_UNDEFINED)
+           goto internal_open_error;
+         hdrv_pcl_about.cpcN_npics = ppcbe->hdrv_pcbe_ncounters ();
+         hdrv_pcl_about.cpcN_docref = ppcbe->hdrv_pcbe_cpuref ();
+         hdrv_pcl_state.get_events = ppcbe->hdrv_pcbe_get_events;
+         hwcdrv_get_x86_eventnum = ppcbe->hdrv_pcbe_get_eventnum;
+         break;
+       }
+    }
+  if (hdrv_pcl_about.cpcN_npics > MAX_PICS)
+    {
+      TprintfT (0, "hwcdrv: WARNING: hdrv_pcl_internal_open:"
+               " reducing number of HWCs from %u to %u on processor '%s'\n",
+               hdrv_pcl_about.cpcN_npics, MAX_PICS, hdrv_pcl_about.cpcN_cciname);
+      hdrv_pcl_about.cpcN_npics = MAX_PICS;
+    }
+  TprintfT (DBG_LT1, "hwcdrv: hdrv_pcl_internal_open:"
+           " perf_event cpuver=%d, name='%s'\n",
+           hdrv_pcl_about.cpcN_cpuver, hdrv_pcl_about.cpcN_cciname);
+  return 0;
+
+internal_open_error:
+  hdrv_pcl_about.cpcN_cpuver = CPUVER_UNDEFINED;
+  hdrv_pcl_about.cpcN_npics = 0;
+  hdrv_pcl_about.cpcN_docref = NULL;
+  hdrv_pcl_about.cpcN_cciname = NULL;
+  return HWCFUNCS_ERROR_NOT_SUPPORTED;
+}
+
+static void *
+single_thread_tsd_ftn ()
+{
+  static hdrv_pcl_ctx_t tsd_context;
+  return &tsd_context;
+}
+
+/* HWCDRV_API */
+HWCDRV_API int
+hwcdrv_init (hwcfuncs_abort_fn_t abort_ftn, int *tsd_sz)
+{
+  hdrv_pcl_state.find_vpc_ctx = single_thread_tsd_ftn;
+  if (tsd_sz)
+    *tsd_sz = sizeof (hdrv_pcl_ctx_t);
+
+  if (hdrv_pcl_state.internal_open_called)
+    return HWCFUNCS_ERROR_ALREADY_CALLED;
+  return hdrv_pcl_internal_open ();
+}
+
+HWCDRV_API void
+hwcdrv_get_info (int *cpuver, const char **cciname, uint_t *npics,
+                const char **docref, uint64_t *support)
+{
+  if (cpuver)
+    *cpuver = hdrv_pcl_about.cpcN_cpuver;
+  if (cciname)
+    *cciname = hdrv_pcl_about.cpcN_cciname;
+  if (npics)
+    *npics = hdrv_pcl_about.cpcN_npics;
+  if (docref)
+    *docref = hdrv_pcl_about.cpcN_docref;
+  if (support)
+    *support = HWCFUNCS_SUPPORT_OVERFLOW_PROFILING | HWCFUNCS_SUPPORT_OVERFLOW_CTR_ID;
+}
+
+HWCDRV_API int
+hwcdrv_enable_mt (hwcfuncs_tsd_get_fn_t tsd_ftn)
+{
+  if (tsd_ftn)
+    hdrv_pcl_state.find_vpc_ctx = tsd_ftn;
+  else
+    {
+      TprintfT (0, "hwcdrv: ERROR: enable_mt(): tsd_ftn==NULL\n");
+      return HWCFUNCS_ERROR_UNAVAIL;
+    }
+  return 0;
+}
+
+HWCDRV_API int
+hwcdrv_get_descriptions (hwcf_hwc_cb_t *hwc_cb, hwcf_attr_cb_t *attr_cb)
+{
+  int count = 0;
+  if (hwc_cb && hdrv_pcl_state.get_events)
+    count = hdrv_pcl_state.get_events (hwc_cb);
+  if (attr_cb)
+    for (int ii = 0; perfctr_attrs_table && perfctr_attrs_table[ii].attrname; ii++)
+      attr_cb (perfctr_attrs_table[ii].attrname);
+  if (!count)
+    return -1;
+  return 0;
+}
+
+HWCDRV_API int
+hwcdrv_assign_regnos (Hwcentry* entries[], unsigned numctrs)
+{
+  return hwcdrv_assign_all_regnos (entries, numctrs);
+}
+
+static int
+internal_hwc_start (int fd)
+{
+  int rc = ioctl (fd, PERF_EVENT_IOC_REFRESH, 1);
+  if (rc == -1)
+    {
+      TprintfT (DBG_LT0, "hwcdrv: ERROR: internal_hwc_start:"
+               " PERF_EVENT_IOC_REFRESH(fd=%d) failed: errno=%d\n", fd, errno);
+      return HWCFUNCS_ERROR_UNAVAIL;
+    }
+  TprintfT (DBG_LT3, "hwcdrv: internal_hwc_start(fd=%d)\n", fd);
+  return 0;
+}
+
+HWCDRV_API int
+hwcdrv_overflow (siginfo_t *si, hwc_event_t *eventp, hwc_event_t *lost_events)
+{
+  /* set expired counters to overflow value and all others to 0 */
+  /* return 0: OK, counters should be restarted */
+  /* return non-zero: eventp not set, counters should not be restarted */
+  /* clear return values */
+  int ii;
+  for (ii = 0; ii < hdrv_pcl_state.hwcdef_cnt; ii++)
+    {
+      eventp->ce_pic[ii] = 0;
+      lost_events->ce_pic[ii] = 0;
+    }
+  hrtime_t sig_ts = gethrtime (); //YXXX get this from HWC event?
+  eventp->ce_hrt = sig_ts;
+  lost_events->ce_hrt = sig_ts;
+
+  /* determine source signal */
+  int signal_fd = -1;
+  switch (si->si_code)
+    {
+    case POLL_HUP: /* expected value from pcl */
+      /* According to Stephane Eranian:
+       * "expect POLL_HUP instead of POLL_IN because we are
+       * in one-shot mode (IOC_REFRESH)"
+       */
+      signal_fd = si->si_fd;
+      break;
+    case SI_TKILL: /* event forwarded by tkill */
+      /* DBX can only forward SI_TKILL when it detects POLL_HUP
+       * unfortunately, this means that si->si_fd has been lost...
+       * We need to process the buffers, but we don't know the fd!
+       */
+      TprintfT (DBG_LT0, "hwcdrv: sig_ts=%llu: WARNING: hwcdrv_overflow:"
+               " SI_TKILL detected\n", sig_ts);
+      break;
+    default:
+      // "sometimes we see a POLL_IN (1) with very high event rates,"
+      // according to eranian(?)
+      TprintfT (DBG_LT0, "hwcdrv: sig_ts=%llu: ERROR: hwcdrv_overflow:"
+               " unexpected si_code 0x%x\n", sig_ts, si->si_code);
+      return HWCFUNCS_ERROR_GENERIC;
+    }
+
+  hdrv_pcl_ctx_t * pctx = hdrv_pcl_state.find_vpc_ctx ();
+  if (!pctx)
+    {
+      TprintfT (DBG_LT0, "hwcdrv: sig_ts=%llu: ERROR: hwcdrv_overflow:"
+               " tsd context is NULL\n", sig_ts);
+      return HWCFUNCS_ERROR_UNEXPECTED;
+    }
+  counter_state_t * ctr_list = (counter_state_t *) pctx->ctr_list;
+  if (!ctr_list)
+    {
+      TprintfT (DBG_LT0, "hwcdrv: sig_ts=%llu: WARNING: hwcdrv_overflow:"
+               " ctr_list is NULL\n", sig_ts);
+      return HWCFUNCS_ERROR_UNEXPECTED;
+    }
+
+  /* clear needs_restart flag */
+  for (ii = 0; ii < hdrv_pcl_state.hwcdef_cnt; ii++)
+    ctr_list[ii].needs_restart = 0;
+
+  /* attempt to identify the counter to read */
+  int signal_idx = -1;
+  pctx->signal_fd = signal_fd; // save the signal provided by siginfo_t
+  if (signal_fd != -1)
+    {
+      for (ii = 0; ii < hdrv_pcl_state.hwcdef_cnt; ii++)
+       {
+         if (ctr_list[ii].fd == signal_fd)
+           {
+             signal_idx = ii;
+             break;
+           }
+       }
+    }
+
+  if (signal_idx < 0)
+    {
+      TprintfT (DBG_LT0, "hwcdrv: sig_ts=%llu: ERROR: hwcdrv_overflow:"
+               " pmc not determined!\n", sig_ts);
+      lost_events->ce_pic[0] = 1; /* record a bogus value into experiment */
+      // note: bogus value may get overwritten in loop below
+    }
+
+  /* capture sample(s).  In addition to signal_idx, check other counters. */
+  struct perf_event_header sheader;
+  int idx;
+  for (idx = 0; idx < hdrv_pcl_state.hwcdef_cnt; idx++)
+    {
+      int num_recs = 0;
+      while (1)
+       {
+         /* check for samples */
+         struct perf_event_mmap_page *metadata = ctr_list[idx].buf_state.buf;
+         if (metadata == NULL)
+           break; // empty
+         if (metadata->data_tail == metadata->data_head)
+           break; // empty
+
+         /* read header */
+         if (read_buf (&ctr_list[idx].buf_state, &sheader, sizeof (sheader)))
+           break;
+         num_recs++;
+
+         /* check for PERF_RECORD_SAMPLE */
+         size_t datasz = sheader.size - sizeof (struct perf_event_header);
+         if (sheader.type != PERF_RECORD_SAMPLE)
+           {
+             TprintfT (DBG_LT2, "hwcdrv: sig_ts=%llu: WARNING: hwcdrv_overflow:"
+                       " unexpected recd type=%d\n",
+                       sig_ts, sheader.type);
+             if (skip_buf (&ctr_list[idx].buf_state, datasz))
+               {
+                 TprintfT (DBG_LT0, "hwcdrv: sig_ts=%llu: ERROR: hwcdrv_overflow:"
+                           " skip recd type=%d failed\n", sig_ts, sheader.type);
+                 lost_events->ce_pic[idx] = 4; /* record a bogus value */
+                 break; // failed to skip buffer??
+               }
+             lost_events->ce_pic[idx] = 2; /* record a bogus value */
+             continue; // advance to next record
+           }
+
+         /* type is PERF_RECORD_SAMPLE */
+         uint64_t value, lostv;
+         if (read_sample (&ctr_list[idx], datasz, &value, &lostv))
+           {
+             TprintfT (DBG_LT0, "hwcdrv: sig_ts=%llu: ERROR: hwcdrv_overflow:"
+                       " read_sample() failed\n", sig_ts);
+             lost_events->ce_pic[idx] = 3; // record a bogus value
+             break;                        // failed to read sample data??
+           }
+         TprintfT (DBG_LT3, "hwcdrv: sig_ts=%llu: hwcdrv_overflow:"
+                   " idx=%d value=%llu lost=%llu\n", (unsigned long long) sig_ts,
+                   idx, (unsigned long long) value, (unsigned long long) lostv);
+         if (eventp->ce_pic[idx])
+           {
+             TprintfT (DBG_LT2, "hwcdrv: sig_ts=%llu: WARNING: hwcdrv_overflow:"
+                       " idx=%d previous sample recorded as lost_event\n", sig_ts, idx);
+             lost_events->ce_pic[idx] += eventp->ce_pic[idx];
+           }
+         eventp->ce_pic[idx] = value;
+         lost_events->ce_pic[idx] += lostv;
+       }
+
+      /* debug output for unexpected (but common) cases */
+      if (idx == signal_idx)
+       {
+         if (num_recs != 1)
+           TprintfT (DBG_LT2, "hwcdrv: sig_ts=%llu: WARNING: hwcdrv_overflow:"
+                     " %d records for signal_idx=%d\n", sig_ts, num_recs, signal_idx);
+       }
+      else if (num_recs)
+       TprintfT (DBG_LT2, "hwcdrv: sig_ts=%llu: WARNING: hwcdrv_overflow:"
+                 " %d unexpected record(s) for idx=%d (signal_idx=%d)\n",
+                 sig_ts, num_recs, idx, signal_idx);
+
+      /* trigger counter restart whenever records were found */
+      if (num_recs)
+       {
+         /* check whether to adapt the overflow interval */
+         /* This is the Linux version.
+          * The Solaris version is in hwprofile.c collector_update_overflow_counters().
+          */
+         hrtime_t min_time = global_perf_event_def[idx].min_time;
+         if (min_time > 0 // overflow interval is adaptive
+             && sig_ts - ctr_list[idx].last_overflow_time < min_time) // last interval below min
+           {
+             /* pick a new overflow interval */
+             /* roughly doubled, but add funny numbers */
+             /* hopefully the result is prime or not a multiple of some # of ops/loop */
+             uint64_t new_period = 2 * ctr_list[idx].last_overflow_period + 37;
+#if 0
+             // On Solaris, we report the adjustment to the log file.
+             // On Linux it's hard for us to do so since hwcdrv_pcl.c doesn't know about collector_interface, SP_JCMD_COMMENT, or COL_COMMENT_HWCADJ.
+             // For now we simply don't report.
+             collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s %d -> %d</event>\n",
+                                            SP_JCMD_COMMENT, COL_COMMENT_HWCADJ, global_perf_event_def[idx].name,
+                                            ctr_list[idx].last_overflow_period, new_period);
+#endif
+             /* There are a variety of ways of resetting the period on Linux.
+              * The most elegant is
+              *     ioctl(fd,PERF_EVENT_IOC_PERIOD,&period)
+              * but check the perf_event_open man page for PERF_EVENT_IOC_PERIOD:
+              *     > Prior to Linux 2.6.36 this ioctl always failed due to a bug in the kernel.
+              *     > Prior to Linux 3.14 (or 3.7 on ARM), the new period did not take effect
+              *         until after the next overflow.
+              * So we're kind of stuck shutting the fd down and restarting it with the new period.
+              */
+             if (stop_one_ctr (idx, ctr_list))
+               {
+                 // EUGENE figure out what to do on error
+               }
+             ctr_list[idx].last_overflow_period = new_period;
+             if (start_one_ctr (idx, ctr_list[idx].buf_state.pagesz, pctx, "hwcdrv: ERROR: hwcdrv_overflow (readjust overflow):"))
+               {
+                 // EUGENE figure out what to do on error
+               }
+           }
+         ctr_list[idx].last_overflow_time = sig_ts;
+#if 0
+         ctr_list[idx].needs_restart = 1;
+#else // seems to be more reliable to restart here instead of hwcdrv_sighlr_restart()
+         internal_hwc_start (ctr_list[idx].fd);
+#endif
+       }
+    }
+  return 0; // OK to restart counters
+}
+
+HWCDRV_API int
+hwcdrv_sighlr_restart (const hwc_event_t *pp)
+{
+#if 0 // restarting here doesn't seem to work as well as restarting in hwcdrv_overflow()
+  hdrv_pcl_ctx_t * pctx = hdrv_pcl_state.find_vpc_ctx ();
+  if (!pctx)
+    {
+      TprintfT (DBG_LT0, "hwcdrv: ERROR: hwcdrv_sighlr_restart: find_vpc_ctx()==NULL\n");
+      return -1;
+    }
+  counter_state_t * ctr_list = (counter_state_t *) pctx->ctr_list;
+  if (!ctr_list)
+    {
+      TprintfT (DBG_LT0, "hwcdrv: WARNING: hwcdrv_sighlr_restart: ctr_list is NULL\n");
+      return -1;
+    }
+  int errors = 0;
+  for (int ii = 0; ii < hdrv_pcl_state.hwcdef_cnt; ii++)
+    {
+      if (ctr_list[ii].needs_restart)
+       errors |= internal_hwc_start (ctr_list[ii].fd);
+      ctr_list[ii].needs_restart = 0;
+    }
+  return errors;
+#else
+  return 0;
+#endif
+}
+
+/* create counters based on hwcdef[] */
+HWCDRV_API int
+hwcdrv_create_counters (unsigned hwcdef_cnt, Hwcentry *hwcdef)
+{
+  if (hwcdef_cnt > hdrv_pcl_about.cpcN_npics)
+    {
+      logerr (GTXT ("More than %d counters were specified\n"), hdrv_pcl_about.cpcN_npics); /*!*/
+      return HWCFUNCS_ERROR_HWCARGS;
+    }
+  if (hdrv_pcl_about.cpcN_cpuver == CPUVER_UNDEFINED)
+    {
+      logerr (GTXT ("Processor not supported\n"));
+      return HWCFUNCS_ERROR_HWCARGS;
+    }
+
+  /* add counters */
+  for (unsigned idx = 0; idx < hwcdef_cnt; idx++)
+    {
+      perf_event_def_t *glb_event_def = &global_perf_event_def[idx];
+      memset (glb_event_def, 0, sizeof (perf_event_def_t));
+      unsigned int pmc_sel;
+      eventsel_t evntsel;
+      if (hwcfuncs_get_x86_eventsel (hwcdef[idx].reg_num,
+                                    hwcdef[idx].int_name, &evntsel, &pmc_sel))
+       {
+         TprintfT (0, "hwcdrv: ERROR: hwcfuncs_get_x86_eventsel() failed\n");
+         return HWCFUNCS_ERROR_HWCARGS;
+       }
+      glb_event_def->reg_num = pmc_sel;
+      glb_event_def->eventsel = evntsel;
+      glb_event_def->counter_preload = hwcdef[idx].val;
+      glb_event_def->min_time = hwcdef[idx].min_time;
+      glb_event_def->name = strdup (hwcdef[idx].name); // memory leak??? very minor
+      init_perf_event (&glb_event_def->hw, glb_event_def->eventsel,
+                      glb_event_def->counter_preload);
+      TprintfT (DBG_LT1, "hwcdrv: create_counters: pic=%u name='%s' interval=%lld"
+               "(min_time=%lld): reg_num=0x%x eventsel=0x%llx ireset=%lld usr=%lld sys=%lld\n",
+               idx, hwcdef[idx].int_name, (long long) glb_event_def->counter_preload,
+               (long long) glb_event_def->min_time, (int) glb_event_def->reg_num,
+               (long long) glb_event_def->eventsel,
+               (long long) HW_INTERVAL_PRESET (hwcdef[idx].val),
+               (long long) glb_event_def->hw.exclude_user,
+               (long long) glb_event_def->hw.exclude_kernel);
+    }
+
+  hdrv_pcl_state.hwcdef_cnt = hwcdef_cnt;
+  return 0;
+}
+
+HWCDRV_API int
+hwcdrv_free_counters () // note: only performs shutdown for this thread
+{
+  hdrv_pcl_ctx_t * pctx;
+  if (!COUNTERS_ENABLED ())
+    return 0;
+  pctx = hdrv_pcl_state.find_vpc_ctx ();
+  if (!pctx)
+    {
+      TprintfT (0, "hwcdrv: WARNING: hwcdrv_free_counters: tsd context is NULL\n");
+      return HWCFUNCS_ERROR_GENERIC;
+    }
+  counter_state_t *ctr_list = pctx->ctr_list;
+  if (!ctr_list)
+    {
+      // fork child: prolog suspends hwcs, then epilog frees them
+      TprintfT (DBG_LT1, "hwcdrv: WARNING: hwcdrv_free_counters: ctr_list is already NULL\n");
+      return 0;
+    }
+  int hwc_rc = 0;
+  for (int ii = 0; ii < hdrv_pcl_state.hwcdef_cnt; ii++)
+    if (stop_one_ctr (ii, ctr_list))
+      hwc_rc = HWCFUNCS_ERROR_GENERIC;
+  TprintfT (DBG_LT1, "hwcdrv: hwcdrv_free_counters(tid=0x%lx).\n", pctx->tid);
+  pctx->ctr_list = NULL;
+  return hwc_rc;
+}
+
+HWCDRV_API int
+hwcdrv_start (void) /* must be called from each thread ? */
+{
+  hdrv_pcl_ctx_t *pctx = NULL;
+  if (!COUNTERS_ENABLED ())
+    {
+      TprintfT (DBG_LT1, "hwcdrv: WARNING: hwcdrv_start: no counters to start \n");
+      return 0;
+    }
+  if (!hdrv_pcl_state.library_ok)
+    {
+      TprintfT (0, "hwcdrv: ERROR: hwcdrv_start: library is not open\n");
+      return HWCFUNCS_ERROR_NOT_SUPPORTED;
+    }
+
+  /*
+   * set up per-thread context
+   */
+  pctx = hdrv_pcl_state.find_vpc_ctx ();
+  if (!pctx)
+    {
+      TprintfT (0, "hwcdrv: ERROR: hwcdrv_start: tsd context is NULL\n");
+      return HWCFUNCS_ERROR_UNEXPECTED;
+    }
+  pctx->tid = hwcdrv_gettid ();
+  TprintfT (DBG_LT1, "hwcdrv: hwcdrv_start(tid=0x%lx)\n", pctx->tid);
+
+  /*
+   * create per-thread counter list
+   */
+  counter_state_t *ctr_list = (counter_state_t *) calloc (hdrv_pcl_state.hwcdef_cnt,
+                                                         sizeof (counter_state_t));
+  if (!ctr_list)
+    {
+      TprintfT (0, "hwcdrv: ERROR: hwcdrv_start: calloc(ctr_list) failed\n");
+      return HWCFUNCS_ERROR_MEMORY;
+    }
+  int ii;
+  for (ii = 0; ii < hdrv_pcl_state.hwcdef_cnt; ii++)
+    ctr_list[ii].fd = -1; // invalidate fds in case we have to close prematurely
+  pctx->ctr_list = ctr_list;
+
+  /*
+   * bind the counters
+   */
+  size_t pgsz = sysconf (_SC_PAGESIZE);
+  for (ii = 0; ii < hdrv_pcl_state.hwcdef_cnt; ii++)
+    {
+      ctr_list[ii].last_overflow_period = global_perf_event_def[ii].hw.sample_period;
+      if (start_one_ctr (ii, pgsz, pctx, "hwcdrv: ERROR: hwcdrv_start:")) goto hwcdrv_start_cleanup;
+    }
+
+  /*
+   * start the counters
+   */
+  for (ii = 0; ii < hdrv_pcl_state.hwcdef_cnt; ii++)
+    {
+      int rc = internal_hwc_start (ctr_list[ii].fd);
+      if (rc < 0)
+       goto hwcdrv_start_cleanup;
+    }
+  return 0;
+
+hwcdrv_start_cleanup:
+  hwcdrv_free_counters (); // PERF_EVENT_IOC_DISABLE and close() for all fds
+  return HWCFUNCS_ERROR_UNAVAIL;
+}
+
+HWCDRV_API int
+hwcdrv_lwp_suspend (void) /* must be called from each thread */
+{
+  if (!COUNTERS_ENABLED ())
+    {
+      TprintfT (DBG_LT1, "hwcdrv: WARNING: hwcdrv_lwp_suspend: no counters\n");
+      return 0;
+    }
+  TprintfT (DBG_LT1, "hwcdrv: hwcdrv_lwp_suspend()\n");
+  return hwcdrv_free_counters ();
+}
+
+HWCDRV_API int
+hwcdrv_lwp_resume (void) /* must be called from each thread */
+{
+  if (!COUNTERS_ENABLED ())
+    {
+      TprintfT (DBG_LT1, "hwcdrv: WARNING: hwcdrv_lwp_resume: no counters\n");
+      return 0;
+    }
+  TprintfT (DBG_LT1, "hwcdrv: hwcdrv_lwp_resume()\n");
+  return hwcdrv_start ();
+}
+
+HWCDRV_API int
+hwcdrv_read_events (hwc_event_t *overflow_data, hwc_event_samples_t *sampled_data)
+{
+  overflow_data->ce_hrt = 0;
+  for (int i = 0; i < MAX_PICS; i++)
+    {
+      overflow_data->ce_pic[i] = 0;
+      if (sampled_data)
+       HWCFUNCS_SAMPLE_RESET (&sampled_data->sample[i]);
+    }
+  return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/* HWCDRV_API */
+
+hwcdrv_api_t hwcdrv_pcl_api = {
+  hwcdrv_init,
+  hwcdrv_get_info,
+  hwcdrv_enable_mt,
+  hwcdrv_get_descriptions,
+  hwcdrv_assign_regnos,
+  hwcdrv_create_counters,
+  hwcdrv_start,
+  hwcdrv_overflow,
+  hwcdrv_read_events,
+  hwcdrv_sighlr_restart,
+  hwcdrv_lwp_suspend,
+  hwcdrv_lwp_resume,
+  hwcdrv_free_counters,
+  hwcdrv_lwp_init,
+  hwcdrv_lwp_fini,
+    -1                      // hwcdrv_init_status
+};
diff --git a/gprofng/common/hwcdrv.h b/gprofng/common/hwcdrv.h
new file mode 100644 (file)
index 0000000..14c55cf
--- /dev/null
@@ -0,0 +1,330 @@
+/* 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 driver's header */
+
+#ifndef __HWCDRV_H
+#define __HWCDRV_H
+
+#include "hwcfuncs.h"
+
+#ifdef linux
+#define HWCFUNCS_SIGNAL         SIGIO
+#define HWCFUNCS_SIGNAL_STRING  "SIGIO"
+#else
+#define HWCFUNCS_SIGNAL         SIGEMT
+#define HWCFUNCS_SIGNAL_STRING  "SIGEMT"
+#endif
+
+#ifndef LIBCOLLECTOR_SRC /* not running in libcollector */
+#include <string.h>
+
+#else /* running in libcollector */
+#include "collector_module.h"
+#include "libcol_util.h"
+
+#define get_hwcdrv                  __collector_get_hwcdrv
+#define hwcdrv_drivers              __collector_hwcdrv_drivers
+#define hwcdrv_cpc1_api             __collector_hwcdrv_cpc1_api
+#define hwcdrv_cpc2_api             __collector_hwcdrv_cpc2_api
+#define hwcdrv_default              __collector_hwcdrv_default
+#define hwcdrv_driver               __collector_hwcdrv_driver
+#define hwcdrv_init                 __collector_hwcdrv_init
+#define hwcdrv_get_info             __collector_hwcdrv_get_info
+#define hwcdrv_enable_mt            __collector_hwcdrv_enable_mt
+#define hwcdrv_get_descriptions     __collector_hwcdrv_get_descriptions
+#define hwcdrv_assign_regnos        __collector_hwcdrv_assign_regnos
+#define hwcdrv_create_counters      __collector_hwcdrv_create_counters
+#define hwcdrv_start                __collector_hwcdrv_start
+#define hwcdrv_overflow             __collector_hwcdrv_overflow
+#define hwcdrv_read_events          __collector_hwcdrv_read_events
+#define hwcdrv_sighlr_restart       __collector_hwcdrv_sighlr_restart
+#define hwcdrv_lwp_suspend          __collector_hwcdrv_lwp_suspend
+#define hwcdrv_lwp_resume           __collector_hwcdrv_lwp_resume
+#define hwcdrv_free_counters        __collector_hwcdrv_free_counters
+#define hwcdrv_lwp_init             __collector_hwcdrv_lwp_init
+#define hwcdrv_lwp_fini             __collector_hwcdrv_lwp_fini
+#define hwcdrv_assign_all_regnos    __collector_hwcdrv_assign_all_regnos
+#define hwcdrv_lookup_cpuver        __collector_hwcdrv_lookup_cpuver
+#define hwcfuncs_int_capture_errmsg  __collector_hwcfuncs_int_capture_errmsg
+
+#define GTXT(x) x
+
+/* Implemented by libcollector */
+#define calloc          __collector_calloc
+#define close           CALL_UTIL(close)
+#define fcntl           CALL_UTIL(fcntl)
+#define fprintf         CALL_UTIL(fprintf)
+//#define free            __collector_free
+#define free(...)
+#define gethrtime       __collector_gethrtime
+#define ioctl           CALL_UTIL(ioctl)
+#define malloc          __collector_malloc
+#define memcpy          __collector_memcpy
+#define memset          CALL_UTIL(memset)
+#define mmap            CALL_UTIL(mmap)
+#define snprintf        CALL_UTIL(snprintf)
+#define strchr          CALL_UTIL(strchr)
+#define strcmp          CALL_UTIL(strcmp)
+#define strncmp         CALL_UTIL(strncmp)
+#define strcpy          CALL_UTIL(strcpy)
+#define strdup          __collector_strdup
+#define strncpy         CALL_UTIL(strncpy)
+#define strerror        CALL_UTIL(strerror)
+#define strlen          CALL_UTIL(strlen)
+#define strstr          CALL_UTIL(strstr)
+#define strtol          CALL_UTIL(strtol)
+#define strtoll         CALL_UTIL(strtoll)
+#define strtoul         CALL_UTIL(strtoul)
+#define strtoull        CALL_UTIL(strtoull)
+#define syscall         CALL_UTIL(syscall)
+#define sysconf         CALL_UTIL(sysconf)
+#define vsnprintf       CALL_UTIL(vsnprintf)
+
+#endif  /* --- LIBCOLLECTOR_SRC --- */
+
+/* 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
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+  /* hwcdrv api */
+  typedef struct
+  {
+    int (*hwcdrv_init)(hwcfuncs_abort_fn_t abort_ftn, int * tsd_sz);
+    /* Initialize hwc counter library (do not call again after fork)
+        Must be called before other functions.
+       Input:
+        <abort_ftn>: NULL or callback function to be used for fatal errors
+        <tsd_sz>: If not NULL, returns size in bytes required for thread-specific storage
+       Return: 0 if successful
+     */
+
+    void (*hwcdrv_get_info)(int *cpuver, const char **cciname, uint_t *npics,
+                           const char **docref, uint64_t *support);
+    /* get info about session
+       Input:
+        <cpuver>: if not NULL, returns value of CPC cpu version
+        <cciname>: if not NULL, returns name of CPU
+        <npics>: if not NULL, returns maximum # of HWCs
+        <docref>: if not NULL, returns documentation reference
+        <support>: if not NULL, returns bitmask (see hwcfuncs.h) of hwc support
+       Return: 0 if successful, nonzero otherwise
+     */
+
+    int (*hwcdrv_enable_mt)(hwcfuncs_tsd_get_fn_t tsd_ftn);
+    /* Enables multi-threaded mode (do not need to call again after fork)
+       Input:
+        <tsd_ftn>: If <tsd_sz>==0, this parameter is ignored.
+                   Otherwise:
+                    tsd_ftn() must be able to return a pointer to thread-specific
+                    memory of <tsd_sz> bytes.
+                    For a given thread, tsd_ftn() must
+                    always return the same pointer.
+       Return: none
+     */
+
+    int (*hwcdrv_get_descriptions)(hwcf_hwc_cb_t *hwc_find_action,
+                                  hwcf_attr_cb_t *attr_find_action);
+    /* Initiate callbacks with all available HWC names and and HWC attributes.
+       Input:
+        <hwc_find_action>: if not NULL, will be called once for each HWC
+        <attr_find_action>: if not NULL, will be called once for each attribute
+       Return: 0 if successful
+         or a cpc return code upon error
+     */
+
+    int (*hwcdrv_assign_regnos)(Hwcentry* entries[], unsigned numctrs);
+    /* Assign entries[]->reg_num values as needed by platform
+       Input:
+        <entries>: array of counters
+        <numctrs>: number of items in <entries>
+       Return: 0 if successful
+         HWCFUNCS_ERROR_HWCINIT if resources unavailable
+         HWCFUNCS_ERROR_HWCARGS if counters were not specified correctly
+     */
+
+    int (*hwcdrv_create_counters)(unsigned hwcdef_cnt, Hwcentry *hwcdef);
+    /* Create the counters, but don't start them.
+        call this once in main thread to create counters.
+       Input:
+        <defcnt>: number of counter definitions.
+        <hwcdef>: counter definitions.
+       Return: 0 if successful
+         or a cpc return code upon error
+     */
+
+    int (*hwcdrv_start)(void);
+    /* Start the counters.
+        call this once in main thread to start counters.
+       Return: 0 if successful
+         or a cpc return code upon error
+     */
+
+    int (*hwcdrv_overflow)(siginfo_t *si, hwc_event_t *sample,
+                          hwc_event_t *lost_samples);
+    /* Linux only.  Capture current counter values.
+        This is intended to be called from SIGEMT handler;
+       Input:
+        <si>: signal handler context information
+        <sample>: returns non-zero values for counters that overflowed
+        <lost_samples>: returns non-zero values for counters that "lost" counts
+       Return: 0 if successful
+         or a cpc return code upon error.
+     */
+
+    int (*hwcdrv_read_events)(hwc_event_t *overflow_data,
+                             hwc_event_samples_t *sampled_data);
+    /* Read current counter values and samples.  Read of samples is destructive.
+       Note: hwcdrv_read_events is not supported on Linux.
+       <overflow_data>: returns snapshot of counter values
+       <sampled_data>: returns sampled data
+       Return: 0 if successful
+         HWCFUNCS_ERROR_UNAVAIL if resource unavailable(e.g. called before initted)
+         (other values may be possible)
+     */
+
+    int (*hwcdrv_sighlr_restart)(const hwc_event_t* startVals);
+    /* Restarts the counters at the given value.
+        This is intended to be called from SIGEMT handler;
+       Input:
+        <startVals>: Solaris: new start values.
+                     Linux: pointer may be NULL; startVals is ignored.
+       Return: 0 if successful
+         or a cpc return code upon error.
+     */
+
+    int (*hwcdrv_lwp_suspend)(void);
+    /* Attempt to stop counters on this lwp only.
+        hwcdrv_lwp_resume() should be used to restart counters.
+       Return: 0 if successful
+         or a cpc return code upon error.
+     */
+
+    int (*hwcdrv_lwp_resume)(void);
+    /* Attempt to restart counters on this lwp when counters were
+        stopped with hwcdrv_lwp_suspend().
+       Return: 0 if successful
+         or a cpc return code upon error.
+     */
+
+    int (*hwcdrv_free_counters)(void);
+    /* Stops counters on this lwp only and frees resources.
+        This will fail w/ unpredictable results if other lwps's are
+        still running.  After this call returns,
+        hwcdrv_create_counters() may be called with new values.
+       Return: 0 if successful
+         or a cpc return code upon error.
+     */
+
+    int (*hwcdrv_lwp_init)(void);
+    /* per-thread counter init.
+        Solaris: nop.
+        Linux: just after thread creation call this from inside thread
+             to create context and start counters.
+       Return: 0 if successful
+         or a perfctr return code upon error
+     */
+
+    void (*hwcdrv_lwp_fini)(void);
+    /* per-thread counter cleanup.
+        Solaris: nop.
+        Linux: call in each thread upon thread destruction.
+     */
+
+    int hwcdrv_init_status;
+  } hwcdrv_api_t;
+
+  extern hwcdrv_api_t *get_hwcdrv ();
+  extern hwcdrv_api_t *__collector_get_hwcdrv ();
+  extern int __collector_hwcfuncs_bind_descriptor (const char *defstring);
+  extern Hwcentry **__collector_hwcfuncs_get_ctrs (unsigned *defcnt);
+  extern hwcdrv_api_t *hwcdrv_drivers[]; // array of available drivers
+
+  /* prototypes for internal use by hwcdrv drivers */
+  typedef struct
+  { // see hwcdrv_get_info() for field definitions
+    int cpcN_cpuver;
+    uint_t cpcN_npics;
+    const char *cpcN_docref;
+    const char *cpcN_cciname;
+  } hwcdrv_about_t;
+
+  extern int hwcdrv_assign_all_regnos (Hwcentry* entries[], unsigned numctrs);
+  /* assign user's counters to specific CPU registers */
+
+  extern int hwcdrv_lookup_cpuver (const char * cpcN_cciname);
+  /* returns hwc_cpus.h ID for a given string. */
+
+  extern void hwcfuncs_int_capture_errmsg (const char *fn, int subcode,
+                                          const char *fmt, va_list ap);
+#define logerr  hwcfuncs_int_logerr
+
+  /*---------------------------------------------------------------------------*/
+  /* prototypes for internal use by linux hwcdrv drivers */
+#define PERFCTR_FIXED_MAGIC 0x40000000 /* tells perfctr to use intel fixed pmcs */
+#define PERFCTR_UMASK_SHIFT 8
+#define EXTENDED_EVNUM_2_EVSEL(evnum) \
+  ( (((eventsel_t)(evnum) & 0x0f00ULL) << 24) | ((eventsel_t)(evnum) & ~0x0f00ULL) )
+
+  typedef uint64_t eventsel_t;
+  extern int  hwcfuncs_get_x86_eventsel (unsigned int regno, const char *int_name,
+                            eventsel_t *return_event, uint_t *return_pmc_sel);
+
+  typedef int (hwcdrv_get_events_fn_t) (hwcf_hwc_cb_t *hwc_cb);
+  typedef int (hwcdrv_get_eventnum_fn_t) (const char *eventname, uint_t pmc,
+                                         eventsel_t *eventnum,
+                                         eventsel_t *valid_umask, uint_t *pmc_sel);
+  extern hwcdrv_get_eventnum_fn_t *hwcdrv_get_x86_eventnum;
+
+  typedef struct
+  {
+    const char * attrname;  // user-visible name of attribute
+    int is_inverted;        // nonzero means boolean attribute is inverted
+    eventsel_t mask;        // which attribute bits can be set?
+    eventsel_t shift;       // how far to shift bits for use in x86 register
+  } attr_info_t;
+  extern const attr_info_t *perfctr_attrs_table;
+
+  /* hdrv_pcbe api: cpu-specific drivers for Linux */
+  typedef struct
+  {
+    int (*hdrv_pcbe_init)(void);
+    uint_t (*hdrv_pcbe_ncounters)(void);
+    const char *(*hdrv_pcbe_impl_name)(void);
+    const char *(*hdrv_pcbe_cpuref)(void);
+    int (*hdrv_pcbe_get_events)(hwcf_hwc_cb_t *hwc_cb);
+    int (*hdrv_pcbe_get_eventnum)(const char * eventname, uint_t pmc,
+                                 eventsel_t *eventnum, eventsel_t *valid_umask,
+                                 uint_t *pmc_sel);
+  } hdrv_pcbe_api_t;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/gprofng/common/hwcentry.h b/gprofng/common/hwcentry.h
new file mode 100644 (file)
index 0000000..8611ab7
--- /dev/null
@@ -0,0 +1,417 @@
+/* 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 _HWCENTRY_H
+#define _HWCENTRY_H
+
+#ifndef LIBCOLLECTOR_SRC /* not running in libcollector */
+#include <stdio.h>  /* FILE */
+#endif  /* --- LIBCOLLECTOR_SRC --- */
+#include <stdlib.h> /* size_t */
+#include "hwc_cpus.h"
+#include "gp-time.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+  /* ABS backtrack types */
+  typedef enum
+  {
+    /* !! Lowest 2 bits are used to indicate load and store, respectively !! */
+    /* Example: On SPARC, backtrack.c did this: if (ABS_memop & inst_type) ... */
+    ABST_NONE               = 0x0,
+    ABST_LOAD               = 0x1,
+    ABST_STORE              = 0x2,
+    ABST_LDST               = 0x3,
+    ABST_COUNT              = 0x4,
+    ABST_US_DTLBM           = 0xF,
+    ABST_NOPC               = 0x100,
+    ABST_CLKDS              = 0x103,     // Obsolete
+    ABST_EXACT              = 0x203,
+    ABST_LDST_SPARC64       = 0x303,
+    ABST_EXACT_PEBS_PLUS1   = 0x403
+    /* full description below... */
+  } ABST_type;
+
+#define ABST_PLUS_BY_DEFAULT(n) ((n)==ABST_EXACT || (n)==ABST_EXACT_PEBS_PLUS1)
+#define ABST_BACKTRACK_ENABLED(n) ((n)!=ABST_NONE && (n)!=ABST_NOPC)
+#define ABST_MEMSPACE_ENABLED(n)  ((n)!=ABST_NONE && (n)!=ABST_NOPC && (n)!=ABST_COUNT)
+
+  /* ABS determines the type of backtracking available for a particular metric.
+   * Backtracking is enabled with the "+" in "-h +<countername>...".
+   *
+   * When Backtracking is not possible:
+   *
+   *  ABST_NONE=0:     Either the user did not specify "+", or backtracking
+   *                   is not applicable to the metric, for example:
+   *                     clk cycles,
+   *                     instruct counts (dispatch + branch + prefetch),
+   *                     i$,
+   *                     FP ops
+   *  ABST_NOPC=0x100  Used for non-program-related external events, for example:
+   *                     system interface events,
+   *                     memory controller counters
+   *                   Of all ABST_type options, only ABST_NOPC prevents hwprofile.c
+   *                     from recording PC/stack information.
+   *
+   * When backtracking is allowed:
+   *
+   *  ABST_LOAD=1:     data read events, used with metrics like:
+   *                     D$, E$, P$ read misses and hits.
+   *                     [DC+EC+PC]_rd*, Re_*_miss*,
+   *                     EC_snoop_cb(?)
+   *  ABST_STORE=2:    data write events, used with metrics like:
+   *                     D$ writes and write related misses
+   *                     DC_wr/wr-miss, EC_wb, WC=writecache, Rstall_storeQ
+   *                     [EC+PC=pcache]_snoop_inv(?), WC_snoop_cb(?),
+   *  ABST_LDST=3:     data reads/writes, used with metrics like:
+   *                     E$ references, misses.
+   *  ABST_COUNT=4:    dedicated assembly instruction: '%hi(0xfc000)'
+   *                     See SW_count_n metric on sparc.
+   *  ABST_US_DTLBM=0xF: for load-store on Sparc -- seems to be used only
+   *                     for "unskidded DTLB_miss" with DTLB_miss metric.
+   *                     Checks two adjacent instructions for Data access.
+   *  ABST_CLKDS=0x103: data reads/writes, used with Clock-based Dataspace
+   *                     profiling.  Ultrasparc T2 and earlier.
+   *  ABST_EXACT=0x203: data reads/writes, precise trap with no skid
+   *  ABST_LDST_SPARC64=0x303: Fujitsu SPARC64 load/store
+   *  ABST_EXACT_PEBS_PLUS1=0x403: data reads/writes, precise sampling with 1 instr. skid
+   */
+
+  /* Hwcentry - structure for defining a counter.
+   *   Some fields have different usage when returned from
+   *   hwc_lookup(), hwc_post_lookup(), or hwc_scan_*().
+   *   Each function will describe its return values in more detail.
+   */
+  typedef struct
+  {
+    char *name;         /* user HWC specification */
+    char *int_name;     /* internal HWC specification */
+    regno_t reg_num;    /* register in CPU, aka picnum, or REGNO_ANY */
+    char *metric;       /* descriptive name, for well-known counters only */
+    volatile int val;   /* default or actual overflow value */
+    int timecvt;        /* multiplier to convert metric to time, 0 if N/A */
+    ABST_type memop;    /* type of backtracking allowed */
+    char *short_desc;   /* optional one-liner description, or NULL */
+    int type;           /* Type of perf_event_attr */
+    long long config;   /* perf_event_type -specific configuration */
+    /* the fields above this line are expected, in order, by the tables in hwctable.c */
+    /* ================================================== */
+    /* the fields below this line are more flexible */
+    int sort_order;     /* "tag" to associate experiment record with HWC def */
+    regno_t *reg_list;  /* if not NULL, legal values for <reg_num> field above */
+    /* Note: reg_list will be terminated by REGNO_ANY */
+    /* Max size of array is MAX_PICS */
+    hrtime_t min_time;  /* target minimum time between overflow events.  0 is off.  See HWCTIME_* macros */
+    hrtime_t min_time_default; /* if min_time==HWCTIME_AUTO, use this value instead.  0 is off. */
+    int ref_val;    /* if min_time==HWCTIME_AUTO, use this time.  0 is off. */
+    int lval, hval; /* temporary to allow DBX to build until dbx glue.cc fixed */
+  } Hwcentry;
+
+  // Hwcentry.min_time canned values
+#define HWCTIME_TBD ((hrtime_t)( -1LL)) /* self-adjusting enabled but nsecs not yet selected */
+#define HWCTIME_HI  (   1 * 1000 * 1000LL ) /*   1 msec represented in nsecs */
+#define HWCTIME_ON  (  10 * 1000 * 1000LL ) /*  10 msec represented in nsecs */
+#define HWCTIME_LO  ( 100 * 1000 * 1000LL ) /* 100 msec represented in nsecs */
+
+#define HWC_VAL_HI(refVal) (((refVal)/10) + 1)
+#define HWC_VAL_ON(refVal) (refVal)
+#define HWC_VAL_LO(refVal) (((refVal)*10)/100*100 + 1)  // zero's out lower digits, add 1
+#define HWC_VAL_CUSTOM(refVal, targetNanoSec) ((double)(refVal)*(targetNanoSec)/HWCTIME_ON)
+
+#define HWCENTRY_USES_SAMPLING(h)   ((h)->memop==ABST_EXACT_PEBS_PLUS1)
+
+  extern int hwc_lookup (int forKernel, hrtime_t min_time_default,
+                        const char *uname, Hwcentry *list[], unsigned listsz,
+                        char **emsg, char **wmsg);
+  /* Parses counter cmdline string.  Returns counter definitions.
+   * Input:
+   *   <forKernel> lookup using which table: 0-collect or 1-er_kernel
+   *   <min_time_default> minimum nseconds between events if Hwcentry.min_time == HWCTIME_TBD.  0 to disable.
+   *   <uname> command line HWC definition of format:
+   *           <ctr_def>...[{','|(whitespace)}<ctr_n_def>] where
+   *           <ctr_def> == [+]<ctr>[/<reg#>][,<interval>]
+   *   <list> array of pointers to store counter definitions
+   *   <listsz> number of elements in <list>
+   * Returns:
+   *   Success:
+   *     Returns number of valid counters in <list> and <list>'s elements
+   *     will be initialized as follows:
+   *
+   *     <list[]->name>:
+   *       Copy of the <uname> with the following modification:
+   *         if backtracking is not supported, the + will be removed.
+   *     <list[]->int_name>:
+   *       For well-known and convenience ctrs, the internal HWC specification,
+   *         e.g. BSQ_cache_reference~emask=0x0100.
+   *       For raw ctrs, this will be a copy of <name>.
+   *     <list[]->reg_num>:
+   *       Register number if specified by user or table, REGNO_ANY otherwise.
+   *     <list[]->metric>:
+   *       For well-known counters, descriptive name, e.g. "D$ Read Misses".
+   *       NULL otherwise.
+   *     <list[]->val>:
+   *       Overflow value selected by user, default value otherwise.
+   *     <list[]->timecvt>:
+   *       Value from tables.
+   *     <list[]->memop>:
+   *       If + is selected and backtracking is allowed, value from table.
+   *       ABST_NONE or ABST_NOPC otherwise.
+   *
+   *     It is the responsibility of the caller to free 'name' and 'int_name'.
+   *     'metric' is a static string and shouldn't be freed.
+   *     'emsg' will point to NULL
+   *
+   *   Failure:
+   *     Frees all allocated elements.
+   *     emsg will point to a string with an error message to print
+   *     returns -1
+   */
+
+  extern char *hwc_validate_ctrs (int forKernel, Hwcentry *list[], unsigned listsz);
+  /* Validates that the vector of specified HW counters can be loaded (more-or-less)
+   *   Some invalid combinations, especially on Linux will not be detected
+   */
+
+  extern int hwc_get_cpc_cpuver ();
+  /* Return the cpc_cpuver for this system.  Other possible values:
+   *   CPUVER_GENERIC=0,           CPU could not be determined, but HWCs are ok.
+   *   CPUVER_UNDEFINED=-1,        HWCs are not available.
+   */
+
+  extern char *hwc_get_docref (char *buf, size_t buflen);
+  /* Return a CPU HWC document reference, or NULL. */
+
+  // TBR
+  extern char *hwc_get_default_cntrs ();
+  /* Return a default HW counter string; may be NULL, or zero-length */
+  /* NULL means none is defined in the table; or zero-length means string defined could not be loaded */
+
+  extern char *hwc_get_default_cntrs2 (int forKernel, int style);
+  /* like hwc_get_default_cntrs() for style==1 */
+  /* but allows other styles of formatting as well */
+  /* deprecate and eventually remove hwc_get_default_cntrs() */
+
+  extern char *hwc_get_orig_default_cntrs ();
+  /* Get the default HW counter string as set in the table */
+  /* NULL means none is defined in the table */
+
+  extern void hwc_update_val (Hwcentry *ctr);
+  /* Check time-based intervals and update Hwcentry.val as needed */
+
+  extern char *hwc_get_cpuname (char *buf, size_t buflen);
+  /* Return the cpc cpu name for this system, or NULL. */
+
+  extern unsigned hwc_get_max_regs ();
+  /* Return number of counters registers for this system. */
+
+  extern unsigned hwc_get_max_concurrent (int forKernel);
+  /* Return the max number of simultaneous counters for this system. */
+
+  extern char **hwc_get_attrs (int forKernel);
+  /* Return:
+   *   Array of attributes (strings) supported by this system.
+   *   Last element in array is null.
+   *   Array and its elements should NOT be freed by the caller.
+   */
+
+  extern unsigned hwc_scan_attrs (void (*action)(const char *attr,
+                                                const char *desc));
+  /* Scan the HW counter attributes, and call function for each attribute.
+   * Input:
+   *   <action>:
+   *     If NULL, no action is performed, but count is still returned.
+   *     Otherwise called for each type of attributes, or if none exist,
+   *       called once with NULL parameter.
+   * Return: count of times <action> would have been called w/ non-NULL data.
+   */
+
+  extern Hwcentry *hwc_post_lookup (Hwcentry * pret_ctr, char *uname,
+                                   char * int_name, int cpc_cpuver);
+  /* When post-processing a run, look up a Hwcentry for given type of system.
+   * Input:
+   *   <pret_ctr>: storage for counter definition
+   *   <uname>: well-known name, convenience name, or complete HWC defintion.
+   *   <int_name>: Hwcentry->int_name or NULL for don't care
+   *   <cpc_cpuver>: version of cpu used for experiment.
+   * Return:
+   *   <pret_ctr>'s elements set as follows:
+   *
+   *     <pret_ctr->name>:
+   *       Copy of <uname> with the following modifications:
+   *         1) + and /<regnum> will be stripped off
+   *         2) attributes will be sorted and values will shown in hex.
+   *     <pret_ctr->int_name>:
+   *       For well-known/convenience counters, the internal HWC specification
+   *         from the table, e.g. BSQ_cache_reference~emask=0x0100.
+   *       Otherwise, a copy of <uname>.
+   *     <pret_ctr->reg_num>:
+   *       Register number if specified by user or table,
+   *       REGNO_ANY othewise.
+   *     <pret_ctr->metric>:
+   *       For well-known counters, descriptive name, e.g. "D$ Read Misses".
+   *       NULL otherwise.
+   *     <pret_ctr->timecvt>:
+   *       For well-known/convenience/hidden counters, value from table.
+   *       0 otherwise.
+   *     <pret_ctr->memop>:
+   *       For well-known/convenience/hidden counters, value from table.
+   *       ABST_NONE otherwise.
+   *     <pret_ctr->sort_order>:
+   *       Set to 0.
+   *
+   *     It is the responsibility of the caller to free 'name' and 'int_name'.
+   *     'metric' is a static string and shouldn't be freed.
+   */
+
+  extern Hwcentry **hwc_get_std_ctrs (int forKernel);
+  /* Return:
+   *   Array of well-known counters supported by this system.
+   *   Last element in array will be NULL.
+   *   Array and its elements should NOT be freed by the caller.
+   */
+
+  extern unsigned hwc_scan_std_ctrs (void (*action)(const Hwcentry *));
+  /* Call <action> for each well-known counter.
+   * Input:
+   *   <action>:
+   *     If NULL, no action is performed, but count is still returned.
+   *     Otherwise called for each type of attributes, or if none exist,
+   *       called once with NULL parameter.
+   * Return:
+   *   Count of times <action> would have been called w/ non-NULL data.
+   *   If <action> is not NULL, Hwcentry fields will be set as follows:
+   *     <ctr->name>:
+   *       HWC alias name, e.g. dcrm.
+   *     <ctr->int_name>:
+   *       The internal HWC specification, e.g. BSQ_cache_reference~emask=0x0100.
+   *     <ctr->reg_num>:
+   *       Register number if specified by the table, REGNO_ANY otherwise.
+   *     <ctr->metric>:
+   *       Descriptive name, e.g. "D$ Read Misses".
+   *     <ctr->lval>:
+   *       Low-resolution overflow value.
+   *     <ctr->val>:
+   *       Default overflow value.
+   *     <ctr->hval>:
+   *       High-resolution overflow value.
+   *     <ctr->timecvt>:
+   *       multiplier to convert metric to time, 0 otherwise.
+   *     <ctr->memop>:
+   *       ABST_* type for this counter.
+   *     <ctr->reg_list>:
+   *       Array of legal <reg_num> values.  Terminated by REGNO_ANY.
+   *
+   *     Note: All fields point to static data, none should be freed.
+   */
+
+  extern Hwcentry **hwc_get_raw_ctrs (int forKernel);
+  /* Return:
+   *   Table of raw (not well-known) counters supported by this system.
+   *   Last element in array will be NULL.
+   *   Table and its elements should NOT be freed by the caller.
+   */
+
+  extern unsigned hwc_scan_raw_ctrs (void (*action)(const Hwcentry *));
+  /* Call <action> for each raw counter.
+   * Input:
+   *   <action>:
+   *     If NULL, no action is performed, but count is still returned.
+   *     Otherwise called for each type of attributes, or if none exist,
+   *       called once with NULL parameter.
+   * Return:
+   *   Count of times <action> would have been called w/ non-NULL data.
+   *   If <action> is not NULL, Hwcentry fields will be set as follows:
+   *     <ctr->name>:
+   *       HWC raw name without attributes, e.g. BSQ_cache_reference.
+   *     <ctr->int_name>:
+   *       NULL.
+   *     <ctr->metric>:
+   *       NULL.
+   *     The remainder of the fields are the same as for
+   *       hwc_scan_std_ctrs().
+   *
+   *     Note: All fields point to static data, none should be freed.
+   */
+
+  extern void
+  hwc_usage (int forKernel, const char *cmd, const char *dataspace_msg);
+  /* Print an i18n'd description of "-h" usage, used by collect and er_kernel.
+   */
+
+  extern void hwc_usage_f (int forKernel, FILE *f, const char *cmd,
+                          const char *dataspace_msg, int show_syntax,
+                          int show_short_desc);
+  /* Print an i18n'd description of "-h" usage to a FILE.  Used by GUI. */
+
+  extern char *hwc_rate_string (const Hwcentry *pctr, int force_numeric_format);
+  /* Returns {"on"|"hi"|"lo"|""|<value>}.  Return value must be freed by caller. */
+
+  extern char *hwc_i18n_metric (const Hwcentry *ctr);
+  /* Get a basic lable for a counter, properly i18n'd.
+   *   Note: NOT MT SAFE.
+   * Examples:
+   *   CPU Cycles
+   *   DC_rd Events
+   * Pseudocode:
+   *   if(ctr->metric != NULL) {
+   *       sprintf(metricbuf, PTXT(ctr->metric) );
+   *   } else if (ctr->name != NULL) {
+   *       sprintf(metricbuf, GTXT("%s Events"), ctr->name );
+   *   } else if (ctr->int_name != NULL) {
+   *       sprintf(metricbuf, GTXT("%s Events"), ctr->int_name );
+   *   }
+   * Return: pointer to a buffer containing the above description.
+   */
+
+  extern char *hwc_hwcentry_string (char *buf, size_t buflen, const Hwcentry *ctr);
+  /* Get a i18n'd description of a HW counter's options.
+   *   Examples of well-known counters:
+   *     cycles[/{0|1}],9999991 ('CPU Cycles', alias for Cycle_cnt; CPU-cycles)
+   *     dcr[/0],1000003 ('D$ Read Refs', alias for DC_rd; load events)
+   *   Examples of raw counters:
+   *     Cycle_cnt[/{0|1}],1000003 (CPU-cycles)
+   *     DC_rd[/0],1000003 (load events)
+   * Return: <buf>, filled in.
+   */
+
+  extern char *hwc_hwcentry_specd_string (char *buf, size_t buflen, const Hwcentry *ctr);
+  /* Get a i18n'd description of a HW counter's specific configuration.
+   *   Examples of well-known counters:
+   *     cycles,9999991 ('CPU Cycles')
+   *     +dcr/0,1000003 ('D$ Read Refs')
+   *   Examples of raw counters:
+   *     Cycle_cnt,1000003
+   *     +DC_rd/0,1000003
+   * Return: <buf>, filled in.
+   */
+
+  extern const char *hwc_memop_string (ABST_type memop);
+  /* Get a i18n'd description of a variable of type ABST_type.
+   * Return: pointer to static string.
+   */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/gprofng/common/hwcfuncs.c b/gprofng/common/hwcfuncs.c
new file mode 100644 (file)
index 0000000..2f9764d
--- /dev/null
@@ -0,0 +1,704 @@
+/* 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 "hwcdrv.h"
+#include "hwcfuncs.h"
+
+/*---------------------------------------------------------------------------*/
+/* macros */
+
+#define IS_GLOBAL           /* Mark global symbols */
+#define HWCDRV_API static   /* Mark functions used by hwcdrv API */
+
+/*---------------------------------------------------------------------------*/
+/* static variables */
+static uint_t cpcN_npics;
+static char hwcfuncs_errmsg_buf[1024];
+static int hwcfuncs_errmsg_enabled = 1;
+static int hwcfuncs_errmsg_valid;
+
+/* --- user counter selections and options */
+static unsigned hwcdef_cnt; /* number of *active* hardware counters */
+static Hwcentry hwcdef[MAX_PICS]; /* HWC definitions */
+static Hwcentry *hwctable[MAX_PICS]; /* HWC definitions */
+
+/* --- drivers --- */
+
+// default driver
+
+HWCDRV_API int
+hwcdrv_init (hwcfuncs_abort_fn_t abort_ftn, int* tsd_sz)
+{
+  return -1;
+}
+
+HWCDRV_API void
+hwcdrv_get_info (
+                int * cpuver, const char ** cciname,
+                uint_t * npics, const char ** docref, uint64_t* support) { }
+
+HWCDRV_API int
+hwcdrv_enable_mt (hwcfuncs_tsd_get_fn_t tsd_ftn)
+{
+  return -1;
+}
+
+HWCDRV_API int
+hwcdrv_get_descriptions (hwcf_hwc_cb_t *hwc_find_action,
+                        hwcf_attr_cb_t *attr_find_action)
+{
+  return 0;
+}
+
+HWCDRV_API int
+hwcdrv_assign_regnos (Hwcentry *entries[], unsigned numctrs)
+{
+  return -1;
+}
+
+HWCDRV_API int
+hwcdrv_create_counters (unsigned hwcdef_cnt, Hwcentry *hwcdef)
+{
+  return -1;
+}
+
+HWCDRV_API int
+hwcdrv_read_events (hwc_event_t *events, hwc_event_samples_t*samples)
+{
+  return -1;
+}
+
+HWCDRV_API int
+hwcdrv_start (void)
+{
+  return -1;
+}
+
+HWCDRV_API int
+hwcdrv_overflow (siginfo_t *si, hwc_event_t *s, hwc_event_t *t)
+{
+  return 0;
+}
+
+HWCDRV_API int
+hwcdrv_sighlr_restart (const hwc_event_t *sample)
+{
+  return -1;
+}
+
+HWCDRV_API int
+hwcdrv_lwp_suspend (void)
+{
+  return -1;
+}
+
+HWCDRV_API int
+hwcdrv_lwp_resume (void)
+{
+  return -1;
+}
+
+HWCDRV_API int
+hwcdrv_free_counters (void)
+{
+  return 0;
+}
+
+HWCDRV_API int
+hwcdrv_lwp_init (void)
+{
+  return 0;
+}
+
+HWCDRV_API void
+hwcdrv_lwp_fini (void) { }
+
+static hwcdrv_api_t hwcdrv_default = {
+  hwcdrv_init,
+  hwcdrv_get_info,
+  hwcdrv_enable_mt,
+  hwcdrv_get_descriptions,
+  hwcdrv_assign_regnos,
+  hwcdrv_create_counters,
+  hwcdrv_start,
+  hwcdrv_overflow,
+  hwcdrv_read_events,
+  hwcdrv_sighlr_restart,
+  hwcdrv_lwp_suspend,
+  hwcdrv_lwp_resume,
+  hwcdrv_free_counters,
+  hwcdrv_lwp_init,
+  hwcdrv_lwp_fini,
+  -1                        // hwcdrv_init_status
+};
+
+static hwcdrv_api_t *hwcdrv_driver = &hwcdrv_default;
+
+
+/*---------------------------------------------------------------------------*/
+/* misc */
+
+/* print a counter definition (for debugging) */
+static void
+ctrdefprint (int dbg_lvl, const char * hdr, Hwcentry*phwcdef)
+{
+  TprintfT (dbg_lvl, "%s: name='%s', int_name='%s',"
+           " reg_num=%d, timecvt=%d, memop=%d, "
+           "interval=%d, tag=%u, reg_list=%p\n",
+           hdr, phwcdef->name, phwcdef->int_name, phwcdef->reg_num,
+           phwcdef->timecvt, phwcdef->memop, phwcdef->val,
+           phwcdef->sort_order, phwcdef->reg_list);
+}
+
+/*---------------------------------------------------------------------------*/
+/* errmsg buffering */
+
+/* errmsg buffering is needed only because the most descriptive error
+   messages from CPC are delivered using a callback mechanism.
+   hwcfuncs_errmsg_get() should only be used during initialization, and
+   ideally,  only to provide feedback to an end user when his counters can't
+   be bound to HW.
+ */
+IS_GLOBAL char *
+hwcfuncs_errmsg_get (char *buf, size_t bufsize, int enable)
+{
+  hwcfuncs_errmsg_enabled = 0;
+  if (buf && bufsize)
+    {
+      if (hwcfuncs_errmsg_valid)
+       {
+         strncpy (buf, hwcfuncs_errmsg_buf, bufsize);
+         buf[bufsize - 1] = 0;
+       }
+      else
+       *buf = 0;
+    }
+  hwcfuncs_errmsg_buf[0] = 0;
+  hwcfuncs_errmsg_valid = 0;
+  hwcfuncs_errmsg_enabled = enable;
+  return buf;
+}
+
+/* used by cpc to log an error */
+IS_GLOBAL void
+hwcfuncs_int_capture_errmsg (const char *fn, int subcode,
+                            const char *fmt, va_list ap)
+{
+  if (hwcfuncs_errmsg_enabled &&
+      !hwcfuncs_errmsg_valid)
+    {
+      vsnprintf (hwcfuncs_errmsg_buf, sizeof (hwcfuncs_errmsg_buf), fmt, ap);
+      TprintfT (DBG_LT0, "hwcfuncs: cpcN_capture_errmsg(): %s\n",
+               hwcfuncs_errmsg_buf);
+      hwcfuncs_errmsg_valid = 1;
+    }
+  return;
+}
+
+/* Log an internal error to the CPC error buffer.
+ * Note: only call this during init functions.
+ * Note: when most cpc calls fail, they will call cpcN_capture_errmsg()
+ *   directly, so only call logerr() when a non-cpc function fails.
+ */
+IS_GLOBAL void
+hwcfuncs_int_logerr (const char *format, ...)
+{
+  va_list va;
+  va_start (va, format);
+  hwcfuncs_int_capture_errmsg ("logerr", 0, format, va);
+  va_end (va);
+}
+
+/* utils to parse counter strings */
+static void
+clear_hwcdefs ()
+{
+  for (unsigned idx = 0; idx < MAX_PICS; idx++)
+    {
+      static Hwcentry empty;
+      hwcdef[idx] = empty; // leaks strings and reg_list array
+      hwcdef[idx].reg_num = REGNO_ANY;
+      hwcdef[idx].val = -1;
+      hwcdef[idx].sort_order = -1;
+    }
+}
+
+/* initialize hwcdef[] based on user's counter definitions */
+static int
+process_data_descriptor (const char *defstring)
+{
+  /*
+   * <defstring> format should be of format
+   *  :%s:%s:0x%x:%d:%lld:%d:%d:0x%x[,%s...repeat for each ctr]
+   * where the counter fields are:
+   *  :<userName>:<internalCtr>:<register>:<timeoutVal>[:m<min_time>]:<tag>:<timecvt>:<memop>
+   * See Coll_Ctrl::build_data_desc().
+   */
+  int err = 0;
+  char *ds = NULL;
+  char *dsp = NULL;
+  unsigned idx;
+
+  clear_hwcdefs ();
+  if (!defstring || !strlen (defstring))
+    {
+      err = HWCFUNCS_ERROR_HWCARGS;
+      goto ext_hw_install_end;
+    }
+  ds = strdup (defstring);
+  if (!ds)
+    {
+      err = HWCFUNCS_ERROR_HWCINIT;
+      goto ext_hw_install_end;
+    }
+  dsp = ds;
+
+  for (idx = 0; idx < MAX_PICS && *dsp; idx++)
+    {
+      char *name = NULL;
+      char *int_name = NULL;
+      regno_t reg = REGNO_ANY;
+      ABST_type memop = ABST_NONE;
+      int interval = 0;
+      int timecvt = 0;
+      unsigned sort_order = (unsigned) - 1;
+
+      /* name */
+      name = dsp;
+      dsp = strchr (dsp, ':');
+      if (dsp == NULL)
+       {
+         err = HWCFUNCS_ERROR_HWCARGS;
+         goto ext_hw_install_end;
+       }
+      *dsp++ = (char) 0;
+
+      /* int_name */
+      int_name = dsp;
+      dsp = strchr (dsp, ':');
+      if (dsp == NULL)
+       {
+         err = HWCFUNCS_ERROR_HWCARGS;
+         goto ext_hw_install_end;
+       }
+      *dsp++ = (char) 0;
+
+      /* reg_num */
+      reg = (int) strtol (dsp, &dsp, 0);
+      if (*dsp++ != ':')
+       {
+         err = HWCFUNCS_ERROR_HWCARGS;
+         goto ext_hw_install_end;
+       }
+      if (reg < 0 && reg != -1)
+       {
+         err = HWCFUNCS_ERROR_HWCARGS;
+         goto ext_hw_install_end;
+       }
+      if (reg >= 0)
+       hwcdef[idx].reg_num = reg;
+
+      /* val */
+      interval = (int) strtol (dsp, &dsp, 0);
+      if (*dsp++ != ':')
+       {
+         err = HWCFUNCS_ERROR_HWCARGS;
+         goto ext_hw_install_end;
+       }
+      if (interval < 0)
+       {
+         err = HWCFUNCS_ERROR_HWCARGS;
+         goto ext_hw_install_end;
+       }
+      hwcdef[idx].val = interval;
+
+      /* min_time */
+      /*
+       * This is a new field.
+       * An old launcher (dbx, etc.) would not include it.
+       * Detect the presence of the field by the char 'm'.
+       */
+      if (*dsp == 'm')
+       {
+         long long tmp_ll = 0;
+         dsp++;
+         tmp_ll = strtoll (dsp, &dsp, 0);
+         if (*dsp++ != ':')
+           {
+             err = HWCFUNCS_ERROR_HWCARGS;
+             goto ext_hw_install_end;
+           }
+         if (tmp_ll < 0)
+           {
+             err = HWCFUNCS_ERROR_HWCARGS;
+             goto ext_hw_install_end;
+           }
+         hwcdef[idx].min_time = tmp_ll;
+       }
+      else
+       hwcdef[idx].min_time = 0;
+
+      /* sort_order */
+      sort_order = (int) strtoul (dsp, &dsp, 0);
+      if (*dsp++ != ':')
+       {
+         err = HWCFUNCS_ERROR_HWCARGS;
+         goto ext_hw_install_end;
+       }
+      hwcdef[idx].sort_order = sort_order;
+
+      /* timecvt */
+      timecvt = (int) strtol (dsp, &dsp, 0);
+      if (*dsp++ != ':')
+       {
+         err = HWCFUNCS_ERROR_HWCARGS;
+         goto ext_hw_install_end;
+       }
+      hwcdef[idx].timecvt = timecvt;
+
+      /* memop */
+      memop = (ABST_type) strtol (dsp, &dsp, 0);
+      if (*dsp != 0 && *dsp++ != ',')
+       {
+         err = HWCFUNCS_ERROR_HWCARGS;
+         goto ext_hw_install_end;
+       }
+      hwcdef[idx].memop = memop;
+      if (*name)
+       hwcdef[idx].name = strdup (name);
+      else
+       hwcdef[idx].name = strdup (int_name);
+      if (*int_name)
+       hwcdef[idx].int_name = strdup (int_name);
+      else
+       hwcdef[idx].int_name = strdup (name);
+      ctrdefprint (DBG_LT1, "hwcfuncs: process_data_descriptor", &hwcdef[idx]);
+    }
+
+  if (*dsp)
+    {
+      TprintfT (DBG_LT0, "hwcfuncs: ERROR: process_data_descriptor(): "
+               "ctr string had some trailing garbage:"
+               " '%s'\n", dsp);
+      err = HWCFUNCS_ERROR_HWCARGS;
+      goto ext_hw_install_end;
+    }
+  free (ds);
+  hwcdef_cnt = idx;
+  return 0;
+
+ext_hw_install_end:
+  if (dsp && *dsp)
+    {
+      TprintfT (DBG_LT0, "hwcfuncs: ERROR: process_data_descriptor(): "
+               " syntax error just before:"
+               " '%s;\n", dsp);
+      logerr (GTXT ("Data descriptor syntax error near `%s'\n"), dsp);
+    }
+  else
+    logerr (GTXT ("Data descriptor syntax error\n"));
+  free (ds);
+  return err;
+}
+
+/* initialize hwcdef[] based on user's counter definitions */
+static int
+process_hwcentrylist (const Hwcentry* entries[], unsigned numctrs)
+{
+  int err = 0;
+  clear_hwcdefs ();
+  if (numctrs > cpcN_npics)
+    {
+      logerr (GTXT ("More than %d counters were specified\n"), cpcN_npics); /*!*/
+      return HWCFUNCS_ERROR_HWCARGS;
+    }
+  for (unsigned idx = 0; idx < numctrs; idx++)
+    {
+      Hwcentry *phwcdef = &hwcdef[idx];
+      *phwcdef = *entries[idx];
+      if (phwcdef->name)
+       phwcdef->name = strdup (phwcdef->name);
+      else
+       phwcdef->name = "NULL";
+      if (phwcdef->int_name)
+       phwcdef->int_name = strdup (phwcdef->int_name);
+      else
+       phwcdef->int_name = "NULL";
+      if (phwcdef->val < 0)
+       {
+         logerr (GTXT ("Negative interval specified for HW counter `%s'\n"), /*!*/
+                 phwcdef->name);
+         err = HWCFUNCS_ERROR_HWCARGS;
+         break;
+       }
+      ctrdefprint (DBG_LT1, "hwcfuncs: process_hwcentrylist", phwcdef);
+    }
+  if (!err)
+    hwcdef_cnt = numctrs;
+  return err;
+}
+
+/* see hwcfuncs.h */
+IS_GLOBAL void *
+hwcfuncs_parse_attrs (const char *countername, hwcfuncs_attr_t attrs[],
+                     unsigned max_attrs, uint_t *pnum_attrs, char**errstring)
+{
+  char *head = NULL;
+  char *tail = NULL;
+  uint_t nattrs = 0;
+  char *counter_copy;
+  int success = 0;
+  char errbuf[512];
+  errbuf[0] = 0;
+  counter_copy = strdup (countername);
+
+  /* advance pointer to first attribute */
+  tail = strchr (counter_copy, HWCFUNCS_PARSE_ATTR);
+  if (tail)
+    *tail = 0;
+
+  /* remove regno and value, if supplied */
+  {
+    char *tmp = strchr (counter_copy, HWCFUNCS_PARSE_REGNUM);
+    if (tmp)
+      *tmp = 0;
+    tmp = strchr (counter_copy, HWCFUNCS_PARSE_VALUE);
+    if (tmp)
+      *tmp = 0;
+  }
+
+  while (tail)
+    {
+      char *pch;
+      if (nattrs >= max_attrs)
+       {
+         snprintf (errbuf, sizeof (errbuf),
+                   GTXT ("Too many attributes defined in `%s'"),
+                   countername);
+         goto mycpc2_parse_attrs_end;
+       }
+      /* get attribute name */
+      head = tail + 1;
+      tail = strchr (head, HWCFUNCS_PARSE_EQUAL);
+      if (!tail)
+       {
+         snprintf (errbuf, sizeof (errbuf),
+                   GTXT ("Missing value for attribute `%s' in `%s'"),
+                   head, countername);
+         goto mycpc2_parse_attrs_end;
+       }
+      *tail = 0; /* null terminate current component */
+      attrs[nattrs].ca_name = head;
+
+      /* get attribute value */
+      head = tail + 1;
+      tail = strchr (head, HWCFUNCS_PARSE_ATTR);
+      if (tail)
+       *tail = 0; /* null terminate current component */
+      attrs[nattrs].ca_val = strtoull (head, &pch, 0);
+      if (pch == head)
+       {
+         snprintf (errbuf, sizeof (errbuf),
+                   GTXT ("Illegal value for attribute `%s' in `%s'"),
+                   attrs[nattrs].ca_name, countername);
+         goto mycpc2_parse_attrs_end;
+       }
+      TprintfT (DBG_LT0, "hwcfuncs: pic_: '%s', attribute[%u]"
+               " '%s' = 0x%llx\n",
+               counter_copy, nattrs, attrs[nattrs].ca_name,
+               (long long unsigned int) attrs[nattrs].ca_val);
+
+      nattrs++;
+    }
+  success = 1;
+
+mycpc2_parse_attrs_end:
+  *pnum_attrs = nattrs;
+  if (success)
+    {
+      if (errstring)
+       *errstring = NULL;
+    }
+  else
+    {
+      if (errstring)
+       *errstring = strdup (errbuf);
+      free (counter_copy);
+      counter_copy = NULL;
+    }
+  return counter_copy;
+}
+
+IS_GLOBAL void
+hwcfuncs_parse_ctr (const char *counter_def, int *pplus, char **pnameOnly,
+                   char **pattrs, char **pregstr, regno_t *pregno)
+{
+  char *nameptr, *copy, *slash, *attr_delim;
+  int plus;
+  regno_t regno;
+  nameptr = copy = strdup (counter_def);
+
+  /* plus */
+  plus = 0;
+  if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK)
+    {
+      plus = 1;
+      nameptr++;
+    }
+  else if (nameptr[0] == HWCFUNCS_PARSE_BACKTRACK_OFF)
+    {
+      plus = -1;
+      nameptr++;
+    }
+  if (pplus)
+    *pplus = plus;
+
+  /* regno */
+  regno = REGNO_ANY;
+  if (pregstr)
+    *pregstr = NULL;
+  slash = strchr (nameptr, HWCFUNCS_PARSE_REGNUM);
+  if (slash != NULL)
+    {
+      /* the remaining string should be a number > 0 */
+      if (pregstr)
+       *pregstr = strdup (slash);
+      char *endchar = NULL;
+      regno = (regno_t) strtol (slash + 1, &endchar, 0);
+      if (*endchar != 0)
+       regno = -2;
+      if (*(slash + 1) == '-')
+       regno = -2;
+      /* terminate previous element up to slash */
+      *slash = 0;
+    }
+  if (pregno)
+    *pregno = regno;
+
+  /* attrs */
+  if (pattrs)
+    *pattrs = NULL;
+  attr_delim = strchr (nameptr, HWCFUNCS_PARSE_ATTR);
+  if (attr_delim != NULL)
+    {
+      if (pattrs)
+       *pattrs = strdup (attr_delim);
+      /* terminate previous element up to attr_delim */
+      *attr_delim++ = 0;
+    }
+  if (pnameOnly)
+    *pnameOnly = strdup (nameptr);
+  free (copy);
+}
+
+/* create counters */
+IS_GLOBAL int
+hwcfuncs_bind_descriptor (const char *defstring)
+{
+  int err = process_data_descriptor (defstring);
+  if (err)
+    {
+      TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_descriptor failed\n");
+      return err;
+    }
+  err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
+  return err;
+}
+
+/* see hwcfuncs.h */
+IS_GLOBAL int
+hwcfuncs_bind_hwcentry (const Hwcentry* entries[], unsigned numctrs)
+{
+  int err = -1;
+  err = process_hwcentrylist (entries, numctrs);
+  if (err)
+    {
+      TprintfT (DBG_LT0, "hwcfuncs: ERROR: hwcfuncs_bind_hwcentry\n");
+      return err;
+    }
+  err = hwcdrv_driver->hwcdrv_create_counters (hwcdef_cnt, hwcdef);
+  return err;
+}
+
+/* see hwcfuncs.h */
+IS_GLOBAL Hwcentry **
+hwcfuncs_get_ctrs (unsigned *defcnt)
+{
+  if (defcnt)
+    *defcnt = hwcdef_cnt;
+  return hwctable;
+}
+
+/* return 1 if <regno> is in Hwcentry's list */
+IS_GLOBAL int
+regno_is_valid (const Hwcentry * pctr, regno_t regno)
+{
+  regno_t *reg_list = pctr->reg_list;
+  if (REG_LIST_IS_EMPTY (reg_list))
+    return 0;
+  if (regno == REGNO_ANY)   /* wildcard */
+    return 1;
+  for (int ii = 0; ii < MAX_PICS; ii++)
+    {
+      regno_t tmp = reg_list[ii];
+      if (REG_LIST_EOL (tmp))   /* end of list */
+       break;
+      if (tmp == regno)     /* is in list */
+       return 1;
+    }
+  return 0;
+}
+
+/* supplied by hwcdrv_api drivers */
+IS_GLOBAL int
+hwcfuncs_assign_regnos (Hwcentry* entries[],
+                       unsigned numctrs)
+{
+  if (numctrs > cpcN_npics)
+    {
+      logerr (GTXT ("More than %d counters were specified\n"), cpcN_npics); /*!*/
+      return HWCFUNCS_ERROR_HWCARGS;
+    }
+  return hwcdrv_driver->hwcdrv_assign_regnos (entries, numctrs);
+}
+
+extern hwcdrv_api_t hwcdrv_pcl_api;
+static int hwcdrv_driver_inited = 0;
+
+hwcdrv_api_t *
+get_hwcdrv ()
+{
+  if (hwcdrv_driver_inited)
+    return hwcdrv_driver;
+  hwcdrv_driver_inited = 1;
+  cpcN_npics = 0;
+  for (int i = 0; i < MAX_PICS; i++)
+    hwctable[i] = &hwcdef[i];
+  hwcdrv_driver = &hwcdrv_pcl_api;
+  hwcdrv_driver->hwcdrv_init_status = hwcdrv_driver->hwcdrv_init (NULL, NULL);
+  if (hwcdrv_driver->hwcdrv_init_status == 0)
+    {
+      hwcdrv_driver->hwcdrv_get_info (NULL, NULL, &cpcN_npics, NULL, NULL);
+      return hwcdrv_driver;
+    }
+  hwcdrv_driver = &hwcdrv_default;
+  return hwcdrv_driver;
+}
diff --git a/gprofng/common/hwcfuncs.h b/gprofng/common/hwcfuncs.h
new file mode 100644 (file)
index 0000000..ef0360b
--- /dev/null
@@ -0,0 +1,269 @@
+/* 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 */
+
+#ifndef __HWCFUNCS_H
+#define __HWCFUNCS_H
+
+#ifdef LIBCOLLECTOR_SRC /* running in libcollector */
+#define hwcfuncs_int_logerr         __collector_hwcfuncs_int_logerr
+#define hwcfuncs_parse_ctr          __collector_hwcfuncs_parse_ctr
+#define hwcfuncs_parse_attrs        __collector_hwcfuncs_parse_attrs
+#define hwcfuncs_bind_descriptor    __collector_hwcfuncs_bind_descriptor
+#define hwcfuncs_bind_hwcentry      __collector_hwcfuncs_bind_hwcentry
+#define hwcfuncs_assign_regnos      __collector_hwcfuncs_assign_regnos
+#define regno_is_valid              __collector_regno_is_valid
+#define hwcfuncs_get_ctrs           __collector_hwcfuncs_get_ctrs
+#define hwcfuncs_errmsg_get         __collector_hwcfuncs_errmsg_get
+#endif  /* --- LIBCOLLECTOR_SRC --- */
+
+#include <signal.h>     /* siginfo_t */
+#include <limits.h>     /* UINT64_t */
+#include <sys/types.h>
+#include <stdint.h>
+
+#include "hwcentry.h"   /* for Hwcentry type */
+#include "gp-time.h"
+
+typedef unsigned int uint_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* compile options */
+
+#define HWC_DEBUG   0 /* 0/1 to enable extra HWC debug */
+
+/*---------------------------------------------------------------------------*/
+/* typedefs */
+/* generic hw event */
+  typedef struct _hwc_event_t
+  { /* generalized counter event */
+    hrtime_t ce_hrt;            /* gethrtime() */
+    uint64_t ce_pic[MAX_PICS];  /* counter samples or start values */
+  } hwc_event_t;
+
+  /* supplementary data that accompanies some hw events */
+  typedef struct
+  { /* supplementary data fields */
+    uint64_t smpl_pc;           /* pc related to event */
+    uint64_t smpl_data_source;  /* chip-specific data source encoding */
+    uint64_t smpl_latency;      /* latency related to event */
+    uint64_t smpl_mem_addr;     /* memory address related to event */
+  } hwc_sample_t;
+#define HWCFUNCS_INVALID_U64 0xFEEDBEEFDEADBEEFllu /* identifies fields as unused */
+
+typedef struct {                                /* supplementary data fields */
+    hwc_sample_t sample[MAX_PICS];  /* counter samples or start values */
+} hwc_event_samples_t;
+
+#define HWCFUNCS_SAMPLE_RESET(sample) \
+       do { \
+           (sample)->smpl_pc          =HWCFUNCS_INVALID_U64; \
+           (sample)->smpl_data_source =HWCFUNCS_INVALID_U64; \
+           (sample)->smpl_latency     =HWCFUNCS_INVALID_U64; \
+           (sample)->smpl_mem_addr    =HWCFUNCS_INVALID_U64; \
+       } while(0)
+
+#define HWCFUNCS_SAMPLE_IS_RESET(sample) \
+       ( \
+           (sample)->smpl_pc         ==HWCFUNCS_INVALID_U64 && \
+           (sample)->smpl_data_source==HWCFUNCS_INVALID_U64 && \
+           (sample)->smpl_latency    ==HWCFUNCS_INVALID_U64 && \
+           (sample)->smpl_mem_addr   ==HWCFUNCS_INVALID_U64 \
+       )
+
+/*---------------------------------------------------------------------------*/
+/* macros */
+
+#define HW_INTERVAL_MAX         UINT64_MAX
+#define HW_INTERVAL_PRESET(x)   (HW_INTERVAL_MAX - ((uint64_t)(x) - 1))
+#define HW_INTERVAL_TYPE(x)     ((uint64_t) (x)
+
+/* parsing */
+#define HWCFUNCS_MAX_ATTRS              20
+#define HWCFUNCS_PARSE_ATTR             '~'
+#define HWCFUNCS_PARSE_EQUAL            '='
+#define HWCFUNCS_PARSE_BACKTRACK        '+'
+#define HWCFUNCS_PARSE_BACKTRACK_OFF    '-'
+#define HWCFUNCS_PARSE_REGNUM           '/'
+#define HWCFUNCS_PARSE_VALUE            ','
+
+/* error codes */
+#define HWCFUNCS_ERROR_GENERIC          (-1)
+#define HWCFUNCS_ERROR_NOT_SUPPORTED    (-2)
+#define HWCFUNCS_ERROR_ALREADY_CALLED   (-3)
+#define HWCFUNCS_ERROR_HWCINIT          (-4)
+#define HWCFUNCS_ERROR_HWCARGS          (-5)
+#define HWCFUNCS_ERROR_MEMORY           (-6)
+#define HWCFUNCS_ERROR_UNAVAIL          (-7)
+#define HWCFUNCS_ERROR_ERRNO_ZERO       (-8)
+#define HWCFUNCS_ERROR_UNEXPECTED       (-99)
+
+/*---------------------------------------------------------------------------*/
+/* prototypes */
+
+typedef void (*hwcfuncs_abort_fn_t) (int errnum, const char *msg);
+
+extern void hwcfuncs_int_logerr(const char *format,...);
+/* Log an error to the internal error buffer. See hwcfuncs_errmsg_get().
+     Note: Not MT-safe; don't even enable logging in an MT environment.
+       Recommend using this call only during init.
+     Note: when a libcpc call fails, it may automatically call
+       cpcN_capture_errmsg() to log the error message in the same internal buffer.
+       Recommend using this call only for non-cpc failures.
+ */
+
+#define HWCFUNCS_SUPPORT_OVERFLOW_PROFILING 0x01llu
+#define HWCFUNCS_SUPPORT_PEBS_SAMPLING      0x02llu
+#define HWCFUNCS_SUPPORT_OVERFLOW_CTR_ID    0x04llu // OS identifies which counter overflowed
+  /* get info about session
+     Input:
+       <cpuver>: if not NULL, returns value of CPC cpu version
+       <cciname>: if not NULL, returns name of CPU
+       <npics>: if not NULL, returns maximum # of HWCs
+       <docref>: if not NULL, returns documentation reference
+       <support>: if not NULL, returns bitmask (see above) of hwc support
+     Return: none
+   */
+
+  typedef void* (*hwcfuncs_tsd_get_fn_t) (void);
+  typedef void (hwcf_hwc_cb_t) (uint_t cpcregno, const char *name);
+  typedef void (hwcf_attr_cb_t) (const char *attr);
+
+  extern void
+  hwcfuncs_parse_ctr (const char *counter_def, int *pplus, char **pnameOnly,
+                     char **pattrs, char **pregstr, regno_t *pregno);
+/* Parse a counter definition string (value must already be stripped off).
+     Input:
+       <counter_def>: input whose format is
+        [+|-]<countername>[~attrs...][/<regno>]
+       pointers to return values:  Any can be NULL.
+     Return:
+       <plus>: 1 if [+] is found, -1 if [-] is found, 0 otherwise
+       <pnameonly>: strdup(<countername>)
+       <pattrs>: strdup([~attrs...]) if specified, NULL otherwise.
+       <pregstr>: strdup(/<regno>) if specified, NULL otherwise.
+       <pregno>: <regno> if readable, REGNO_ANY if not specd, or -2 otherwise.
+   */
+
+  typedef struct
+  {
+    char *ca_name;
+    uint64_t ca_val;
+  } hwcfuncs_attr_t; /* matches cpc_attr_t */
+
+  void * hwcfuncs_parse_attrs (const char *countername,
+                              hwcfuncs_attr_t attrs[], unsigned max_attrs,
+                              uint_t *pnum_attrs, char **errstring);
+  /* Extract the attribute fields from <countername>.
+       Input:
+        <countername>: string whose format is
+           [+]<ctrname>[~attributes...][/<regno>][,...]
+        <attrs>: array of attributes to be returned
+        <max_attrs>: number of elements in <attrs>
+        <pnum_attrs>: if not NULL, will return how many attrs were found.
+        <errstring>: pointer to a buffer for storing error info, or NULL.
+       Return: upon success, a pointer to an allocated copy of <countername>, or
+          NULL if there's a failure.  (A copy is made in order to provide storage
+          for the ca_name fields in the <attrs> array.)
+
+          The pointer should be freed when <attrs> is no longer in use.
+          <attrs> will be filled in data from countername.
+        <pnum_attrs> will have the number of elements in <attrs>.  May be
+          non-zero even if return value indicates an error.
+        <errstring> NULL if no error, otherwise, a malloc'd GTXT string.
+   */
+
+  extern int hwcfuncs_bind_descriptor (const char *defstring);
+  /* Bind counters to resources.
+     Input:
+       <defstring>: string whose format is
+         :%s:%s:0x%x:%d:%d,0x%x[:%s...repeat for each ctr]
+        where the fields are:
+         :<userName>:<internalCtr>:<register>:<timeoutVal>:<tag>:<memop>
+     Return: 0 if successful
+       HWCFUNCS_ERROR_HWCINIT if resources unavailable
+       HWCFUNCS_ERROR_HWCARGS if counters were not specified correctly
+   */
+
+  extern int hwcfuncs_bind_hwcentry (const Hwcentry *entries[],
+                                    unsigned numctrs);
+  /* Bind counters to resources.
+     Input:
+       <entries>: array of counters
+       <numctrs>: number of items in <entries>
+     Return: 0 if successful
+       HWCFUNCS_ERROR_HWCINIT if resources unavailable
+       HWCFUNCS_ERROR_HWCARGS if counters were not specified correctly
+   */
+
+  extern int hwcfuncs_assign_regnos (Hwcentry *entries[], unsigned numctrs);
+  /* Assign entries[]->reg_num values as needed by platform
+       Note: modifies <entries> by supplying a regno to each counter
+     Input:
+       <entries>: array of counters
+       <numctrs>: number of items in <entries>
+     Output:
+       <entries>: array of counters is modified
+     Return: 0 if successful
+       HWCFUNCS_ERROR_HWCINIT if resources unavailable
+       HWCFUNCS_ERROR_HWCARGS if counters were not specified correctly
+   */
+
+  extern int regno_is_valid (const Hwcentry *pctr, regno_t regno);
+  /* return 1 if <regno> is in Hwcentry's list
+     Input:
+       <pctr>: counter definition, reg_list[] should be initialized
+       <regno>: register to check
+     Return: 1 if <regno> is in Hwcentry's list, 0 otherwise
+   */
+
+  extern Hwcentry **hwcfuncs_get_ctrs (unsigned *defcnt);
+  /* Get descriptions of the currently bound counters.
+     Input:
+       <defcnt>: if not NULL, returns number of counter definitions.
+     Return:
+       table of counter definition pointers
+   */
+
+  extern char *hwcfuncs_errmsg_get (char * buf, size_t bufsize,
+                                   int enable_capture);
+  /* Gets a recent HWC error message.
+       To clear previous error messages and insure error message is enabled,
+       call hwcfuncs_errmsg_get(NULL,0,1).
+       Once enabled, one error is stored in an internal buffer.  A call to this
+       function will clear the buffer and allow a new message to be captured.
+       Note: Not MT-safe - don't enable this feature in an MT environment.
+     Input:
+       <buf>: pointer to buffer or NULL.
+       <bufsize>: size of <buf>
+       <enable_capture>: 0 - disable buffering, 1 - enable buffering.
+     Return: error string or an empty string.
+   */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ! __HWCFUNCS_H */
diff --git a/gprofng/common/hwctable.c b/gprofng/common/hwctable.c
new file mode 100644 (file)
index 0000000..bc441e1
--- /dev/null
@@ -0,0 +1,5410 @@
+/* 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 <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+
+#include "hwcdrv.h"
+#include "hwcfuncs.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
+
+/*---------------------------------------------------------------------------*/
+/* compile options */
+
+#define DISALLOW_USI_USII_6357446
+/* Solaris 9/libcpc1 allows cpc_bind() to work on US-IIe processors, even
+   though this processor cannot generate profiling interrupts. */
+
+#define DISALLOW_PENTIUM_PRO_MMX_7007575
+/* Solaris/libcpc2 defaults to "Pentium Pro with MMX, Pentium II"
+   when it doesn't recognize an Intel processor.  As a result,
+   when collect attempts to start Pentium Pro counters on a
+   new machine (e.g. Westmere as of 1/2011), the OS may hang.  */
+
+/* Register 0 counter doesn't work on Niagara T1 version (?) */
+#define WORKAROUND_6231196_NIAGARA1_NO_CTR_0
+
+/*---------------------------------------------------------------------------*/
+/* consts, macros */
+
+/* 10^N rates */
+#define PRELOADS_9      1001000001
+#define PRELOADS_85      320100001
+#define PRELOADS_8       100100001
+#define PRELOADS_75       32010001
+#define PRELOADS_7        10010001
+#define PRELOADS_65        3201001
+#define PRELOADS_6         1001001
+#define PRELOADS_55         320101
+#define PRELOADS_5          100101
+#define PRELOADS_45          32001
+#define PRELOADS_4           10001
+#define PRELOADS_35           3201
+#define PRELOADS_3            1001
+#define PRELOADS_25            301
+
+#define ABST_TBD        ABST_NONE /* to be determined */
+
+/*---------------------------------------------------------------------------*/
+/* prototypes */
+static void hwc_cb (uint_t cpc_regno, const char *name);
+static void attrs_cb (const char *attr);
+static int attr_is_valid (int forKernel, const char *attr);
+
+/*---------------------------------------------------------------------------*/
+/* HWC definition tables */
+
+/*
+  comments on hwcentry tables
+  ---------------------------
+  name:          this field should not contain '~'.
+  int_name:      actual name of register, may contain ~ attribute specifications.
+  regnum:        assigned register.
+  metric:        if non-NULL, is a 'standard' counter that will show up in help.
+  timecvt:       >0: can convert to time, 'timecvt' CPU cycles per event
+                =0: counts events
+                <0: can convert to time, count reference-clock cycles at '-timecvt' MHz
+  memop:         see description for ABST_type enum
+ */
+
+// PRELOAD(): generates an interval based on the cycles/event and CPU GHZ.
+// Note: the macro tweaks the interval so that it ends in decimal 001.
+#define CYC_PER_SAMPLE (1000ULL*1000*1000/100) // cycles per signal at 1ghz, 100 samples/second
+#define PRELOAD(min_cycles_per_event,ghz) (((ghz)*CYC_PER_SAMPLE/(min_cycles_per_event))/100*100+1)
+
+// PRELOAD_DEF: initial value for uncalibrated events.
+// This value should be based on a rate that will work for the slowest changing
+// HWCs, HWCs where there are many CPU cycles between events.
+//
+// The interval needs to target the slowest HWCs so that
+// automatic adjustment of HWC overflow intervals can adapt.
+#define PRELOAD_DEF PRELOAD(1000,3)  // default interval targets 1000 cycles/event at 3ghz
+// For er_kernel, which HWC intervals cannot be adjusted automatically for ON/HI/LO,
+// The interval should target some safe interval for fast events
+#define PRELOAD_DEF_ERKERNEL PRELOAD(4,4)  // default interval targets 4 cycles/event at 4ghz
+
+static const Hwcentry empty_ctr = {NULL, NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, 0};
+
+
+// --- use cycles counter to expose "system_time" on Linux ---
+#define SYSTIME_REGNOS REGNO_ANY // Linux: make sys_time/usr_time available for data collection
+// Note: For x86, Linux and Solaris use different ref-clock names
+#define USE_INTEL_REF_CYCLES(MHZ) \
+    {"usr_time","unhalted-reference-cycles",                SYSTIME_REGNOS, STXT("User CPU"),   PRELOAD(900,MHZ),  -(MHZ), ABST_NONE}, \
+    {"usr_time","cpu_clk_unhalted.ref_p",                   SYSTIME_REGNOS, STXT("User CPU"),   PRELOAD(900,MHZ),  -(MHZ), ABST_NONE}, \
+    {"sys_time","unhalted-reference-cycles~system=1~user=0", SYSTIME_REGNOS, STXT("System CPU"), PRELOAD(900,MHZ), -(MHZ), ABST_NONE}, \
+    {"sys_time","cpu_clk_unhalted.ref_p~system=1~user=0",   SYSTIME_REGNOS, STXT("System CPU"), PRELOAD( 900,MHZ), -(MHZ), ABST_NONE}, \
+    {"cycles0",        "unhalted-reference-cycles",                0,  NULL,   PRELOAD( 900,MHZ),  -(MHZ), ABST_NONE}, /*hidden*/ \
+    {"cycles0",        "cpu_clk_unhalted.ref_p",                   0,  NULL,   PRELOAD( 900,MHZ),  -(MHZ), ABST_NONE}, /*hidden*/ \
+    {"cycles1",        "unhalted-reference-cycles",                1,  NULL,   PRELOAD( 910,MHZ),  -(MHZ), ABST_NONE}, /*hidden*/ \
+    {"cycles1",        "cpu_clk_unhalted.ref_p",                   1,  NULL,   PRELOAD( 910,MHZ),  -(MHZ), ABST_NONE}, /*hidden*/ \
+    /* end of list */
+
+#define SPARC_CYCLES \
+    {"usr_time","Cycles_user",                  SYSTIME_REGNOS, STXT("User CPU"),   PRELOADS_75,1, ABST_NONE}, \
+    {"sys_time","Cycles_user~system=1~user=0",  SYSTIME_REGNOS, STXT("System CPU"), PRELOADS_75,1, ABST_NONE}, \
+    /* end of list */
+
+
+/* --- PERF_EVENTS "software" definitions --- */
+#define PERF_EVENTS_SW_EVENT_ALIASES \
+// none supported for now
+#if 0
+    {"usr",            "PERF_COUNT_SW_TASK_CLOCK",                     REGNO_ANY, STXT("User CPU"),                    PRELOADS_7, -(1000), ABST_NONE}, \
+    {"sys",            "PERF_COUNT_SW_TASK_CLOCK~system=1~user=0",     REGNO_ANY, STXT("System CPU"),                  PRELOADS_7, -(1000), ABST_NONE}, \
+    /* end of list */
+#endif
+
+#define PERF_EVENTS_SW_EVENT_DEFS \
+// none supported for now
+#if 0
+    {"PERF_COUNT_SW_TASK_CLOCK",                                       NULL, REGNO_ANY, NULL, PRELOADS_7, -(1000),ABST_NONE}, \
+    /* end of list */
+#endif
+
+/*
+ * The PAPI descriptive strings used to be wrapped with STXT(),
+ * a macro defined in perfan/include/i18n.h.  For the time being,
+ * we want to demote the PAPI counters by omitting the
+ * descriptions.  So we use a new macro PAPITXT() for this purpose.
+ */
+#define PAPITXT(x)  NULL
+
+/* Solaris "Generic" Counters */
+static Hwcentry papi_generic_list[] = {
+  {"PAPI_l1_dcm", NULL, REGNO_ANY, PAPITXT ("L1 D-cache misses"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l1_icm", NULL, REGNO_ANY, PAPITXT ("L1 I-cache misses"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l2_dcm", NULL, REGNO_ANY, PAPITXT ("L2 D-cache misses"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l2_icm", NULL, REGNO_ANY, PAPITXT ("L2 I-cache misses"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l3_dcm", NULL, REGNO_ANY, PAPITXT ("L3 D-cache misses"), PRELOADS_5, 0, ABST_NONE},
+  {"PAPI_l3_icm", NULL, REGNO_ANY, PAPITXT ("L3 I-cache misses"), PRELOADS_5, 0, ABST_NONE},
+  {"PAPI_l1_tcm", NULL, REGNO_ANY, PAPITXT ("L1 misses"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l2_tcm", NULL, REGNO_ANY, PAPITXT ("L2 misses"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l3_tcm", NULL, REGNO_ANY, PAPITXT ("L3 misses"), PRELOADS_5, 0, ABST_NONE},
+  {"PAPI_ca_snp", NULL, REGNO_ANY, PAPITXT ("Requests for a snoop"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_ca_shr", NULL, REGNO_ANY, PAPITXT ("Requests for exclusive access to shared cache line"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_ca_cln", NULL, REGNO_ANY, PAPITXT ("Requests for exclusive access to clean cache line"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_ca_inv", NULL, REGNO_ANY, PAPITXT ("Requests for cache line invalidation"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_ca_itv", NULL, REGNO_ANY, PAPITXT ("Requests for cache line intervention"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l3_ldm", NULL, REGNO_ANY, PAPITXT ("L3 load misses"), PRELOADS_5, 0, ABST_NONE},
+  {"PAPI_l3_stm", NULL, REGNO_ANY, PAPITXT ("L3 store misses"), PRELOADS_5, 0, ABST_NONE},
+  {"PAPI_bru_idl", NULL, REGNO_ANY, PAPITXT ("Cycles branch units are idle"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_fxu_idl", NULL, REGNO_ANY, PAPITXT ("Cycles integer units are idle"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_fpu_idl", NULL, REGNO_ANY, PAPITXT ("Cycles FP units are idle"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_lsu_idl", NULL, REGNO_ANY, PAPITXT ("Cycles load/store units are idle"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_tlb_dm", NULL, REGNO_ANY, PAPITXT ("DTLB misses"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_tlb_im", NULL, REGNO_ANY, PAPITXT ("ITLB misses"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_tlb_tl", NULL, REGNO_ANY, PAPITXT ("Total TLB misses"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_tlb_tm", NULL, REGNO_ANY, PAPITXT ("Total TLB misses"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l1_ldm", NULL, REGNO_ANY, PAPITXT ("L1 load misses"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l1_stm", NULL, REGNO_ANY, PAPITXT ("L1 store misses"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l2_ldm", NULL, REGNO_ANY, PAPITXT ("L2 load misses"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l2_stm", NULL, REGNO_ANY, PAPITXT ("L2 store misses"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_btac_m", NULL, REGNO_ANY, PAPITXT ("Branch target address cache misses"), PRELOADS_5, 0, ABST_NONE},
+  {"PAPI_prf_dm", NULL, REGNO_ANY, PAPITXT ("Data prefetch cache misses"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l3_dch", NULL, REGNO_ANY, PAPITXT ("L3 D-cache hits"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_tlb_sd", NULL, REGNO_ANY, PAPITXT ("TLB shootdowns"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_csr_fal", NULL, REGNO_ANY, PAPITXT ("Failed store conditional instructions"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_csr_suc", NULL, REGNO_ANY, PAPITXT ("Successful store conditional instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_csr_tot", NULL, REGNO_ANY, PAPITXT ("Total store conditional instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_mem_scy", NULL, REGNO_ANY, PAPITXT ("Cycles Stalled Waiting for memory accesses"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_mem_rcy", NULL, REGNO_ANY, PAPITXT ("Cycles Stalled Waiting for memory reads"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_mem_wcy", NULL, REGNO_ANY, PAPITXT ("Cycles Stalled Waiting for memory writes"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_stl_icy", NULL, REGNO_ANY, PAPITXT ("Cycles with no instruction issue"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_ful_icy", NULL, REGNO_ANY, PAPITXT ("Cycles with maximum instruction issue"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_stl_ccy", NULL, REGNO_ANY, PAPITXT ("Cycles with no instructions completed"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_ful_ccy", NULL, REGNO_ANY, PAPITXT ("Cycles with maximum instructions completed"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_hw_int", NULL, REGNO_ANY, PAPITXT ("Hardware interrupts"), PRELOADS_5, 0, ABST_NONE},
+  {"PAPI_br_ucn", NULL, REGNO_ANY, PAPITXT ("Unconditional branch instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_br_cn", NULL, REGNO_ANY, PAPITXT ("Cond. branch instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_br_tkn", NULL, REGNO_ANY, PAPITXT ("Cond. branch instructions taken"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_br_ntk", NULL, REGNO_ANY, PAPITXT ("Cond. branch instructions not taken"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_br_msp", NULL, REGNO_ANY, PAPITXT ("Cond. branch instructions mispredicted"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_br_prc", NULL, REGNO_ANY, PAPITXT ("Cond. branch instructions correctly predicted"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_fma_ins", NULL, REGNO_ANY, PAPITXT ("FMA instructions completed"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_tot_iis", NULL, REGNO_ANY, PAPITXT ("Instructions issued"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_tot_ins", NULL, REGNO_ANY, PAPITXT ("Instructions completed"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_int_ins", NULL, REGNO_ANY, PAPITXT ("Integer instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_fp_ins", NULL, REGNO_ANY, PAPITXT ("Floating-point instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_ld_ins", NULL, REGNO_ANY, PAPITXT ("Load instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_sr_ins", NULL, REGNO_ANY, PAPITXT ("Store instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_br_ins", NULL, REGNO_ANY, PAPITXT ("Branch instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_vec_ins", NULL, REGNO_ANY, PAPITXT ("Vector/SIMD instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_res_stl", NULL, REGNO_ANY, PAPITXT ("Cycles stalled on any resource"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_fp_stal", NULL, REGNO_ANY, PAPITXT ("Cycles the FP unit(s) are stalled"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_tot_cyc", NULL, REGNO_ANY, PAPITXT ("Total cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"PAPI_lst_ins", NULL, REGNO_ANY, PAPITXT ("Load/store instructions completed"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_syc_ins", NULL, REGNO_ANY, PAPITXT ("Sync instructions completed"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l1_dch", NULL, REGNO_ANY, PAPITXT ("L1 D-cache hits"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_l2_dch", NULL, REGNO_ANY, PAPITXT ("L2 D-cache hits"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l1_dca", NULL, REGNO_ANY, PAPITXT ("L1 D-cache accesses"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_l2_dca", NULL, REGNO_ANY, PAPITXT ("L2 D-cache accesses"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l3_dca", NULL, REGNO_ANY, PAPITXT ("L3 D-cache accesses"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l1_dcr", NULL, REGNO_ANY, PAPITXT ("L1 D-cache reads"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_l2_dcr", NULL, REGNO_ANY, PAPITXT ("L2 D-cache reads"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l3_dcr", NULL, REGNO_ANY, PAPITXT ("L3 D-cache reads"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l1_dcw", NULL, REGNO_ANY, PAPITXT ("L1 D-cache writes"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_l2_dcw", NULL, REGNO_ANY, PAPITXT ("L2 D-cache writes"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l3_dcw", NULL, REGNO_ANY, PAPITXT ("L3 D-cache writes"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l1_ich", NULL, REGNO_ANY, PAPITXT ("L1 I-cache hits"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_l2_ich", NULL, REGNO_ANY, PAPITXT ("L2 I-cache hits"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l3_ich", NULL, REGNO_ANY, PAPITXT ("L3 I-cache hits"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l1_ica", NULL, REGNO_ANY, PAPITXT ("L1 I-cache accesses"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_l2_ica", NULL, REGNO_ANY, PAPITXT ("L2 I-cache accesses"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l3_ica", NULL, REGNO_ANY, PAPITXT ("L3 I-cache accesses"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l1_icr", NULL, REGNO_ANY, PAPITXT ("L1 I-cache reads"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_l2_icr", NULL, REGNO_ANY, PAPITXT ("L2 I-cache reads"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l3_icr", NULL, REGNO_ANY, PAPITXT ("L3 I-cache reads"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l1_icw", NULL, REGNO_ANY, PAPITXT ("L1 I-cache writes"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_l2_icw", NULL, REGNO_ANY, PAPITXT ("L2 I-cache writes"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l3_icw", NULL, REGNO_ANY, PAPITXT ("L3 I-cache writes"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l1_tch", NULL, REGNO_ANY, PAPITXT ("L1 total hits"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_l2_tch", NULL, REGNO_ANY, PAPITXT ("L2 total hits"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l3_tch", NULL, REGNO_ANY, PAPITXT ("L3 total hits"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l1_tca", NULL, REGNO_ANY, PAPITXT ("L1 total accesses"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_l2_tca", NULL, REGNO_ANY, PAPITXT ("L2 total accesses"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l3_tca", NULL, REGNO_ANY, PAPITXT ("L3 total accesses"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l1_tcr", NULL, REGNO_ANY, PAPITXT ("L1 total reads"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_l2_tcr", NULL, REGNO_ANY, PAPITXT ("L2 total reads"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l3_tcr", NULL, REGNO_ANY, PAPITXT ("L3 total reads"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_l1_tcw", NULL, REGNO_ANY, PAPITXT ("L1 total writes"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_l2_tcw", NULL, REGNO_ANY, PAPITXT ("L2 total writes"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_l3_tcw", NULL, REGNO_ANY, PAPITXT ("L3 total writes"), PRELOADS_6, 0, ABST_NONE},
+  {"PAPI_fml_ins", NULL, REGNO_ANY, PAPITXT ("FP multiply instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_fad_ins", NULL, REGNO_ANY, PAPITXT ("FP add instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_fdv_ins", NULL, REGNO_ANY, PAPITXT ("FP divide instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_fsq_ins", NULL, REGNO_ANY, PAPITXT ("FP square root instructions"), PRELOADS_65, 0, ABST_NONE},
+  {"PAPI_fnv_ins", NULL, REGNO_ANY, PAPITXT ("FP inverse instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"PAPI_fp_ops", NULL, REGNO_ANY, PAPITXT ("FP operations"), PRELOADS_7, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry usIlist[] = {
+  {"cycles", "Cycle_cnt", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"insts", "Instr_cnt", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_7, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry usIIIlist[] = /* III, IIIi, IIIp.  Note that some counters are processor-specific */{
+  {"cycles", "Cycle_cnt", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"insts", "Instr_cnt", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_7, 0, ABST_NONE},
+  {"icm", "IC_miss", REGNO_ANY, STXT ("I$ Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"dcrm", "DC_rd_miss", REGNO_ANY, STXT ("D$ Read Misses"), PRELOADS_5, 0, ABST_LOAD},
+  {"dcwm", "DC_wr_miss", REGNO_ANY, STXT ("D$ Write Misses"), PRELOADS_5, 0, ABST_STORE},
+  {"dcr", "DC_rd", REGNO_ANY, STXT ("D$ Read Refs"), PRELOADS_6, 0, ABST_LOAD},
+  {"dcw", "DC_wr", REGNO_ANY, STXT ("D$ Write Refs"), PRELOADS_6, 0, ABST_STORE},
+  {"ecref", "EC_ref", REGNO_ANY, STXT ("E$ Refs"), PRELOADS_6, 0, ABST_LDST},
+  {"itlbm", "ITLB_miss", REGNO_ANY, STXT ("ITLB Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"dtlbm", "DTLB_miss", REGNO_ANY, STXT ("DTLB Misses"), PRELOADS_5, 0, ABST_US_DTLBM},
+  {"ecm", "EC_misses", REGNO_ANY, STXT ("E$ Misses"), PRELOADS_5, 0, ABST_LDST},
+  {"ecrm", "EC_rd_miss", REGNO_ANY, STXT ("E$ Read Misses"), PRELOADS_5, 0, ABST_LOAD},
+  {"ecml", "EC_miss_local", REGNO_ANY, STXT ("E$ Local Misses"), PRELOADS_5, 0, ABST_LDST},
+  {"ecmr", "EC_miss_remote", REGNO_ANY, STXT ("E$ Remote Misses"), PRELOADS_5, 0, ABST_LDST},
+  {"ecim", "EC_ic_miss", REGNO_ANY, STXT ("E$ Instr. Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"icstall", "Dispatch0_IC_miss", REGNO_ANY, STXT ("I$ Stall Cycles"), PRELOADS_6, 1, ABST_NONE},
+  {"dcstall", "Re_DC_miss", REGNO_ANY, STXT ("D$ and E$ Stall Cycles"), PRELOADS_6, 1, ABST_LOAD},
+  {"ecstall", "Re_EC_miss", REGNO_ANY, STXT ("E$ Stall Cycles"), PRELOADS_6, 1, ABST_LOAD},
+  {"sqstall", "Rstall_storeQ", REGNO_ANY, STXT ("StoreQ Stall Cycles"), PRELOADS_6, 1, ABST_STORE},
+  {"rawstall", "Re_RAW_miss", REGNO_ANY, STXT ("RAW Stall Cycles"), PRELOADS_6, 1, ABST_LOAD},
+  {"dcmissov", "Re_DC_missovhd", REGNO_ANY, STXT ("DC Miss Ovhd"), PRELOADS_6, 1, ABST_LOAD},
+  {"fpustall", "Re_FPU_bypass", REGNO_ANY, STXT ("FPU Stall Cycles"), PRELOADS_6, 1, ABST_NONE},
+  {"fpusestall", "Rstall_FP_use", REGNO_ANY, STXT ("FPU Use Stall Cycles"), PRELOADS_6, 1, ABST_NONE},
+  {"iustall", "Rstall_IU_use", REGNO_ANY, STXT ("IU Stall Cycles"), PRELOADS_6, 1, ABST_NONE},
+  {"fpadd", "FA_pipe_completion", REGNO_ANY, STXT ("FP Adds"), PRELOADS_6, 0, ABST_NONE},
+  {"fpmul", "FM_pipe_completion", REGNO_ANY, STXT ("FP Muls"), PRELOADS_6, 0, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {"Cycle_cnt", NULL, REGNO_ANY, NULL, PRELOADS_7, 1, ABST_NONE},
+  {"EC_miss_mtag_remote", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST},
+  {"DC_rd_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"DC_wr_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"DC_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"DC_wr", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"EC_ref", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST},
+  {"EC_snoop_inv", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC /*?*/},
+  {"EC_wb", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"EC_wb_remote", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"DTLB_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_US_DTLBM},
+  {"EC_misses", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST},
+  {"EC_rd_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"PC_port0_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"EC_miss_local", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST},
+  {"EC_miss_remote", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST},
+  {"EC_snoop_cb", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC /*?*/},
+  {"WC_snoop_cb", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC /*?*/},
+  {"WC_scrubbed", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"WC_wb_wo_read", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"PC_MS_misses", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"PC_soft_hit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"PC_hard_hit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"PC_port1_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"PC_snoop_inv", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE /*?*/},
+  {"SW_count_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_COUNT},
+  {"SW_count_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_COUNT},
+  {"Dispatch0_IC_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Dispatch0_mispred", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Dispatch0_br_target", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Dispatch0_2nd_br", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Dispatch_rs_mispred", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Rstall_storeQ", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_STORE},
+  {"Rstall_FP_use", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Rstall_IU_use", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"EC_write_hit_RTO", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"Re_RAW_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_LOAD},
+  {"Re_DC_missovhd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_LOAD},
+  {"Re_endian_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_LOAD},
+  {"Re_FPU_bypass", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Re_DC_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_LOAD},
+  {"Re_EC_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_LOAD},
+  {"Re_PC_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_LOAD},
+  {"SI_snoop", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"SI_ciq_flow", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"SI_owned", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_msl_busy_stall", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NOPC},
+  {"MC_mdb_overflow_stall", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NOPC},
+  {"MC_page_close_stall", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NOPC},
+  {"MC_reads_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_reads_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_reads_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_reads_3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_writes_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_writes_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_writes_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_writes_3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_stalls_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NOPC},
+  {"MC_stalls_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NOPC},
+  {"MC_stalls_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NOPC},
+  {"MC_stalls_3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NOPC},
+
+  /* additional (hidden) aliases, for convenience */
+  {"cycles0", "Cycle_cnt", 0, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"cycles1", "Cycle_cnt", 1, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"insts0", "Instr_cnt", 0, NULL, PRELOADS_75, 0, ABST_NONE},
+  {"insts1", "Instr_cnt", 1, NULL, PRELOADS_75, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry usIVplist[] = {
+  {"cycles", "Cycle_cnt", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"insts", "Instr_cnt", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_7, 0, ABST_NONE},
+  {"icm", "IC_fill", REGNO_ANY, STXT ("I$ Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"dcrm", "DC_rd_miss", REGNO_ANY, STXT ("D$ Read Misses"), PRELOADS_5, 0, ABST_LOAD},
+  {"dcwm", "DC_wr_miss", REGNO_ANY, STXT ("D$ Write Misses"), PRELOADS_5, 0, ABST_STORE},
+  {"dcr", "DC_rd", REGNO_ANY, STXT ("D$ Read Refs"), PRELOADS_6, 0, ABST_LOAD},
+  {"dcw", "DC_wr", REGNO_ANY, STXT ("D$ Write Refs"), PRELOADS_6, 0, ABST_STORE},
+  {"itlbm", "ITLB_miss", REGNO_ANY, STXT ("ITLB Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"dtlbm", "DTLB_miss", REGNO_ANY, STXT ("DTLB Misses"), PRELOADS_5, 0, ABST_US_DTLBM},
+  {"l2ref", "L2_ref", REGNO_ANY, STXT ("L2$ Refs"), PRELOADS_5, 0, ABST_LDST},
+  {"l2m", "L2_miss", REGNO_ANY, STXT ("L2$ Misses"), PRELOADS_5, 0, ABST_LDST},
+  {"l2rm", "L2_rd_miss", REGNO_ANY, STXT ("L2$ Read Misses"), PRELOADS_5, 0, ABST_LOAD},
+  {"l2im", "L2_IC_miss", REGNO_ANY, STXT ("L2$ Instr. Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"ecm", "L3_miss", REGNO_ANY, STXT ("E$ Misses"), PRELOADS_5, 0, ABST_LDST},
+  {"ecrm", "L3_rd_miss", REGNO_ANY, STXT ("E$ Read Misses"), PRELOADS_5, 0, ABST_LOAD},
+  {"ecml", "SSM_L3_miss_local", REGNO_ANY, STXT ("E$ Local Misses"), PRELOADS_5, 0, ABST_LDST},
+  {"ecmr", "SSM_L3_miss_remote", REGNO_ANY, STXT ("E$ Remote Misses"), PRELOADS_5, 0, ABST_LDST},
+  {"ecim", "L3_IC_miss", REGNO_ANY, STXT ("E$ Instr. Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"icstall", "Dispatch0_IC_miss", REGNO_ANY, STXT ("I$ Stall Cycles"), PRELOADS_6, 1, ABST_NONE},
+  {"dcstall", "Re_DC_miss", REGNO_ANY, STXT ("D$ and E$ Stall Cycles"), PRELOADS_6, 1, ABST_LOAD},
+  {"ecstall", "Re_L3_miss", REGNO_ANY, STXT ("E$ Stall Cycles"), PRELOADS_6, 1, ABST_LOAD},
+  {"sqstall", "Rstall_storeQ", REGNO_ANY, STXT ("StoreQ Stall Cycles"), PRELOADS_6, 1, ABST_STORE},
+  {"rawstall", "Re_RAW_miss", REGNO_ANY, STXT ("RAW Stall Cycles"), PRELOADS_6, 1, ABST_LOAD},
+  {"dcmissov", "Re_DC_missovhd", REGNO_ANY, STXT ("DC Miss Ovhd"), PRELOADS_6, 1, ABST_LOAD},
+  {"fpustall", "Re_FPU_bypass", REGNO_ANY, STXT ("FPU Stall Cycles"), PRELOADS_6, 1, ABST_NONE},
+  {"fpusestall", "Rstall_FP_use", REGNO_ANY, STXT ("FPU Use Stall Cycles"), PRELOADS_6, 1, ABST_NONE},
+  {"iustall", "Rstall_IU_use", REGNO_ANY, STXT ("IU Stall Cycles"), PRELOADS_6, 1, ABST_NONE},
+  {"fpadd", "FA_pipe_completion", REGNO_ANY, STXT ("FP Adds"), PRELOADS_6, 0, ABST_NONE},
+  {"fpmul", "FM_pipe_completion", REGNO_ANY, STXT ("FP Muls"), PRELOADS_6, 0, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {"Cycle_cnt", NULL, REGNO_ANY, NULL, PRELOADS_7, 1, ABST_NONE},
+  {"DC_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"DC_rd_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"DC_wr", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"DC_wr_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"DTLB_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_US_DTLBM},
+  {"Dispatch0_2nd_br", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Dispatch0_IC_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Dispatch0_other", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2L3_snoop_cb_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC /*?*/},
+  {"L2L3_snoop_inv_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC /*?*/},
+  {"L2_hit_I_state_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST /*?*/},
+  {"L2_hit_other_half", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST},
+  {"L2_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST},
+  {"L2_rd_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"L2_ref", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST},
+  {"L2_snoop_cb_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC /*?*/},
+  {"L2_snoop_inv_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC /*?*/},
+  {"L2_wb", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"L2_wb_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"L2_write_hit_RTO", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"L2_write_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"L3_hit_I_state_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST},
+  {"L3_hit_other_half", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST},
+  {"L3_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST},
+  {"L3_rd_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"L3_wb", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"L3_wb_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"L3_write_hit_RTO", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"L3_write_miss_RTO", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE},
+  {"MC_reads_0_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_reads_1_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_reads_2_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_reads_3_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_stalls_0_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NOPC},
+  {"MC_stalls_1_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NOPC},
+  {"MC_stalls_2_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NOPC},
+  {"MC_stalls_3_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NOPC},
+  {"MC_writes_0_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_writes_1_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_writes_2_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"MC_writes_3_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  /*? {"PC_MS_misses", NULL, REGNO_ANY, NULL, PRELOAD_DEF,     0, ABST_LOAD}, */
+  {"PC_hard_hit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"PC_inv", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE /*?*/},
+  {"PC_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"PC_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"PC_soft_hit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LOAD},
+  {"Re_DC_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_LOAD},
+  {"Re_DC_missovhd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_LOAD},
+  {"Re_FPU_bypass", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Re_L2_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_LOAD},
+  {"Re_L3_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_LOAD},
+  {"Re_PFQ_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Re_RAW_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_LOAD},
+  {"Rstall_FP_use", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Rstall_IU_use", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Rstall_storeQ", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_STORE},
+  {"SI_RTO_src_data", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"SI_RTS_src_data", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"SI_ciq_flow_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NOPC},
+  {"SI_owned_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"SI_snoop_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NOPC},
+  {"ecml", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST},
+  {"ecmr", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST},
+  {"SSM_L3_miss_local", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST /*?*/},
+  {"SSM_L3_miss_mtag_remote", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST /*?*/},
+  {"SSM_L3_miss_remote", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_LDST /*?*/},
+  {"SSM_L3_wb_remote", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_STORE /*?*/},
+  {"SSM_new_transaction_sh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_TBD /*?*/},
+
+  /* additional (hidden) aliases, for convenience */
+  {"cycles0", "Cycle_cnt", 0, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"cycles1", "Cycle_cnt", 1, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"insts0", "Instr_cnt", 0, NULL, PRELOADS_75, 0, ABST_NONE},
+  {"insts1", "Instr_cnt", 1, NULL, PRELOADS_75, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry niagara1[] =
+       /* CPC_ULTRA_T1              , "UltraSPARC T1" */{
+  {"insts", "Instr_cnt", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_7, 0, ABST_NONE},
+#ifndef WORKAROUND_6231196_NIAGARA1_NO_CTR_0 /* since register 0 counter don't work XXX */
+  {"icm", "IC_miss", REGNO_ANY, STXT ("I$ Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"itlbm", "ITLB_miss", REGNO_ANY, STXT ("ITLB Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"ecim", "L2_imiss", REGNO_ANY, STXT ("E$ Instr. Misses"), PRELOADS_4, 0, ABST_NONE},
+  {"dcm", "DC_miss", REGNO_ANY, STXT ("D$ Misses"), PRELOADS_5, 0, ABST_EXACT},
+  {"dtlbm", "DTLB_miss", REGNO_ANY, STXT ("DTLB Misses"), PRELOADS_5, 0, ABST_EXACT},
+  {"ecdm", "L2_dmiss_ld", REGNO_ANY, STXT ("E$ Data Misses"), PRELOADS_4, 0, ABST_EXACT},
+  {"flops", "FP_instr_cnt", REGNO_ANY, STXT ("Floating-point Ops"), PRELOADS_6, 0, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {"SB_full", NULL, REGNO_ANY, NULL, PRELOADS_6, 1, ABST_NONE},
+  {"DC_miss", NULL, REGNO_ANY, NULL, PRELOADS_6, 0, ABST_EXACT},
+  {"DTLB_miss", NULL, REGNO_ANY, NULL, PRELOADS_6, 0, ABST_EXACT},
+  {"L2_dmiss_ld", NULL, REGNO_ANY, NULL, PRELOADS_6, 0, ABST_EXACT},
+#endif
+
+  /* additional (hidden) aliases, for convenience */
+  {"insts1", "Instr_cnt", 1, NULL, PRELOADS_75, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry niagara2[] = {
+  /* CPC_ULTRA_T2              , "UltraSPARC T2" */
+  /* CPC_ULTRA_T2              , "UltraSPARC T2+" */
+  {"insts", "Instr_cnt", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_7, 0, ABST_NONE},
+  {"loads", "Instr_ld", REGNO_ANY, STXT ("Load Instructions"), PRELOADS_7, 0, ABST_EXACT},
+  {"stores", "Instr_st", REGNO_ANY, STXT ("Store Instructions"), PRELOADS_6, 0, ABST_EXACT},
+  {"dcm", "DC_miss", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_6, 0, ABST_EXACT},
+  {"dtlbm", "DTLB_miss", REGNO_ANY, STXT ("DTLB Misses"), PRELOADS_6, 0, ABST_NONE},
+  {"l2drm", "L2_dmiss_ld", REGNO_ANY, STXT ("L2 D-cache Read Misses (See Bug 15664448)"), PRELOADS_5, 0, ABST_EXACT},
+  {"icm", "IC_miss", REGNO_ANY, STXT ("L1 I-cache Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"itlbm", "ITLB_miss", REGNO_ANY, STXT ("ITLB Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"l2im", "L2_imiss", REGNO_ANY, STXT ("L2 I-cache Misses"), PRELOADS_4, 0, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /* Only counters that can be time converted, or are load-store need to be in this table */
+  {"Instr_ld", NULL, REGNO_ANY, NULL, PRELOADS_7, 0, ABST_EXACT},
+  {"Instr_st", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT},
+  {"Atomics", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT},
+  {"DC_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT},
+  {"L2_dmiss_ld", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT},
+  {"DTLB_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE},
+  {"DES_3DES_busy_cycle", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"AES_busy_cycle", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Kasumi_busy_cycle", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"MD5_SHA-1_SHA-256_busy_cycle", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"MA_busy_cycle", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  /* additional (hidden) aliases, for convenience */
+  {"insts1", "Instr_cnt", 1, NULL, PRELOADS_75, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry sparc_t4[] = {
+  // Identical to sparc_t5_m6 except for: l3m_spec
+  // when updating this table, also update sparc_t5_m6[]
+  // obsolete aliases marked with REGNO_INVALID (allows reading of older experiments)
+  {"l2l3dh", "DC_miss_L2_L3_hit_nospec", REGNO_INVALID, STXT ("L2 or L3 D-cache Hits"), PRELOADS_6, 0, ABST_EXACT}, // undercounts due to thread-hog issue
+  {"l3m", "DC_miss_remote_L3_hit_nospec~emask=0x6", REGNO_INVALID, STXT ("L3 D-cache Misses"), PRELOADS_5, 0, ABST_EXACT}, // undercounts due to thread-hog issue
+  {"lmh", "DC_miss_local_hit_nospec", REGNO_INVALID, STXT ("Local Mem. Hits"), PRELOADS_5, 0, ABST_EXACT}, // undercounts due to thread-hog issue
+  {"rmh", "DC_miss_remote_L3_hit_nospec", REGNO_INVALID, STXT ("Remote Mem. Hits"), PRELOADS_5, 0, ABST_EXACT}, // undercounts due to thread-hog issue
+  {"pqs", "PQ_tag_wait", REGNO_INVALID, STXT ("Pick Queue Stalls"), PRELOADS_7, 1, ABST_NONE}, // old alias name
+  {"raw_stb", "RAW_hit_st_buf", REGNO_INVALID, STXT ("RAW Hazard in Store Buffer"), PRELOADS_55, 0, ABST_NONE}, // 11@full hit, 60@partial hit (in future, combine w/st_q)
+  {"raw_stq", "RAW_hit_st_q", REGNO_INVALID, STXT ("RAW Hazard in Store Queue"), PRELOADS_55, 0, ABST_NONE}, // 11@full hit, 60@partial hit (in future, combine w/st_buf)
+  {"sel_stalls", "Sel_0_ready", REGNO_INVALID, STXT ("Stalls Another Thread Selected"), PRELOADS_7, 1, ABST_NONE},
+  {"icm", "IC_miss", REGNO_INVALID, STXT ("L1 I-Cache Misses"), PRELOADS_55, 0, ABST_NONE}, // 20@ l2/l3 hit (guess)
+  {"icm_stalls", "IC_miss", REGNO_INVALID, STXT ("L1 I-Cache Miss Est Stalls"), PRELOADS_55, 25, ABST_NONE}, // 25@ l2-20/l3-50
+
+  // current aliases
+  SPARC_CYCLES
+  {"cycles", "Cycles_user", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "Instr_all", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+  {"c_stalls", "Commit_0", REGNO_ANY, STXT ("Stall Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"loads", "Instr_ld", REGNO_ANY, STXT ("Load Instructions"), PRELOADS_7, 0, ABST_EXACT},
+  {"stores", "Instr_st", REGNO_ANY, STXT ("Store Instructions"), PRELOADS_7, 0, ABST_EXACT},
+  {"dcm", "DC_miss_nospec", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_65, 0, ABST_EXACT},
+  {"l3m_spec", "DC_miss_local_hit~emask=0x6", REGNO_ANY, STXT ("L3 D-cache Speculative Misses"), PRELOADS_5, 0, ABST_NONE, STXT ("Loads that speculatively missed local L3")}, // T4 encoding (430 lm, 690 rm) ~5 misses overlap on t5/pico_ile
+  //  {"l3m_spec",     "DC_miss_local_hit~emask=0x30",         REGNO_ANY, STXT("L3 D-cache Speculative Misses"),PRELOADS_5,0, ABST_NONE, STXT("Loads that speculatively missed local L3")}, // T5/M6 encoding (430 lm, 690 rm) ~5 misses overlap on t5/pico_ile
+  {"lmh_spec", "DC_miss_local_hit", REGNO_ANY, STXT ("Local Mem Speculative Hits"), PRELOADS_5, 0, ABST_NONE},
+  {"rmh_spec", "DC_miss_remote_L3_hit", REGNO_ANY, STXT ("Remote Mem Speculative Hits"), PRELOADS_5, 0, ABST_NONE},
+  //
+  {"dtlbm", "DTLB_miss_asynch", REGNO_ANY, STXT ("DTLB Misses"), PRELOADS_55, 0, ABST_NONE}, // 10@l1 hit, 24@l2 hit, 60@l3 hit, 500@l3 miss, 5000@trap  0.001 events/cycle
+  {"dtlb_hwtw_stalls", "DTLB_HWTW_all", REGNO_ANY, STXT ("DTLB HWTW Est Stalls"), PRELOADS_55, 25, ABST_NONE, STXT ("Estimated time stalled on a DTLB miss requiring a HW tablewalk")}, // l2-20, l3-50
+  {"dtlb_trap_stalls", "DTLB_fill_trap", REGNO_ANY, STXT ("DTLB Trap Est Stalls"), PRELOADS_35, 5000, ABST_NONE, STXT ("Estimated time stalled on a DTLB miss with HW tablewalk unsuccessful")}, // 5000@trap
+  {"rawhaz", "RAW_hit_st_q~emask=0xf", REGNO_ANY, STXT ("Read-after-write Hazards"), PRELOADS_55, 0, ABST_NONE, STXT ("Loads delayed by a previous store (read-after-write hazards)")},
+  {"br_msp_stalls", "Br_mispred", REGNO_ANY, STXT ("Branch Mispredict Stalls"), PRELOADS_6, 24, ABST_NONE, STXT ("Estimated time stalled on Branch mispredictions")}, // 24@miss, %5 of branches is bad
+  {"br_msp", "Br_mispred", REGNO_ANY, STXT ("Branch Mispredict"), PRELOADS_6, 0, ABST_NONE}, // 24@miss, %5 of branches is bad
+  {"br_tkn", "Br_taken", REGNO_ANY, STXT ("Branch Taken"), PRELOADS_7, 0, ABST_NONE}, // 2 cycles minimum
+  {"br_ins", "Branches", REGNO_ANY, STXT ("Branch Instructions"), PRELOADS_7, 0, ABST_NONE}, // 24@miss, %5 of branches is bad
+  {"fgu", "Instr_FGU_crypto", REGNO_ANY, STXT ("FP/VIS/Crypto Instructions"), PRELOADS_7, 0, ABST_NONE}, // 1 cycle/event
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /* Counters that can be time converted, support memspace, or have a short_desc need to be in this table */
+
+  {"Sel_pipe_drain_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread stalls at Select waiting with correct instructions when pipeline has to drain after branch misprediction")},
+  {"Sel_0_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread stalls at Select waiting for various conditions to be resolved")},
+  {"Sel_0_ready", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread was ready to have its instructions selected but another hardware thread was selected instead")},
+  {"Sel_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles that only 1 instruction or uop was selected")},
+  {"Sel_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles that 2 instructions or uops were selected")},
+
+  {"Pick_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Pick_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Pick_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Pick_3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Pick_any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"Branches", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Control transfer instructions completed, excluding trap-related transfers")},
+  {"Instr_FGU_crypto", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("FP and VIS instructions completed by the Floating Point and Graphics Unit")},
+  {"Instr_ld", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("Load instructions completed")},
+  {"Instr_st", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("Store instructions completed")},
+  {"SPR_ring_ops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("Specialized instructions that require internal use of SPR ring completed")},
+  {"Instr_other", NULL, REGNO_ANY, NULL, PRELOAD (2, 4), 0, ABST_NONE, STXT ("Basic arithmetic and logical instructions completed")},
+  {"Instr_all", NULL, REGNO_ANY, NULL, PRELOAD (1, 4), 0, ABST_NONE, STXT ("Total instructions completed")},
+
+  {"Br_taken", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Branch instructions taken and completed")},
+  {"Sw_count_intr", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("SW Count instructions completed")},
+  {"Atomics", NULL, REGNO_ANY, NULL, PRELOAD (20, 4), 0, ABST_EXACT, STXT ("Atomic instructions, including CASA/XA, completed")},
+  {"SW_prefetch", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("PREFETCH and PREFETCHA instructions completed")},
+  {"Block_ld_st", NULL, REGNO_ANY, NULL, PRELOAD (20, 4), 0, ABST_EXACT, STXT ("Block load/store instructions completed")},
+
+  {"BTC_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Branches delayed a few extra cycles because branch target not found in Branch Target Cache")},
+
+  {"ITLB_fill_8KB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 8K page")},
+  {"ITLB_fill_64KB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 64K page")},
+  {"ITLB_fill_4MB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 4M page")},
+  {"ITLB_fill_256MB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 256M page")},
+  {"ITLB_fill_2GB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 2G or 16G page")},
+  {"ITLB_fill_trap", NULL, REGNO_ANY, NULL, PRELOAD (1000, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk unsuccessful")},
+  {"ITLB_miss_asynch", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk search done")},
+
+  {"Fetch_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_0_all", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"Instr_buffer_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"PQ_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"ROB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"ROB_LB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"SB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"ROB_SB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LB_SB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"ROB_LB_SB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"DTLB_miss_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"ITLB_HWTW_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk hit local L2D")},
+  {"ITLB_HWTW_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (80, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk hit local L3 or neighbor L2D")},
+  {"ITLB_HWTW_L3_miss", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk missed all local caches")},
+  {"DTLB_HWTW_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk hit local L2D")},
+  {"DTLB_HWTW_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (80, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk hit local L3 or neighbor L2D")},
+  {"DTLB_HWTW_L3_miss", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk missed all local caches")},
+  {"DTLB_HWTW_all", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss requiring HW tablewalk")},
+
+  {"DC_miss_L2_L3_hit_nospec", NULL, REGNO_ANY, NULL, PRELOAD (25, 4), 0, ABST_EXACT},
+  {"DC_miss_local_hit_nospec", NULL, REGNO_ANY, NULL, PRELOAD (500, 4), 0, ABST_EXACT},
+  {"DC_miss_remote_L3_hit_nospec", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_EXACT},
+  {"DC_miss_nospec", NULL, REGNO_ANY, NULL, PRELOAD (25, 4), 0, ABST_EXACT, STXT ("Loads that missed local L1D")},
+
+  {"DTLB_fill_8KB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 8K page")},
+  {"DTLB_fill_64KB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 64K page")},
+  {"DTLB_fill_4MB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 4M page")},
+  {"DTLB_fill_256MB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 256M page")},
+  {"DTLB_fill_2GB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 2G or 16G page")},
+  {"DTLB_fill_trap", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk unsuccessful")},
+  {"DTLB_miss_asynch", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk search done")},
+  {"RAW_hit_st_buf", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Loads delayed by a previous store (read-after-write) still in store buffer not yet committed")},
+  {"RAW_hit_st_q", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Loads delayed by a previous store (read-after-write) committed but in store queue not yet written to L2D")},
+
+  {"St_q_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"St_hit_L2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Stores whose cacheline being updated was in local L2D")},
+  {"St_hit_L3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Stores whose cacheline being updated was in local L3")},
+
+  {"DC_miss_L2_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (20, 4), 0, ABST_NONE, STXT ("Loads that speculatively hit local L2D or L3")},
+  {"DC_miss_local_hit", NULL, REGNO_ANY, NULL, PRELOAD (500, 4), 0, ABST_NONE, STXT ("Loads that speculatively hit local memory")},
+  {"DC_miss_remote_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_NONE, STXT ("Loads that speculatively hit remote cache or remote memory")},
+  {"DC_miss", NULL, REGNO_ANY, NULL, PRELOAD (20, 4), 0, ABST_NONE, STXT ("Loads that speculatively missed L1D")},
+
+  {"L2_pipe_stall", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"Br_dir_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Branch instructions completed whose direction was mispredicted")},
+  {"Br_trg_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Branch instructions completed whose target was mispredicted")},
+  {"Br_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Branch instructions completed whose direction or target was mispredicted")},
+
+  {"Cycles_user", NULL, REGNO_ANY, NULL, PRELOAD (1, 4), 1, ABST_NONE, STXT ("Cycles hardware thread is active in specified mode(s)")},
+  //
+  {"Commit_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles no uop commits from this hardware thread")},
+  {"Commit_0_all", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles no uop commits from any hardware thread on this core")},
+  {"Commit_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles 1 uop commits from this hardware thread")},
+  {"Commit_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles 2 uops commit from this hardware thread")},
+  {"Commit_1_or_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles 1 or 2 uops commit from this hardware thread")},
+
+  /* additional (hidden) aliases, for convenience */
+  {"cycles0", "Cycles_user", 0, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"cycles1", "Cycles_user", 1, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"insts0", "Instr_all", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "Instr_all", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry sparc_t5_m6[] = {
+  // Identical to sparc_t4 except for: l3m_spec
+  // when updating this table, also update sparc_t4[]
+  // obsolete aliases marked with REGNO_INVALID (allows reading of older experiments)
+  {"l2l3dh", "DC_miss_L2_L3_hit_nospec", REGNO_INVALID, STXT ("L2 or L3 D-cache Hits"), PRELOADS_6, 0, ABST_EXACT}, // undercounts due to thread-hog issue
+  {"l3m", "DC_miss_remote_L3_hit_nospec~emask=0x6", REGNO_INVALID, STXT ("L3 D-cache Misses"), PRELOADS_5, 0, ABST_EXACT}, // undercounts due to thread-hog issue
+  {"lmh", "DC_miss_local_hit_nospec", REGNO_INVALID, STXT ("Local Mem. Hits"), PRELOADS_5, 0, ABST_EXACT}, // undercounts due to thread-hog issue
+  {"rmh", "DC_miss_remote_L3_hit_nospec", REGNO_INVALID, STXT ("Remote Mem. Hits"), PRELOADS_5, 0, ABST_EXACT}, // undercounts due to thread-hog issue
+  {"pqs", "PQ_tag_wait", REGNO_INVALID, STXT ("Pick Queue Stalls"), PRELOADS_7, 1, ABST_NONE}, // old alias name
+  {"raw_stb", "RAW_hit_st_buf", REGNO_INVALID, STXT ("RAW Hazard in Store Buffer"), PRELOADS_55, 0, ABST_NONE}, // 11@full hit, 60@partial hit (in future, combine w/st_q)
+  {"raw_stq", "RAW_hit_st_q", REGNO_INVALID, STXT ("RAW Hazard in Store Queue"), PRELOADS_55, 0, ABST_NONE}, // 11@full hit, 60@partial hit (in future, combine w/st_buf)
+  {"sel_stalls", "Sel_0_ready", REGNO_INVALID, STXT ("Stalls Another Thread Selected"), PRELOADS_7, 1, ABST_NONE},
+  {"icm", "IC_miss", REGNO_INVALID, STXT ("L1 I-Cache Misses"), PRELOADS_55, 0, ABST_NONE}, // 20@ l2/l3 hit (guess)
+  {"icm_stalls", "IC_miss", REGNO_INVALID, STXT ("L1 I-Cache Miss Est Stalls"), PRELOADS_55, 25, ABST_NONE}, // 25@ l2-20/l3-50
+
+  // current aliases
+  SPARC_CYCLES
+  {"cycles", "Cycles_user", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "Instr_all", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+  {"c_stalls", "Commit_0", REGNO_ANY, STXT ("Stall Cycles"), PRELOADS_7, 1, ABST_NONE},
+
+  {"loads", "Instr_ld", REGNO_ANY, STXT ("Load Instructions"), PRELOADS_7, 0, ABST_EXACT},
+  {"stores", "Instr_st", REGNO_ANY, STXT ("Store Instructions"), PRELOADS_7, 0, ABST_EXACT},
+  {"dcm", "DC_miss_nospec", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_65, 0, ABST_EXACT},
+  //  {"l3m_spec",     "DC_miss_local_hit~emask=0x6",          REGNO_ANY, STXT("L3 D-cache Speculative Misses"),PRELOADS_5,0, ABST_NONE, STXT("Loads that speculatively missed local L3")}, // T4 encoding (430 lm, 690 rm) ~5 misses overlap on t5/pico_ile
+  {"l3m_spec", "DC_miss_local_hit~emask=0x30", REGNO_ANY, STXT ("L3 D-cache Speculative Misses"), PRELOADS_5, 0, ABST_NONE, STXT ("Loads that speculatively missed local L3")}, // T5/M6 encoding (430 lm, 690 rm) ~5 misses overlap on t5/pico_ile
+  {"lmh_spec", "DC_miss_local_hit", REGNO_ANY, STXT ("Local Mem Speculative Hits"), PRELOADS_5, 0, ABST_NONE},
+  {"rmh_spec", "DC_miss_remote_L3_hit", REGNO_ANY, STXT ("Remote Mem Speculative Hits"), PRELOADS_5, 0, ABST_NONE},
+  //
+  {"dtlbm", "DTLB_miss_asynch", REGNO_ANY, STXT ("DTLB Misses"), PRELOADS_55, 0, ABST_NONE}, // 10@l1 hit, 24@l2 hit, 60@l3 hit, 500@l3 miss, 5000@trap  0.001 events/cycle
+  {"dtlb_hwtw_stalls", "DTLB_HWTW_all", REGNO_ANY, STXT ("DTLB HWTW Est Stalls"), PRELOADS_55, 25, ABST_NONE, STXT ("Estimated time stalled on a DTLB miss requiring a HW tablewalk")}, // l2-20, l3-50
+  {"dtlb_trap_stalls", "DTLB_fill_trap", REGNO_ANY, STXT ("DTLB Trap Est Stalls"), PRELOADS_35, 5000, ABST_NONE, STXT ("Estimated time stalled on a DTLB miss with HW tablewalk unsuccessful")}, // 5000@trap
+  {"rawhaz", "RAW_hit_st_q~emask=0xf", REGNO_ANY, STXT ("Read-after-write Hazards"), PRELOADS_55, 0, ABST_NONE, STXT ("Loads delayed by a previous store (read-after-write hazards)")},
+  {"br_msp_stalls", "Br_mispred", REGNO_ANY, STXT ("Branch Mispredict Stalls"), PRELOADS_6, 24, ABST_NONE, STXT ("Estimated time stalled on Branch mispredictions")}, // 24@miss, %5 of branches is bad
+  {"br_msp", "Br_mispred", REGNO_ANY, STXT ("Branch Mispredict"), PRELOADS_6, 0, ABST_NONE}, // 24@miss, %5 of branches is bad
+  {"br_tkn", "Br_taken", REGNO_ANY, STXT ("Branch Taken"), PRELOADS_7, 0, ABST_NONE}, // 2 cycles minimum
+  {"br_ins", "Branches", REGNO_ANY, STXT ("Branch Instructions"), PRELOADS_7, 0, ABST_NONE}, // 24@miss, %5 of branches is bad
+  {"fgu", "Instr_FGU_crypto", REGNO_ANY, STXT ("FP/VIS/Crypto Instructions"), PRELOADS_7, 0, ABST_NONE}, // 1 cycle/event
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /* Counters that can be time converted, support memspace, or have a short_desc need to be in this table */
+
+  {"Sel_pipe_drain_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread stalls at Select waiting with correct instructions when pipeline has to drain after branch misprediction")},
+  {"Sel_0_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread stalls at Select waiting for various conditions to be resolved")},
+  {"Sel_0_ready", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread was ready to have its instructions selected but another hardware thread was selected instead")},
+  {"Sel_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles that only 1 instruction or uop was selected")},
+  {"Sel_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles that 2 instructions or uops were selected")},
+
+  {"Pick_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Pick_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Pick_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Pick_3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Pick_any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"Branches", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Control transfer instructions completed, excluding trap-related transfers")},
+  {"Instr_FGU_crypto", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("FP and VIS instructions completed by the Floating Point and Graphics Unit")},
+  {"Instr_ld", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("Load instructions completed")},
+  {"Instr_st", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("Store instructions completed")},
+  {"SPR_ring_ops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("Specialized instructions that require internal use of SPR ring completed")},
+  {"Instr_other", NULL, REGNO_ANY, NULL, PRELOAD (2, 4), 0, ABST_NONE, STXT ("Basic arithmetic and logical instructions completed")},
+  {"Instr_all", NULL, REGNO_ANY, NULL, PRELOAD (1, 4), 0, ABST_NONE, STXT ("Total instructions completed")},
+
+  {"Br_taken", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Branch instructions taken and completed")},
+  {"Sw_count_intr", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("SW Count instructions completed")},
+  {"Atomics", NULL, REGNO_ANY, NULL, PRELOAD (20, 4), 0, ABST_EXACT, STXT ("Atomic instructions, including CASA/XA, completed")},
+  {"SW_prefetch", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("PREFETCH and PREFETCHA instructions completed")},
+  {"Block_ld_st", NULL, REGNO_ANY, NULL, PRELOAD (20, 4), 0, ABST_EXACT, STXT ("Block load/store instructions completed")},
+
+  {"BTC_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Branches delayed a few extra cycles because branch target not found in Branch Target Cache")},
+
+  {"ITLB_fill_8KB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 8K page")},
+  {"ITLB_fill_64KB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 64K page")},
+  {"ITLB_fill_4MB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 4M page")},
+  {"ITLB_fill_256MB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 256M page")},
+  {"ITLB_fill_2GB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 2G or 16G page")},
+  {"ITLB_fill_trap", NULL, REGNO_ANY, NULL, PRELOAD (1000, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk unsuccessful")},
+  {"ITLB_miss_asynch", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk search done")},
+
+  {"Fetch_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_0_all", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"Instr_buffer_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"PQ_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"ROB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"ROB_LB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"SB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"ROB_SB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LB_SB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"ROB_LB_SB_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"DTLB_miss_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"ITLB_HWTW_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk hit local L2D")},
+  {"ITLB_HWTW_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (80, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk hit local L3 or neighbor L2D")},
+  {"ITLB_HWTW_L3_miss", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk missed all local caches")},
+  {"DTLB_HWTW_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk hit local L2D")},
+  {"DTLB_HWTW_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (80, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk hit local L3 or neighbor L2D")},
+  {"DTLB_HWTW_L3_miss", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk missed all local caches")},
+  {"DTLB_HWTW_all", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss requiring HW tablewalk")},
+
+  {"DC_miss_L2_L3_hit_nospec", NULL, REGNO_ANY, NULL, PRELOAD (25, 4), 0, ABST_EXACT},
+  {"DC_miss_local_hit_nospec", NULL, REGNO_ANY, NULL, PRELOAD (500, 4), 0, ABST_EXACT},
+  {"DC_miss_remote_L3_hit_nospec", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_EXACT},
+  {"DC_miss_nospec", NULL, REGNO_ANY, NULL, PRELOAD (25, 4), 0, ABST_EXACT, STXT ("Loads that missed local L1D")},
+
+  {"DTLB_fill_8KB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 8K page")},
+  {"DTLB_fill_64KB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 64K page")},
+  {"DTLB_fill_4MB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 4M page")},
+  {"DTLB_fill_256MB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 256M page")},
+  {"DTLB_fill_2GB", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 2G or 16G page")},
+  {"DTLB_fill_trap", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk unsuccessful")},
+  {"DTLB_miss_asynch", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk search done")},
+  {"RAW_hit_st_buf", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Loads delayed by a previous store (read-after-write) still in store buffer not yet committed")},
+  {"RAW_hit_st_q", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Loads delayed by a previous store (read-after-write) committed but in store queue not yet written to L2D")},
+
+  {"St_q_tag_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"St_hit_L2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Stores whose cacheline being updated was in local L2D")},
+  {"St_hit_L3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Stores whose cacheline being updated was in local L3")},
+
+  {"DC_miss_L2_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (20, 4), 0, ABST_NONE, STXT ("Loads that speculatively hit local L2D or L3")},
+  {"DC_miss_local_hit", NULL, REGNO_ANY, NULL, PRELOAD (500, 4), 0, ABST_NONE, STXT ("Loads that speculatively hit local memory")},
+  {"DC_miss_remote_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_NONE, STXT ("Loads that speculatively hit remote cache or remote memory")},
+  {"DC_miss", NULL, REGNO_ANY, NULL, PRELOAD (20, 4), 0, ABST_NONE, STXT ("Loads that speculatively missed L1D")},
+
+  {"L2_pipe_stall", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"Br_dir_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Branch instructions completed whose direction was mispredicted")},
+  {"Br_trg_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Branch instructions completed whose target was mispredicted")},
+  {"Br_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Branch instructions completed whose direction or target was mispredicted")},
+
+  {"Cycles_user", NULL, REGNO_ANY, NULL, PRELOAD (1, 4), 1, ABST_NONE, STXT ("Cycles hardware thread is active in specified mode(s)")},
+  //
+  {"Commit_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles no uop commits from this hardware thread")},
+  {"Commit_0_all", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles no uop commits from any hardware thread on this core")},
+  {"Commit_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles 1 uop commits from this hardware thread")},
+  {"Commit_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles 2 uops commit from this hardware thread")},
+  {"Commit_1_or_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles 1 or 2 uops commit from this hardware thread")},
+
+  /* additional (hidden) aliases, for convenience */
+  {"cycles0", "Cycles_user", 0, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"cycles1", "Cycles_user", 1, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"insts0", "Instr_all", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "Instr_all", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry sparc_m7[] = {
+  // obsolete aliases marked with REGNO_INVALID (allows reading of older experiments)
+  {"icm", "IC_miss_commit", REGNO_INVALID, STXT ("L1 I-Cache Misses"), PRELOADS_6, 0, ABST_EXACT},
+  {"raw_stb", "RAW_hit_st_buf", REGNO_INVALID, STXT ("RAW Hazard in Store Buffer"), PRELOADS_55, 0, ABST_NONE},
+  {"raw_stq", "RAW_hit_st_q", REGNO_INVALID, STXT ("RAW Hazard in Store Queue"), PRELOADS_55, 0, ABST_NONE},
+  {"pqs", "PQ_tag_wait_cyc", REGNO_INVALID, STXT ("Pick Queue Stalls"), PRELOADS_7, 1, ABST_NONE},
+  {"sel_stalls", "Sel_0_ready_cyc", REGNO_INVALID, STXT ("Stalls Another Thread Selected"), PRELOADS_7, 1, ABST_NONE},
+
+  // current aliases
+  SPARC_CYCLES
+  {"cycles", "Cycles_user", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "Instr_all", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+  {"c_stalls", "Commit_0_cyc", REGNO_ANY, STXT ("Stall Cycles"), PRELOADS_7, 1, ABST_NONE},
+
+  {"loads", "Instr_ld", REGNO_ANY, STXT ("Load Instructions"), PRELOADS_7, 0, ABST_EXACT},
+  {"stores", "Instr_st", REGNO_ANY, STXT ("Store Instructions"), PRELOADS_6, 0, ABST_EXACT},
+  {"dcm", "DC_miss_commit", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_6, 0, ABST_EXACT},
+
+  {"l3m_spec", "DC_miss_L3_miss", REGNO_ANY, STXT ("L3 D-cache Speculative Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"lmh_spec", "DC_miss_local_mem_hit", REGNO_ANY, STXT ("Local Mem Speculative Hits"), PRELOADS_5, 0, ABST_NONE},
+  {"rmh_spec", "DC_miss_remote_mem_hit", REGNO_ANY, STXT ("Remote Mem Speculative Hits"), PRELOADS_5, 0, ABST_NONE},
+  //
+  {"dtlbm", "DTLB_HWTW_search", REGNO_ANY, STXT ("DTLB Misses"), PRELOADS_55, 0, ABST_NONE}, // 10@l1 hit, 24@l2 hit, 60@l3 hit, 500@l3 miss, 5000@trap  0.001 events/cycle
+  {"dtlb_hwtw_stalls", "DTLB_HWTW_ref", REGNO_ANY, STXT ("DTLB HWTW Est Stalls"), PRELOADS_55, 25, ABST_NONE, STXT ("Estimated time stalled on a DTLB miss requiring a HW tablewalk")}, // l2-20, l3-50
+  {"dtlb_trap_stalls", "DTLB_HWTW_miss_trap", REGNO_ANY, STXT ("DTLB Trap Est Stalls"), PRELOADS_35, 5000, ABST_NONE, STXT ("Estimated time stalled on a DTLB miss with HW tablewalk unsuccessful")}, // 5000@trap
+  {"rawhaz", "RAW_hit_st_q~emask=0xf", REGNO_ANY, STXT ("Read-after-write Hazards"), PRELOADS_55, 0, ABST_NONE, STXT ("Loads delayed by a previous store (read-after-write hazards)")},
+  {"br_msp_stalls", "Br_mispred", REGNO_ANY, STXT ("Branch Mispredict Stalls"), PRELOADS_6, 24, ABST_NONE, STXT ("Estimated time stalled on Branch mispredictions")}, // 24@miss, %5 of branches is bad
+  {"br_msp", "Br_mispred", REGNO_ANY, STXT ("Branch Mispredict"), PRELOADS_6, 0, ABST_NONE},
+  {"br_tkn", "Br_taken", REGNO_ANY, STXT ("Branch Taken"), PRELOADS_7, 0, ABST_NONE},
+  {"br_ins", "Branches", REGNO_ANY, STXT ("Branch Instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"fgu", "Instr_FGU_crypto", REGNO_ANY, STXT ("FP/VIS/Crypto Instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"spill_fill", "Flush_arch_exception", REGNO_ANY, STXT ("Reg Window Spill/Fill Est Stalls"), PRELOAD (100, 4), 80, ABST_NONE, STXT ("Estimated time stalled on flushing pipeline due to register window spill/fill")},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Counters that can be time converted, support memspace, or have a short_desc need to be in this table */
+  {"Sel_pipe_drain_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread stalls at Select waiting with correct instructions when pipeline has to drain after branch misprediction")},
+  {"Sel_0_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread stalls at Select waiting for various conditions to be resolved")},
+  {"Sel_0_ready_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread was ready to have its instructions selected but another hardware thread was selected instead")},
+  {"Sel_1_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles that only 1 instruction or uop was selected")},
+  {"Sel_2_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles that 2 instructions or uops were selected")},
+
+  {"Pick_0_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Pick_1_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Pick_2_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Pick_3_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Pick_any_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"Branches", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Control transfer instructions completed, excluding trap-related transfers")},
+  {"Instr_FGU_crypto", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("FP and VIS instructions completed by the Floating Point and Graphics Unit")},
+  {"Instr_ld", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("Load instructions completed")},
+  {"Instr_st", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("Store instructions completed")},
+  {"Instr_SPR_ring_ops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("Specialized instructions that require internal use of SPR ring completed")},
+  {"Instr_other", NULL, REGNO_ANY, NULL, PRELOAD (2, 4), 0, ABST_NONE, STXT ("Basic arithmetic and logical instructions completed")},
+  {"Instr_all", NULL, REGNO_ANY, NULL, PRELOAD (1, 4), 0, ABST_NONE, STXT ("Total instructions completed")},
+
+  {"Br_taken", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Branch instructions taken and completed")},
+  {"Instr_SW_count", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("SW Count instructions completed")},
+  {"Instr_atomic", NULL, REGNO_ANY, NULL, PRELOAD (20, 4), 0, ABST_EXACT, STXT ("Atomic instructions, including CASA/XA, completed")},
+  {"Instr_SW_prefetch", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("PREFETCH and PREFETCHA instructions completed")},
+  {"Instr_block_ld_st", NULL, REGNO_ANY, NULL, PRELOAD (20, 4), 0, ABST_EXACT, STXT ("Block load/store instructions completed")},
+
+  {"Br_BTC_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Branches delayed a few extra cycles because branch target not found in Branch Target Cache")},
+
+  {"ITLB_HWTW_hit_8K", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 8K page")},
+  {"ITLB_HWTW_hit_64K", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 64K page")},
+  {"ITLB_HWTW_hit_4M", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 4M page")},
+  {"ITLB_HWTW_hit_256M", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 256M page")},
+  {"ITLB_HWTW_hit_2G_16G", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 2G or 16G page")},
+  {"ITLB_HWTW_miss_trap", NULL, REGNO_ANY, NULL, PRELOAD (1000, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk unsuccessful")},
+  {"ITLB_HWTW_search", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk search done")},
+
+  {"Fetch_0_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_0_all_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"Instr_buffer_full_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"PQ_tag_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"ROB_tag_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LB_tag_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"SB_tag_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"ROB_LB_tag_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"ROB_SB_tag_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LB_SB_tag_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"ROB_LB_SB_tag_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"DTLB_miss_tag_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"ITLB_HWTW_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk hit local L2D")},
+  {"ITLB_HWTW_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (80, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk hit local L3 or neighbor L2D")},
+  {"ITLB_HWTW_L3_miss", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk missed all local caches")},
+  {"DTLB_HWTW_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk hit local L2D")},
+  {"DTLB_HWTW_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (80, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk hit local L3 or neighbor L2D")},
+  {"DTLB_HWTW_L3_miss", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk missed all local caches")},
+  {"DTLB_HWTW_ref", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss requiring HW tablewalk")},
+
+  {"DC_miss_L2_L3_hit_commit", NULL, REGNO_ANY, NULL, PRELOAD (25, 4), 0, ABST_EXACT},
+  {"DC_miss_nbr_scc_hit_commit", NULL, REGNO_ANY, NULL, PRELOAD (500, 4), 0, ABST_EXACT},
+  {"DC_miss_nbr_scc_miss_commit", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_EXACT},
+  {"DC_miss_commit", NULL, REGNO_ANY, NULL, PRELOAD (25, 4), 0, ABST_EXACT, STXT ("Loads that missed local L1D")},
+
+  {"DTLB_HWTW_hit_8K", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 8K page")},
+  {"DTLB_HWTW_hit_64K", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 64K page")},
+  {"DTLB_HWTW_hit_4M", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 4M page")},
+  {"DTLB_HWTW_hit_256M", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 256M page")},
+  {"DTLB_HWTW_hit_2G_16G", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 2G or 16G page")},
+  {"DTLB_HWTW_miss_trap", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk unsuccessful")},
+  {"DTLB_HWTW_search", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk search done")},
+  {"RAW_hit_st_buf", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Loads delayed by a previous store (read-after-write) still in store buffer not yet committed")},
+  {"RAW_hit_st_q", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Loads delayed by a previous store (read-after-write) committed but in store queue not yet written to L2D")},
+
+  {"St_q_tag_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"St_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Stores whose cacheline being updated was in local L2D")},
+  {"St_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Stores whose cacheline being updated was in local L3")},
+
+  {"DC_hit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Loads that speculatively hit local L1D")},
+  {"DC_miss_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD (20, 4), 0, ABST_NONE, STXT ("Loads that speculatively hit local L2D")},
+  {"DC_miss_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Loads that speculatively hit local L3")},
+  {"DC_miss_nbr_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD (100, 4), 0, ABST_NONE, STXT ("Loads that speculatively hit neighbor L2D via local L3")},
+  {"DC_miss_nbr_scc_hit", NULL, REGNO_ANY, NULL, PRELOAD (100, 4), 0, ABST_NONE, STXT ("Loads that speculatively hit neighbor L3 on same socket")},
+  {"DC_miss_nbr_scc_miss", NULL, REGNO_ANY, NULL, PRELOAD (400, 4), 0, ABST_NONE, STXT ("Loads that speculatively missed all caches on same socket")},
+  {"DC_miss", NULL, REGNO_ANY, NULL, PRELOAD (10, 4), 0, ABST_NONE, STXT ("Loads that speculatively missed local L1D")},
+  {"DC_miss_L2_miss", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Loads that speculatively missed local L2D")},
+  {"DC_miss_L3_miss", NULL, REGNO_ANY, NULL, PRELOAD (200, 4), 0, ABST_NONE, STXT ("Loads that speculatively missed local L3")},
+
+  {"DC_miss_remote_scc_hit", NULL, REGNO_ANY, NULL, PRELOAD (800, 4), 0, ABST_NONE, STXT ("Loads that speculatively hit remote cache on different socket")},
+  {"DC_miss_local_mem_hit", NULL, REGNO_ANY, NULL, PRELOAD (500, 4), 0, ABST_NONE, STXT ("Loads that speculatively hit local memory")},
+  {"DC_miss_remote_mem_hit", NULL, REGNO_ANY, NULL, PRELOAD (1000, 4), 0, ABST_NONE, STXT ("Loads that speculatively hit remote memory")},
+  {"Br_dir_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Branch instructions completed whose direction was mispredicted")},
+  {"Br_tgt_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Branch instructions completed whose target was mispredicted")},
+  {"Br_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Branch instructions completed whose direction or target was mispredicted")},
+
+  {"Cycles_user", NULL, REGNO_ANY, NULL, PRELOAD (1, 4), 1, ABST_NONE, STXT ("Cycles hardware thread is active in specified mode(s)")},
+
+  {"Flush_L3_miss", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Pipeline flushes due to a load that misses L3 when more than 1 hardware thread is active on the core")},
+  {"Flush_br_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Pipeline flushes due to a branch misprediction")},
+  {"Flush_arch_exception", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Pipeline flushes due to SPARC architecture exceptions and trap entry/return")},
+  {"Flush_other", NULL, REGNO_ANY, NULL, PRELOAD (40, 4), 0, ABST_NONE, STXT ("Pipeline flushes due to hardware thread state change to/from halted/paused state")},
+  //
+  {"Commit_0_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles no uop commits from this hardware thread")},
+  {"Commit_0_all_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles no uop commits from any hardware thread on this core")},
+  {"Commit_1_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles 1 uop commits from this hardware thread")},
+  {"Commit_2_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles 2 uops commit from this hardware thread")},
+  {"Commit_1_or_2_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles 1 or 2 uops commit from this hardware thread")},
+
+
+  /* additional (hidden) aliases, for convenience */
+  {"cycles0", "Cycles_user", 0, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"cycles1", "Cycles_user", 1, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"insts0", "Instr_all", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "Instr_all", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry sparc_m8[] = {
+  // current aliases
+  SPARC_CYCLES
+  {"cycles", "Cycles_user", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "Instr_all", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+  {"c_stalls", "Commit_0_cyc", 3, STXT ("Stall Cycles"), PRELOADS_7, 1, ABST_NONE}, // 22825776: limit to reg 3
+  {"Sel_0_wait_cyc", "Sel_0_cyc~emask=0x3f", REGNO_ANY, STXT ("Select Stall Cycles"), PRELOADS_7, 1, ABST_NONE, STXT ("Cycles a hardware thread stalls at Select waiting for various conditions to be resolved that prevent it being selected")},
+
+  {"loads", "Instr_ld", REGNO_ANY, STXT ("Load Instructions"), PRELOADS_7, 0, ABST_EXACT},
+  {"stores", "Instr_st", REGNO_ANY, STXT ("Store Instructions"), PRELOADS_6, 0, ABST_EXACT},
+  {"dcm", "DC_miss_commit", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_6, 0, ABST_EXACT},
+
+  {"lmh_spec", "DC_miss_local_mem_hit", REGNO_ANY, STXT ("Local Mem Speculative Hits"), PRELOADS_5, 0, ABST_NONE},
+  {"rmh_spec", "DC_miss_remote_mem_hit", REGNO_ANY, STXT ("Remote Mem Speculative Hits"), PRELOADS_5, 0, ABST_NONE},
+
+  {"dtlbm", "DTLB_HWTW", REGNO_ANY, STXT ("DTLB Misses"), PRELOAD (40, 5), 0, ABST_NONE}, // 10@l1 hit, 24@l2 hit, 60@l3 hit, 500@l3 miss, 5000@trap  0.001 events/cycle
+  {"dtlb_hwtw_stalls", "DTLB_HWTW", REGNO_ANY, STXT ("DTLB HWTW Est Stalls"), PRELOAD (40, 5), 25, ABST_NONE, STXT ("Estimated time stalled on a DTLB miss requiring a HW tablewalk")}, // l2-20, l3-50
+  {"dtlb_trap_stalls", "DTLB_HWTW_miss_trap", REGNO_ANY, STXT ("DTLB Trap Est Stalls"), PRELOAD (800, 5), 5000, ABST_NONE, STXT ("Estimated time stalled on a DTLB miss with HW tablewalk unsuccessful")}, // 5000@trap
+  {"rawhaz", "RAW_hit", REGNO_ANY, STXT ("Read-after-write Hazards"), PRELOAD (40, 5), 0, ABST_NONE},
+  {"br_msp_stalls", "Br_mispred", REGNO_ANY, STXT ("Branch Mispredict Stalls"), PRELOAD (40, 5), 24, ABST_NONE, STXT ("Estimated time stalled on Branch mispredictions")}, // 24@miss, %5 of branches is bad
+  {"br_msp", "Br_mispred", REGNO_ANY, STXT ("Branch Mispredict"), PRELOAD (40, 5), 0, ABST_NONE},
+  {"br_tkn", "Br_taken", REGNO_ANY, STXT ("Branch Taken"), PRELOADS_7, 0, ABST_NONE},
+  {"br_ins", "Branches", REGNO_ANY, STXT ("Branch Instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"fgu", "Instr_FGU_crypto", REGNO_ANY, STXT ("FP/VIS/Crypto Instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"spill_fill", "Flush_spill_fill", REGNO_ANY, STXT ("Reg Window Spill/Fill Est Stalls"), PRELOAD (100, 5), 80, ABST_NONE, STXT ("Estimated time stalled on flushing pipeline due to register window spill/fill")},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Counters that can be time converted, support memspace, or have a short_desc need to be in this table */
+  //0x01
+  {"Fetch_stall_IFU_reset_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_stall_IC_miss_MB_full_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_stall_IC_miss_MB_avail_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_stall_IC_miss_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_stall_ITLB_miss_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_stall_SEL_buf_full_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_ready_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_0_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_0_all_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  //0x02
+  {"Fetch_1_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_2_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_3_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_4_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_5_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_6_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_7_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_8_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  //0x07
+  {"ITLB_HWTW_hit_8K", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 8K page")},
+  {"ITLB_HWTW_hit_64K", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 64K page")},
+  {"ITLB_HWTW_hit_4M", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 4M page")},
+  {"ITLB_HWTW_hit_256M", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 256M page")},
+  {"ITLB_HWTW_hit_16G", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 16G page")},
+  {"ITLB_HWTW_hit_1T", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk successfully loaded translation for 1T page")},
+  //  { "ITLB_HWTW_miss_RA2PAC",               0x0740, 0xf07ff },
+  //  { "ITLB_HWTW_miss_not_RA2PAC",           0x0780, 0xf07ff },
+  {"ITLB_HWTW_miss_trap", NULL, REGNO_ANY, NULL, PRELOAD (1000, 5), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk unsuccessful")},
+  {"ITLB_HWTW", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk search done")},
+  //0x08
+  {"Br_BTC_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Branches delayed a few extra cycles because branch target not found in Branch Target Cache")},
+  //0x09
+  {"Sel_0_no_instr_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread stalls at Select because no instructions are available")},
+  {"Sel_0_pipe_drain_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread stalls at Select waiting with correct instructions when pipeline has to drain after branch misprediction")},
+  {"Sel_0_postsync_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread stalls at Select waiting for prior instructions to commit")},
+  {"Sel_0_presync_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread stalls at Select with instruction that cannot decode until prior instructions have committed")},
+  {"Sel_0_thread_hog_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread stalls at Select to prevent strand monopolizing resources")},
+  {"Sel_0_tag_stall_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread stalls at Select because no required tags are available")},
+  {"Sel_0_ready_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread was ready to have its instructions selected but another hardware thread was selected instead")},
+  {"Sel_0_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles a hardware thread is not selected")},
+  // No direct equivalent Sel_1/2_cyc. Nearest is Decode_uop, which increments by 0-4 each cycle according to how many uops were decoded.
+  //0x13
+  {"ITLB_HWTW_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk hit local L2D")},
+  {"ITLB_HWTW_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (80, 5), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk hit local L3 or neighbor L2D")},
+  {"ITLB_HWTW_L3_miss", NULL, REGNO_ANY, NULL, PRELOAD (800, 5), 0, ABST_NONE, STXT ("ITLB miss and HW tablewalk missed all local caches")},
+  {"DTLB_HWTW_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk hit local L2D")},
+  {"DTLB_HWTW_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (80, 5), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk hit local L3 or neighbor L2D")},
+  {"DTLB_HWTW_L3_miss", NULL, REGNO_ANY, NULL, PRELOAD (800, 5), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk missed all local caches")},
+  {"DTLB_HWTW_ref", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("DTLB miss requiring HW tablewalk")},
+  //0x0E
+  {"Instr_FGU_crypto", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("FP and VIS instructions completed by the Floating Point and Graphics Unit")},
+  {"Instr_ld", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("Load instructions completed")},
+  {"Instr_st", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("Store instructions completed")},
+  {"Instr_block_ld_st", NULL, REGNO_ANY, NULL, PRELOAD (20, 5), 0, ABST_EXACT, STXT ("Block load/store instructions completed")},
+  {"Instr_SPR_ring_ops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("Specialized instructions that require internal use of SPR ring completed")},
+  {"Instr_atomic", NULL, REGNO_ANY, NULL, PRELOAD (20, 5), 0, ABST_EXACT, STXT ("Atomic instructions, including CASA/XA, completed")},
+  {"Instr_SW_prefetch", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT, STXT ("PREFETCH and PREFETCHA instructions completed")},
+  {"Instr_other", NULL, REGNO_ANY, NULL, PRELOAD (2, 5), 0, ABST_NONE, STXT ("Basic arithmetic and logical instructions completed")},
+  {"Instr_all", NULL, REGNO_ANY, NULL, PRELOAD (1, 5), 0, ABST_NONE, STXT ("Total instructions completed")},
+  //0x0F
+  {"Branches", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Control transfer instructions completed, excluding trap-related transfers")},
+  //0x10
+  {"Br_taken", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Branch instructions taken and completed")},
+  //0x11
+  {"Rename_tag_wait_PQ_1_EXU_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Rename_tag_wait_PQ_0_LSU_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Rename_wait_crypto_diag_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Sel_0_wait_ROB_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Sel_0_wait_WRF_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Sel_0_wait_LB_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Sel_0_wait_SB_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  //0x12
+  {"Fetch_stall_BDA_tag_unavail_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_stall_BTA_tag_unavail_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_stall_misc_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"Fetch_stall_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"MMU_TTE_buffer_tag_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"MMU_PRQ_pool_tag_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  //0x15
+  {"L2I_request_block_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2I_thread_hog_stall_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2I_MB_full_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2I_snoop_eviction", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2I_stall_no_request_credit_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2I_stall_no_response_credit_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  //0x16
+  {"Flush_thread_hog", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes to prevent thread from monopolizing resources")},
+  {"Flush_br_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes due to a branch misprediction")},
+  {"Flush_arch_exception", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes due to SPARC architecture exceptions and trap entry/return")},
+  {"Flush_evil_twin", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes due to detecting floating point evil twin condition")},
+  {"Flush_LSU_trap", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes to refetch Next-PC")},
+  {"Flush_mode_change", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes due to strand mode change")},
+  {"Flush_misalign", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes due to detecting misaligned load/store requiring transition to misaligned mitigation mode")},
+  {"Flush_other", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes due to hardware thread state change to/from halted/paused state")},
+  {"Flush_all", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes due to any reason")},
+  //0x17
+  {"Flush_spill_n_normal", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes due to spill_n_normal exception")},
+  {"Flush_spill_n_other", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes due to spill_n_other exception")},
+  {"Flush_fill_n_normal", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes due to fill_n_normal exception")},
+  {"Flush_fill_n_other", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes due to fill_n_other exception")},
+  {"Flush_spill_fill", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes due to spill/fill exceptions")},
+  {"Flush_lost_load", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Pipeline flushes due to speculatively executed load violating memory order")},
+  //0x21
+  {"Br_dir_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Branch instructions completed whose direction was mispredicted")},
+  {"Br_tgt_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Branch instructions completed whose target was mispredicted")},
+  {"Br_mispred", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Branch instructions completed whose direction or target was mispredicted")},
+  //0x23
+  {"LSU_st_q_tag_wait_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LSU_st_q_tag_wait_all_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2D_stall_no_request_credit_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2D_stall_no_response_credit_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  //0x27
+  {"DC_miss_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD (20, 5), 0, ABST_NONE, STXT ("Loads that speculatively hit local L2D")},
+  {"DC_miss_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Loads that speculatively hit local L3")},
+  {"DC_miss_L3_dirty_copyback", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Loads that speculatively hit local L3 but require copyback from L2D within same CPC")},
+  {"DC_miss_nbr_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (100, 5), 0, ABST_NONE, STXT ("Loads that speculatively hit neighbor L3 on same socket")},
+  {"DC_miss_remote_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (400, 5), 0, ABST_NONE, STXT ("Loads that speculatively hit remote cache on different socket")},
+  {"DC_miss_local_mem_hit", NULL, REGNO_ANY, NULL, PRELOAD (500, 5), 0, ABST_NONE, STXT ("Loads that speculatively hit local memory")},
+  {"DC_miss_remote_mem_hit", NULL, REGNO_ANY, NULL, PRELOAD (1000, 5), 0, ABST_NONE, STXT ("Loads that speculatively hit remote memory")},
+  {"DC_miss", NULL, REGNO_ANY, NULL, PRELOAD (10, 5), 0, ABST_NONE, STXT ("Loads that speculatively missed local L1D")},
+  //0x28
+  {"DC_sec_miss_L2_hit_commit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT},
+  {"DC_miss_L2_hit_commit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT},
+  {"DC_miss_L3_hit_commit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT},
+  {"DC_miss_L3_dirty_copyback_commit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT},
+  {"DC_miss_nbr_L3_hit_commit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT},
+  {"DC_miss_remote_L3_hit_commit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT},
+  {"DC_miss_local_mem_hit_commit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT},
+  {"DC_miss_remote_mem_hit_commit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_EXACT},
+  {"DC_miss_commit", NULL, REGNO_ANY, NULL, PRELOAD (25, 5), 0, ABST_EXACT, STXT ("Loads that missed local L1D")},
+  //0x29
+  //  {"Store_DC_sec_miss_L2_hit",      NULL, REGNO_ANY, NULL, PRELOAD_DEF,     0, ABST_NONE,  STXT("")},
+  {"Store_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD (20, 5), 0, ABST_NONE, STXT ("Stores whose cacheline being updated was in local L2D")},
+  {"Store_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Stores whose cacheline being updated was in local L3")},
+  {"Store_nbr_L2_hit", NULL, REGNO_ANY, NULL, PRELOAD (100, 5), 0, ABST_NONE, STXT ("Stores whose cacheline being updated was in neighbor L2 on same socket")},
+  {"Store_nbr_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (100, 5), 0, ABST_NONE, STXT ("Stores whose cacheline being updated was in neighbor L3 on same socket")},
+  {"Store_remote_L3_hit", NULL, REGNO_ANY, NULL, PRELOAD (400, 5), 0, ABST_NONE, STXT ("Stores whose cacheline being updated was in remote cache on different socket")},
+  {"Store_local_mem_hit", NULL, REGNO_ANY, NULL, PRELOAD (500, 5), 0, ABST_NONE, STXT ("Stores whose cacheline being updated was in local memory")},
+  {"Store_remote_mem_hit", NULL, REGNO_ANY, NULL, PRELOAD (1000, 5), 0, ABST_NONE, STXT ("Stores whose cacheline being updated was in remote memory")},
+  {"Store_all", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE, STXT ("Stores whose cacheline being updated was observed to be somewhere in the memory hierarchy")},
+  //0x2d
+  {"RAW_hit_st_buf", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Loads delayed by a previous store (read-after-write) still in store buffer not yet committed")},
+  {"RAW_hit_st_q", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Loads delayed by a previous store (read-after-write) committed but in store queue not yet written to L2D")},
+  {"RAW_hit", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("Loads delayed by a previous store (read-after-write hazards)")},
+  //0x2f
+  {"Cycles_user_non_MLA", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"Cycles_user_MLA", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"Cycles_user", NULL, REGNO_ANY, NULL, PRELOAD (1, 5), 1, ABST_NONE, STXT ("Cycles hardware thread is active in specified mode(s)")},
+  //0x37
+  {"DTLB_HWTW_hit_8K", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 8K page")},
+  {"DTLB_HWTW_hit_64K", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 64K page")},
+  {"DTLB_HWTW_hit_4M", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 4M page")},
+  {"DTLB_HWTW_hit_256M", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 256M page")},
+  {"DTLB_HWTW_hit_16G", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 16G page")},
+  {"DTLB_HWTW_hit_1T", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk successfully loaded translation for 1T page")},
+  {"DTLB_HWTW_miss_trap", NULL, REGNO_ANY, NULL, PRELOAD (800, 5), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk unsuccessful")},
+  {"DTLB_HWTW", NULL, REGNO_ANY, NULL, PRELOAD (40, 5), 0, ABST_NONE, STXT ("DTLB miss and HW tablewalk search done")},
+  //0x3f
+  {"Commit_0_cyc", /*22825776*/ NULL, 3, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles no uop commits from this hardware thread")},
+  {"Commit_0_all_cyc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE, STXT ("Cycles no uop commits from any hardware thread on this core")},
+  // Similar situation to Sel_1_cyc etc. No direct equivalent, nearest is Commit_uop, which increments by 0-4 each cycle according to how many uops were committed.
+
+  /* additional (hidden) aliases, for convenience */
+  {"cycles0", "Cycles_user", 0, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"cycles1", "Cycles_user", 1, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"insts0", "Instr_all", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "Instr_all", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry usfuji_V_list[] = {
+  {"cycles", "cycle_counts", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"insts", "instruction_counts", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_7, 0, ABST_NONE},
+  {"flops", "floating_instructions", REGNO_ANY, STXT ("Floating-point Ops"), PRELOADS_6, 0, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {"cycle_counts", NULL, REGNO_ANY, NULL, PRELOADS_7, 1, ABST_NONE},
+  {"load_store_instructions", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE},
+
+  /* additional (hidden) aliases for convenience */
+  {"cycles0", "cycle_counts", 0, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"cycles1", "cycle_counts", 1, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"insts0", "instruction_counts", 0, NULL, PRELOADS_75, 0, ABST_NONE},
+  {"insts1", "instruction_counts", 1, NULL, PRELOADS_75, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry usfuji_VI_VII_list[] = {
+  {"cycles", "cycle_counts", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "instruction_counts", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+  {"dcm", "op_r_iu_req_mi_go", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_6, 0, ABST_NONE},
+  {"dcstall", "op_wait_all", REGNO_ANY, STXT ("L1 D-cache Stall Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"dtlbm", "write_op_uTLB", REGNO_ANY, STXT ("DTLB Misses"), PRELOADS_5, 0, ABST_NONE},
+  // l2m: mem_cache_load test shows undercount of 3x, however, we don't care too much about this chip, keeping the alias for now
+  {"l2m", "sx_miss_count_dm", REGNO_ANY, STXT ("L2 Cache Misses"), PRELOADS_5, 0, ABST_NONE}, /*YXXX undercounts?*/
+  {"l2wm", "dvp_count_dm", REGNO_ANY, STXT ("L2 Cache Writeback Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"l2ref", "sx_read_count_dm", REGNO_ANY, STXT ("L2 Cache Refs"), PRELOADS_6, 0, ABST_NONE},
+  {"l2stall", "sx_miss_wait_dm", REGNO_ANY, STXT ("L2 Cache Stall Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"icm", "if_r_iu_req_mi_go", REGNO_ANY, STXT ("L1 I-cache Misses"), PRELOADS_6, 0, ABST_NONE},
+  {"icstall", "if_wait_all", REGNO_ANY, STXT ("L1 I-cache Stall Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"itlbm", "write_if_uTLB", REGNO_ANY, STXT ("ITLB Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"flops", "floating_instructions", REGNO_ANY, STXT ("Floating-point Ops"), PRELOADS_7, 0, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {"cycle_counts", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"op_stv_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"load_store_instructions", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE},
+  {"active_cycle_count", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_sxmiss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"branch_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"write_op_uTLB", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE},
+  {"sx_miss_wait_pf", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"sx_miss_wait_dm", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_nc_pend", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_sxmiss_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"eu_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"sx_miss_count_dm", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE},
+  {"fl_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_r_iu_req_mi_go", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE},
+  {"sx_miss_count_dm_if", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE},
+  {"op_stv_wait_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"swpf_lbs_hit", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE},
+  {"sx_read_count_dm", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE},
+  {"trap_DMMU_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE},
+  {"op_wait_all", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"sx_miss_count_dm_opex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE},
+  {"if_wait_all", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"dvp_count_dm", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE},
+  {"sx_miss_count_dm_opsh", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 0, ABST_NONE},
+
+  /* additional (hidden) aliases for convenience */
+  {"cycles0", "cycle_counts", 0, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"cycles1", "cycle_counts", 1, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"insts0", "instruction_counts", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "instruction_counts", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+
+static Hwcentry usfuji_X_list[] = {
+  {"cycles", "cycle_counts", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "instruction_counts", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+  {"dcm", "L1D_miss", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_65, 0, ABST_NONE},
+  {"dcstall", "L1D_wait_all", REGNO_ANY, STXT ("L1 D-cache Stall Cycles"), PRELOADS_7, 1, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {"cycle_counts", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"w_op_stv_wait_nc_pend", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"eu_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_pf_bank0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_pfp_busy_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_dm_bank0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_branch_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_sxmiss_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_nc_pend", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_pf_bank2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_eu_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_sxmiss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_sxmiss_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"branch_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_dm_bank2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"d_move_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_fl_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_pfp_busy", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"fl_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_pf_bank1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_dm_bank1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_sxmiss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_swpf", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L1D_wait_all", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_pf_bank3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"cse_priority_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_pfp_busy_swpf", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L1I_wait_all", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_dm_bank3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"single_mode_cycle_counts", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"suspend_cycle", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"sleep_cycle", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  /* additional (hidden) aliases for convenience */
+  {"cycles0", "cycle_counts", 0, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"cycles1", "cycle_counts", 1, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"insts0", "instruction_counts", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "instruction_counts", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry usfuji_XII_list[] = {
+  {"cycles", "cycle_counts", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "instruction_counts", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+  {"dcm", "L1D_miss", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_65, 0, ABST_NONE},
+  {"dcstall", "L1D_wait_all", REGNO_ANY, STXT ("L1 D-cache Stall Cycles"), PRELOADS_7, 1, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {"cycle_counts", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"L1D_wait_all", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L1I_wait_all", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_dm_bank0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_dm_bank1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_dm_bank2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_dm_bank3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_pf_bank0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_pf_bank1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_pf_bank2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"L2_miss_wait_pf_bank3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LL_miss_wait_dm_bank0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LL_miss_wait_dm_bank1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LL_miss_wait_dm_bank2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LL_miss_wait_dm_bank3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LL_miss_wait_pf_bank0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LL_miss_wait_pf_bank1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LL_miss_wait_pf_bank2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"LL_miss_wait_pf_bank3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"branch_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"cse_priority_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"d_move_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"eu_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"fl_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"l2_sy_miss_wait_dm_part1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"l2_sy_miss_wait_dm_part2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"msgr_reqp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"msgr_rtnp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"msgs_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_l1d_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_l1d_miss_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_l2_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_l2_miss_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_ll_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_ll_miss_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_nc_pend", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_pfp_busy", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_pfp_busy_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_pfp_busy_swpf", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_swpf", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_sxmiss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"op_stv_wait_sxmiss_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_branch_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_eu_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_fl_comp_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_l1d_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_l1d_miss_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_l2_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_l2_miss_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_ll_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_ll_miss_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_nc_pend", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_pfp_busy", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_pfp_busy_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_pfp_busy_swpf", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_sxmiss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"w_op_stv_wait_sxmiss_ex", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {"single_mode_cycle_counts", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"suspend_cycle", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"sleep_cycle", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  /* additional (hidden) aliases for convenience */
+  {"cycles0", "cycle_counts", 0, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"cycles1", "cycle_counts", 1, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"insts0", "instruction_counts", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "instruction_counts", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+/* Kernel profiling pseudo-chip, OBSOLETE (To support 12.3 and earlier, TBR) */
+static Hwcentry kproflist[] = {
+  {"kcycles", "kcycles", 0, STXT ("KCPU Cycles"), PRELOADS_5, 1, ABST_NONE},
+  {"kucycles", "kucycles", 0, STXT ("KUCPU Cycles"), PRELOADS_5, 1, ABST_NONE},
+  {"kthr", "kthr", 0, STXT ("KTHR Cycles"), PRELOADS_5, 1, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry pentiumIIlist[] = {
+  /*  note -- missing entries for dtlbm, ecm */
+  {"cycles", "cpu_clk_unhalted", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"insts", "inst_retired", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_7, 0, ABST_NONE},
+  {"icm", "ifu_ifetch_miss", REGNO_ANY, STXT ("I$ Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"dcrm", "dcu_m_lines_in", REGNO_ANY, STXT ("D$ Read Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"dcwm", "dcu_m_lines_out", REGNO_ANY, STXT ("D$ Write Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"flops", "flops", REGNO_ANY, STXT ("Floating-point Ops"), PRELOADS_7, 0, ABST_NONE},
+  {"itlbm", "itlb_miss", REGNO_ANY, STXT ("ITLB Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"ecim", "l2_ifetch", REGNO_ANY, STXT ("E$ Instr. Misses"), PRELOADS_5, 0, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {"cpu_clk_unhalted", NULL, REGNO_ANY, NULL, PRELOADS_7, 1, ABST_NONE},
+
+  /* additional (hidden) aliases for convenience */
+  {"cycles0", "cpu_clk_unhalted", 0, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"cycles1", "cpu_clk_unhalted", 1, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"insts0", "inst_retired", 0, NULL, PRELOADS_75, 0, ABST_NONE},
+  {"insts1", "inst_retired", 1, NULL, PRELOADS_75, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry pentiumIIIlist[] = {
+  /*  note -- many missing entries; no reference machine to try */
+  {"cycles", "cpu_clk_unhalted", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"insts", "inst_retired", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_7, 0, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {"cpu_clk_unhalted", NULL, REGNO_ANY, NULL, PRELOADS_7, 1, ABST_NONE},
+
+  /* additional (hidden) aliases for convenience */
+  {"cycles0", "cpu_clk_unhalted", 0, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"cycles1", "cpu_clk_unhalted", 1, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"insts0", "inst_retired", 0, NULL, PRELOADS_75, 0, ABST_NONE},
+  {"insts1", "inst_retired", 1, NULL, PRELOADS_75, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry pentium4[] = {
+  {"cycles", "TC_deliver_mode~threshold=0xf~complement=1~compare=1", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"insts", "instr_retired~emask=0x3", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_7, 0, ABST_NONE},
+  {"l1m", "BSQ_cache_reference~emask=0x0507", REGNO_ANY, STXT ("L1 Cache Misses"), PRELOADS_7, 0, ABST_NONE},
+  {"l2h", "BSQ_cache_reference~emask=0x0007", REGNO_ANY, STXT ("L2 Cache Hits"), PRELOADS_7, 0, ABST_NONE},
+  {"l2m", "BSQ_cache_reference~emask=0x0500", REGNO_ANY, STXT ("L2 Cache Misses"), PRELOADS_6, 0, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {"TC_deliver_mode", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"machine_clear", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  /* additional (hidden) aliases, for convenience */
+  {"cycles0", "TC_deliver_mode~threshold=0xf~complement=1~compare=1", 5, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"cycles1", "TC_deliver_mode~threshold=0xf~complement=1~compare=1", 6, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"insts0", "instr_retired~emask=0x3", 15, NULL, PRELOADS_75, 0, ABST_NONE},
+  {"insts1", "instr_retired~emask=0x3", 16, NULL, PRELOADS_75, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry intelCore2list[] = {
+  // For post-processing, both Linux and Solaris definitions need to be "live".
+  // However, for data collection, OS-specific definitions may need to be hidden.
+  // Use REGNO_INVALID for definitions that should be hidden for data collection.
+#define LINUX_ONLY   REGNO_ANY
+#define SOLARIS_ONLY REGNO_INVALID /* hidden for Linux data collection */
+
+  {"cycles", "cpu_clk_unhalted.core", /*6759307*/ SOLARIS_ONLY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"cycles", "cpu_clk_unhalted.thread", /*6759307*/ SOLARIS_ONLY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  /* Linux Note: 7046312 Many HWC tests fail on system Core2 system with perf_events if above alias used */
+  {"cycles", "cpu_clk_unhalted", LINUX_ONLY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+
+  {"insts", "instr_retired.any", SOLARIS_ONLY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+  /* Linux Note: 7046312 Many HWC tests fail on system Core2 system with perf_events if above alias used */
+  {"insts", "inst_retired", LINUX_ONLY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+
+  // The following counters were identified in "Cycle Accounting Analysis on Intel Core2 Processors" by David Levinthal
+  {"uops_stalled", "rs_uops_dispatched~cmask=1~inv=1", REGNO_ANY, STXT ("uOps Stalled"), PRELOADS_7, 1, ABST_NONE},
+  {"l2m", "mem_load_retired~umask=0x08", REGNO_ANY, STXT ("L2 Line Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"dtlbm", "mem_load_retired~umask=0x10", REGNO_ANY, STXT ("L1 DTLB Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"l1m", "mem_load_retired~umask=0x02", REGNO_ANY, STXT ("L1 Line Misses"), PRELOADS_6, 0, ABST_NONE},
+  // {"stalls_resources","resource_stalls~umask=0x1f",         REGNO_ANY, STXT("Resource Stalls"),             PRELOADS_6, 1, ABST_NONE},
+  {"rs_full", "resource_stalls~umask=0x02", REGNO_ANY, STXT ("Reservation Station Full"), PRELOADS_6, 1, ABST_NONE},
+  {"br_miss_flush", "resource_stalls~umask=0x10", REGNO_ANY, STXT ("Mispredicted Branch Flushes"), PRELOADS_6, 1, ABST_NONE},
+  {"ld_st_full", "resource_stalls~umask=0x04", REGNO_ANY, STXT ("Load/Store Buffers Full"), PRELOADS_6, 1, ABST_NONE},
+  {"rob_full", "resource_stalls~umask=0x01", REGNO_ANY, STXT ("Reorder Buffer Full"), PRELOADS_6, 1, ABST_NONE},
+  {"slow_decode", "ild_stall", REGNO_ANY, STXT ("Slow Instruction Decode"), PRELOADS_6, 1, ABST_NONE},
+  {"br_miss", "br_cnd_missp_exec", REGNO_ANY, STXT ("Mispredicted Branches"), PRELOADS_5, 0, ABST_NONE},
+  {"ret_miss", "br_call_missp_exec", REGNO_ANY, STXT ("Mispredicted Return Calls"), PRELOADS_5, 0, ABST_NONE},
+  {"div_busy", "idle_during_div", REGNO_ANY, STXT ("Divider Unit Busy"), PRELOADS_5, 1, ABST_NONE},
+  {"fp_assists", "fp_assist", REGNO_ANY, STXT ("FP Microcode Assists"), PRELOADS_5, 0, ABST_NONE},
+  {"bus_busy", "bus_drdy_clocks~umask=0x60", REGNO_ANY, STXT ("Busy Data Bus"), PRELOADS_5, 1, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {/*30a*/"cpu_clk_unhalted.core", /*6759307*/ NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*30a*/"cpu_clk_unhalted.thread", /*6759307*/ NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*03*/"store_block", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*03*/"store_block.drain_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*03*/"store_block.order", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*03*/"store_block.snoop", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*09*/"memory_disambiguation.reset", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0c*/"page_walks.cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*14*/"cycles_div_busy", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*18*/"idle_during_div", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*19*/"delayed_bypass.load", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*21*/"l2_ads", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*23*/"l2_dbus_busy_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*32*/"l2_no_req", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*3c*/"cpu_clk_unhalted", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*3c*/"cpu_clk_unhalted.core_p", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*3c*/"cpu_clk_unhalted.bus", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*3c*/"cpu_clk_unhalted.no_other", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*42*/"l1d_cache_lock.duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*62*/"bus_drdy_clocks", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*63*/"bus_lock_clocks", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*64*/"bus_data_rcv", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*7a*/"bus_hit_drv", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*7b*/"bus_hitm_drv", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*7d*/"busq_empty", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*7e*/"snoop_stall_drv", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*7f*/"bus_io_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*83*/"inst_queue", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*83*/"inst_queue.full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*86*/"cycles_l1i_mem_stalled", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*87*/"ild_stall", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1*/"rs_uops_dispatched", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1*/"rs_uops_dispatched_port", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1*/"rs_uops_dispatched_port.0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1*/"rs_uops_dispatched_port.1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1*/"rs_uops_dispatched_port.2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1*/"rs_uops_dispatched_port.3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1*/"rs_uops_dispatched_port.4", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1*/"rs_uops_dispatched_port.5", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*6c*/"cycles_int", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*6c*/"cycles_int.masked", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*6c*/"cycles_int.pending_and_masked", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d2*/"rat_stalls", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d2*/"rat_stalls.rob_read_port", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d2*/"rat_stalls.partial_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d2*/"rat_stalls.flags", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d2*/"rat_stalls.fpsw", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d2*/"rat_stalls.any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d2*/"rat_stalls.other_serialization_stalls", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d4*/"seg_rename_stalls", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d4*/"seg_rename_stalls.es", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d4*/"seg_rename_stalls.ds", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d4*/"seg_rename_stalls.fs", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d4*/"seg_rename_stalls.gs", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d4*/"seg_rename_stalls.any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*dc*/"resource_stalls", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*dc*/"resource_stalls.rob_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*dc*/"resource_stalls.rs_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*dc*/"resource_stalls.ld_st", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*dc*/"resource_stalls.fpcw", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*dc*/"resource_stalls.br_miss_clear", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*dc*/"resource_stalls.any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  /* "Architectural" events: */
+  {/*3c*/"unhalted-core-cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  /* additional (hidden) aliases for convenience */
+  {"cycles0", "cpu_clk_unhalted", 0, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"cycles1", "cpu_clk_unhalted", 1, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"insts0", "inst_retired", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "inst_retired", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+
+static Hwcentry intelNehalemList[] = {
+  /* 6832635: on Linux, we're not seeing consistent overflows on FFCs */
+  /* 15634344==6940930: HWC overflow profiling can cause system hang on Solaris/core-i7 systems */
+  /* 17578620: counter overflow for fixed-function counters hangs systems */
+  /* same issues for intelSandyBridgeList and intelHaswellList */
+  PERF_EVENTS_SW_EVENT_ALIASES
+  USE_INTEL_REF_CYCLES (133)
+  {"cycles", "cpu_clk_unhalted.thread_p", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "inst_retired.any_p", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+  // cpu_clk_unhalted.ref: at the ref requency of the cpu. Should not be affected by Speedstep or Turbo.
+  // cpu_clk_unhalted.thread_p: with HT & 2 threads, 2x cycles.  Affected by Speedstep and Turbo.
+
+  // PEBs (Sampling)
+  {"l2m_latency", "mem_inst_retired.latency_above_threshold", REGNO_ANY, STXT ("L2 Cache Miss Est. Latency"), PRELOADS_4, 33, ABST_EXACT_PEBS_PLUS1},
+
+  // See file hwctable.README.corei7
+  {"dch", "mem_load_retired.l1d_hit", REGNO_ANY, STXT ("L1 D-cache Hits"), PRELOADS_7, 0, ABST_NONE},
+  {"dcm", "0xCB~umask=0x1e", REGNO_ANY, STXT ("L1 D-Cache Misses"), PRELOADS_65, 0, ABST_NONE}, /*mem_load_retired*/
+  {"lfbdh", "mem_load_retired.hit_lfb", REGNO_ANY, STXT ("LFB D-cache Hits"), PRELOADS_65, 0, ABST_NONE},
+  {"l2h", "mem_load_retired.l2_hit", REGNO_ANY, STXT ("L2 Cache Hits"), PRELOADS_65, 0, ABST_NONE},
+  {"l2m", "0xCB~umask=0x1c", REGNO_ANY, STXT ("L2 Cache Misses"), PRELOADS_6, 0, ABST_NONE}, /*mem_load_retired*/
+  {"l3h", "mem_load_retired.llc_unshared_hit", REGNO_ANY, STXT ("L3 Cache Hit w/o Snoop"), PRELOADS_6, 0, ABST_NONE},
+  {"l3h_stall", "mem_load_retired.llc_unshared_hit", REGNO_ANY, STXT ("L3 Cache Hit w/o Snoop x 35: Est. Stalls"), PRELOADS_6, 35, ABST_NONE},
+  {"l3hsnoop", "mem_load_retired.other_core_l2_hit_hitm", REGNO_ANY, STXT ("L3 Cache Hit w/Snoop"), PRELOADS_6, 0, ABST_NONE},
+  {"l3hsnoop_stall", "mem_load_retired.other_core_l2_hit_hitm", REGNO_ANY, STXT ("L3 Cache Hit w/Snoop x 74: Est. Stalls"), PRELOADS_6, 74, ABST_NONE},
+  {"l3m", "mem_load_retired.llc_miss", REGNO_ANY, STXT ("L3 Cache Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"l3m_stall", "mem_load_retired.llc_miss", REGNO_ANY, STXT ("L3 Cache Misses x 180: Estimated Stalls"), PRELOADS_5, 180, ABST_NONE},
+  {"dtlbm", "dtlb_load_misses.walk_completed", REGNO_ANY, STXT ("DTLB Misses"), PRELOADS_6, 0, ABST_NONE},
+  {"dtlbm_stall", "dtlb_load_misses.walk_completed", REGNO_ANY, STXT ("DTLB Misses x 30: Estimated Stalls"), PRELOADS_6, 30, ABST_NONE},
+  {"addr_alias_stall", "partial_address_alias", REGNO_ANY, STXT ("Partial Address Aliases x 3: Est. Stalls"), PRELOADS_6, 3, ABST_NONE},
+  {"uope_stall", "uops_executed.port234~cmask=1~inv=1", REGNO_ANY, STXT ("UOP Execute Stalls per Core"), PRELOADS_7, 1, ABST_NONE},
+  {"uopr_stall", "uops_retired.any~cmask=1~inv=1", REGNO_ANY, STXT ("UOP Retired Stalls"), PRELOADS_7, 1, ABST_NONE},
+  {"itlbm", "itlb_miss_retired", REGNO_ANY, STXT ("ITLB Misses"), PRELOADS_6, 0, ABST_NONE},
+  {"l1i_stall", "l1i.cycles_stalled", REGNO_ANY, STXT ("L1 I-cache Stalls"), PRELOADS_6, 1, ABST_NONE},
+  {"br_rets", "br_inst_retired.all_branches", REGNO_ANY, STXT ("Branch Instruction Retires"), PRELOADS_7, 0, ABST_NONE},
+  {"br_misp", "br_misp_exec.any", REGNO_ANY, STXT ("Branch Mispredicts"), PRELOADS_6, 0, ABST_NONE},
+  {"mach_clear", "machine_clears.cycles", REGNO_ANY, STXT ("Machine Clear Asserted"), PRELOADS_6, 1, ABST_NONE},
+  {"fp_mmx", "fp_mmx_trans.any", REGNO_ANY, STXT ("FP-MMX Transistions"), PRELOADS_6, 0, ABST_NONE},
+  {"div_busy", "arith.cycles_div_busy", REGNO_ANY, STXT ("Divider Busy Cycles"), PRELOADS_6, 1, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {/*30a*/"cpu_clk_unhalted.core", /*6759307*/ NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*30a*/"cpu_clk_unhalted.thread", /*6759307*/ NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*04*/"sb_drain.cycles", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*08.04*/"dtlb_load_misses.walk_cycles", /*westmere*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  //{/*0e*/"uops_issued.stalled_cycles",/*future, multibit*/           NULL, REGNO_ANY, NULL, PRELOAD_DEF,     1, ABST_NONE},
+  {/*09*/"memory_disambiguation.reset", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*09*/"memory_disambiguation.watch_cycles", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0b*/"mem_inst_retired.latency_above_threshold", /*PEBS*/ NULL, REGNO_ANY, NULL, PRELOADS_4, 33, ABST_EXACT_PEBS_PLUS1}, //non-standard overflow
+  {/*14*/"arith.cycles_div_busy", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*17*/"inst_queue_write_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*1d*/"hw_int.cycles_masked", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*1d*/"hw_int.cycles_pending_and_masked", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*3c*/"cpu_clk_unhalted.thread_p", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*48*/"l1d_pend_miss.load_buffers_full", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*49.04*/"dtlb_misses.walk_cycles", /*westmere*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*4e*/"sfence_cycles", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*4f.10*/"ept.walk_cycles", /*westmere*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60*/"offcore_requests_outstanding.demand.read_data", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60*/"offcore_requests_outstanding.demand.read_code", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60*/"offcore_requests_outstanding.demand.rfo", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60*/"offcore_requests_outstanding.any.read", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*63*/"cache_lock_cycles.l1d", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*63*/"cache_lock_cycles.l1d_l2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*80*/"l1i.cycles_stalled", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*85*/"itlb_misses.walk_cycles", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*85*/"itlb_misses.pmh_busy_cycles", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*87*/"ild_stall.lcp", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*87*/"ild_stall.mru", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*87*/"ild_stall.iq_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*87*/"ild_stall.regen", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*87*/"ild_stall.any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2*/"resource_stalls.any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2*/"resource_stalls.load", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2*/"resource_stalls.rs_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2*/"resource_stalls.store", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2*/"resource_stalls.rob_full", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2*/"resource_stalls.fpcw", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2*/"resource_stalls.mxcsr", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2*/"resource_stalls.other", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b0*/"offcore_requests_sq_full", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b3*/"snoopq_requests_outstanding.data", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b3*/"snoopq_requests_outstanding.invalidate", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b3*/"snoopq_requests_outstanding.code", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  //{/*c2*/"uops_retired.stalled_cycles",/*future, multibit*/          NULL, REGNO_ANY, NULL, PRELOAD_DEF,     1, ABST_NONE},
+  {/*c3*/"machine_clears.cycles", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d2*/"rat_stalls.flags", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d2*/"rat_stalls.registers", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d2*/"rat_stalls.rob_read_port", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d2*/"rat_stalls.scoreboard", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d2*/"rat_stalls.any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*d4*/"seg_rename_stalls", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*f6*/"sq_full_stall_cycles", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  /* "Architectural" events: */
+  {/*3c*/"unhalted-core-cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  PERF_EVENTS_SW_EVENT_DEFS
+
+  /* additional (hidden) aliases for convenience */
+#if 0
+  USE_INTEL_REF_CYCLES (133),
+#endif
+  {"insts0", "inst_retired.any_p", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "inst_retired.any_p", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+
+static Hwcentry intelSandyBridgeList[] = {
+  /* see comments for "cycles" and "insts" for intelNehalemList */
+  PERF_EVENTS_SW_EVENT_ALIASES
+  USE_INTEL_REF_CYCLES (100)
+  {"cycles", "cpu_clk_unhalted.thread_p", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "inst_retired.any_p", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+
+  // PEBS (sampling)
+  {"l2m_latency", "mem_trans_retired.load_latency", REGNO_ANY, STXT ("L2 Cache Miss Est. Latency"), PRELOADS_4, 65, ABST_EXACT_PEBS_PLUS1},
+
+  // See file hwctable.README.sandybridge
+  {"dch", "mem_load_uops_retired.l1_hit", REGNO_ANY, STXT ("L1 D-cache Hits"), PRELOADS_7, 0, ABST_NONE},
+  {"dcm", "mem_load_uops_retired.l1_miss", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_65, 0, ABST_NONE}, /*mem_load_uops_retired*/
+  {"l2h", "mem_load_uops_retired.l2_hit", REGNO_ANY, STXT ("L2 Cache Hits"), PRELOADS_65, 0, ABST_NONE},
+  {"l2m", "mem_load_uops_retired.l2_miss", REGNO_ANY, STXT ("L2 Cache Misses"), PRELOADS_6, 0, ABST_NONE}, /*mem_load_uops_retired*/
+  // Intel errata:  BT241 and BT243 says the mem_load_uops_retired.llc* counters may not be reliable on some CPU variants
+  {"l3h", "mem_load_uops_retired.llc_hit", REGNO_ANY, STXT ("L3 Cache Hit w/o Snoop"), PRELOADS_6, 0, ABST_NONE}, // may undercount
+  {"l3m", "longest_lat_cache.miss", REGNO_ANY, STXT ("L3 Cache Misses"), PRELOADS_5, 0, ABST_NONE},
+
+  /* dtlbm has not been confirmed via Intel white paper */
+  {"dtlbm", "dtlb_load_misses.walk_completed", REGNO_ANY, STXT ("DTLB Misses"), PRELOADS_6, 0, ABST_NONE},
+  {"dtlbm_stall", "dtlb_load_misses.walk_completed", REGNO_ANY, STXT ("DTLB Misses x 30: Estimated Stalls"), PRELOADS_6, 30, ABST_NONE},
+  {"dtlbm", "dtlb_load_misses.demand_ld_walk_completed", REGNO_ANY, STXT ("DTLB Misses"), PRELOADS_6, 0, ABST_NONE},
+  {"dtlbm_stall", "dtlb_load_misses.demand_ld_walk_completed", REGNO_ANY, STXT ("DTLB Misses x 30: Estimated Stalls"), PRELOADS_6, 30, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {/* 30a */"cpu_clk_unhalted.thread", /*15634344==6940930*/ NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  //{/* 30a */"cpu_clk_unhalted.core",  /*6759307*/                    NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*08.04*/"dtlb_load_misses.walk_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*08.84*/"dtlb_load_misses.demand_ld_walk_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d.03*/"int_misc.recovery_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d.40*/"int_misc.rat_stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0e.01*/"uops_issued.stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0e.01*/"uops_issued.core_stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*14.01*/"arith.fpu_div_active", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*3c.00*/"cpu_clk_unhalted.thread_p", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*48.01*/"l1d_pend_miss.pending_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*49.04*/"dtlb_store_misses.walk_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*59.20*/"partial_rat_stalls.flags_merge_uop", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*59.20*/"partial_rat_stalls.flags_merge_uop_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*59.40*/"partial_rat_stalls.slow_lea_window", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  //{/*59.80*/"partial_rat_stalls.mul_single_uop",                     NULL, REGNO_ANY, NULL, PRELOAD_DEF,     1, ABST_NONE},
+  {/*5b.0c*/"resource_stalls2.all_fl_empty", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5b.0f*/"resource_stalls2.all_prf_control", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5b.40*/"resource_stalls2.bob_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5b.4f*/"resource_stalls2.ooo_rsrc", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5c.01*/"cpl_cycles.ring0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5c.02*/"cpl_cycles.ring123", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5c.xx*/"cpl_cycles.ring0_trans", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5c.xx*/"cpl_cycles.ring0_transition", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5e.01*/"rs_events.empty_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.01*/"offcore_requests_outstanding.cycles_with_demand_data_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.01*/"offcore_requests_outstanding.demand_data_rd_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.04*/"offcore_requests_outstanding.cycles_with_demand_rfo", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.04*/"offcore_requests_outstanding.demand_rfo_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.08*/"offcore_requests_outstanding.cycles_with_data_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.08*/"offcore_requests_outstanding.all_data_rd_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.02*/"offcore_requests_outstanding.demand_code_rd_cycles", /*?*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*63.01*/"lock_cycles.split_lock_uc_lock_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*63.02*/"lock_cycles.cache_lock_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.00*/"idq.empty", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.04*/"idq.mite_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.08*/"idq.dsb_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.10*/"idq.ms_dsb_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.20*/"idq.ms_mite_uops_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.20*/"idq.ms_mite_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.30*/"idq.ms_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.18*/"idq.all_dsb_cycles_any_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.18*/"idq.all_dsb_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.18*/"idq.all_dsb_cycles_4_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.24*/"idq.all_mite_cycles_any_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.24*/"idq.all_mite_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.24*/"idq.all_mite_cycles_4_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.3c*/"idq.mite_all_cycles", /* Linux, but not in docs? */ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*80.04*/"icache.ifetch_stall", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*85.04*/"itlb_misses.walk_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*87.01*/"ild_stall.lcp", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*87.04*/"ild_stall.iq_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.xx*/"idq_uops_not_delivered.cycles_0_uops_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.xx*/"idq_uops_not_delivered.cycles_le_1_uop_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.xx*/"idq_uops_not_delivered.cycles_le_2_uop_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.xx*/"idq_uops_not_delivered.cycles_le_3_uop_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.01*/"idq_uops_not_delivered.cycles_ge_1_uop_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.01*/"idq_uops_not_delivered.cycles_fe_was_ok", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.01*/"uops_executed_port.port_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.02*/"uops_executed_port.port_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.04*/"uops_executed_port.port_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.08*/"uops_executed_port.port_3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.10*/"uops_executed_port.port_4", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.20*/"uops_executed_port.port_5", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.01*/"resource_stalls.any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.02*/"resource_stalls.lb", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.04*/"resource_stalls.rs", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.08*/"resource_stalls.sb", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.0a*/"resource_stalls.lb_sb", /*sb-ep*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.0e*/"resource_stalls.mem_rs", /*sb-ep*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.10*/"resource_stalls.rob", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.20*/"resource_stalls.fcsw", /*sb*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.40*/"resource_stalls.mxcsr", /*sb*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.80*/"resource_stalls.other", /*sb*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.F0*/"resource_stalls.ooo_rsrc", /*sb-ep*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {/*a3.01*/"cycle_activity.cycles_l2_pending", /*F6M62*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*??.??*/"cycle_activity.stalls_l2_pending", /*F6M62*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.02*/"cycle_activity.cycles_ldm_pending", /*F6M62*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*??.??*/"cycle_activity.stalls_ldm_pending", /*F6M62*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.04*/"cycle_activity.cycles_no_execute", /*F6M62*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.04*/"cycle_activity.cycles_no_dispatch", /*sandybridge*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.08*/"cycle_activity.cycles_l1d_pending", /*F6M62*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*??.??*/"cycle_activity.stalls_l1d_pending", /*F6M62*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {/*ab.02*/"dsb2mite_switches.penalty_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.??*/"uops_executed.stall_cycles", /*? not in PRM*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.01*/"uops_dispatched.stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.01*/"uops_executed.stall_cycles", /*F6M62*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.01*/"uops_executed.cycles_ge_1_uop_exec", /*F6M62,not doc'd*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.01*/"uops_executed.cycles_ge_2_uops_exec", /*F6M62,not doc'd*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.01*/"uops_executed.cycles_ge_3_uops_exec", /*F6M62,not doc'd*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.01*/"uops_executed.cycles_ge_4_uops_exec", /*F6M62,not doc'd*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {/*bf.05*/"l1d_blocks.bank_conflict_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c2.01*/"uops_retired.stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c2.01*/"uops_retired.total_cycles", /*cmask==0x10*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c2.01*/"uops_retired.core_stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c2.01*/"uops_retired.active_cycles", /*cmask==0x1*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+#if 0 // need to see documentation on the following before marking them as cycles
+  uops_executed.cycles_ge_1_uop_exec[ / {0 | 1 | 2 | 3}], 1000003 (events)
+  uops_executed.cycles_ge_2_uops_exec[ /
+  {0 | 1 | 2 | 3}
+  ], 1000003 (events)
+  uops_executed.cycles_ge_3_uops_exec[ /
+  {0 | 1 | 2 | 3}
+  ], 1000003 (events)
+  uops_executed.cycles_ge_4_uops_exec[ /
+  {0 | 1 | 2 | 3}
+  ], 1000003 (events)
+#endif
+  {/*cd.01*/"mem_trans_retired.load_latency", /*PEBS*/ NULL, REGNO_ANY, NULL, PRELOADS_4, 65, ABST_EXACT_PEBS_PLUS1}, //non-standard overflow
+
+  /* "Architectural" events: */
+  {/*3c*/"unhalted-core-cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  PERF_EVENTS_SW_EVENT_DEFS
+
+  /* additional (hidden) aliases for convenience */
+#if 0
+  USE_INTEL_REF_CYCLES (100),
+#endif
+  {"insts0", "inst_retired.any_p", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "inst_retired.any_p", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+
+static Hwcentry intelHaswellList[] = {
+  /* see comments for "cycles" and "insts" for intelNehalemList */
+  PERF_EVENTS_SW_EVENT_ALIASES
+  USE_INTEL_REF_CYCLES (100)
+  {"cycles", "cpu_clk_unhalted.thread_p", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "inst_retired.any_p", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+
+  // PEBS (sampling)
+  {"l2m_latency", "mem_trans_retired.load_latency", REGNO_ANY, STXT ("L2 Cache Miss Est. Latency"), PRELOADS_4, 65, ABST_EXACT_PEBS_PLUS1},
+
+  {"dch", "mem_load_uops_retired.l1_hit", REGNO_ANY, STXT ("L1 D-cache Hits"), PRELOADS_7, 0, ABST_NONE},
+  {"dcm", "mem_load_uops_retired.l1_miss", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_65, 0, ABST_NONE}, //mem_load_uops_retired
+  {"dcm", "0xd1~umask=0x08", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_65, 0, ABST_NONE}, //mem_load_uops_retired
+  {"l2h", "mem_load_uops_retired.l2_hit", REGNO_ANY, STXT ("L2 Cache Hits"), PRELOADS_65, 0, ABST_NONE},
+  {"l2m", "mem_load_uops_retired.l2_miss", REGNO_ANY, STXT ("L2 Cache Misses"), PRELOADS_6, 0, ABST_NONE}, //mem_load_uops_retired
+  {"l2m", "0xd1~umask=0x10", REGNO_ANY, STXT ("L2 Cache Misses"), PRELOADS_6, 0, ABST_NONE}, //mem_load_uops_retired
+  {"l3h", "mem_load_uops_retired.l3_hit", REGNO_ANY, STXT ("L3 Cache Hit w/o Snoop"), PRELOADS_6, 0, ABST_NONE},
+  {"l3m", "mem_load_uops_retired.l3_miss", REGNO_ANY, STXT ("L3 Cache Misses"), PRELOADS_5, 0, ABST_NONE}, //mem_load_uops_retired
+  {"l3m", "0xd1~umask=0x20", REGNO_ANY, STXT ("L3 Cache Misses"), PRELOADS_5, 0, ABST_NONE}, //mem_load_uops_retired
+
+  /* dtlbm has not been confirmed via Intel white paper */
+  {"dtlbm", "dtlb_load_misses.walk_completed", REGNO_ANY, STXT ("DTLB Misses"), PRELOADS_6, 0, ABST_NONE},
+  {"dtlbm_stall", "dtlb_load_misses.walk_completed", REGNO_ANY, STXT ("DTLB Misses x 30: Estimated Stalls"), PRELOADS_6, 30, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {/* 30a */"cpu_clk_unhalted.thread", /*15634344==6940930*/ NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  //{/* 30a */"cpu_clk_unhalted.core",  /*6759307*/                    NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*08.10*/"dtlb_load_misses.walk_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d.03*/"int_misc.recovery_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0e.01*/"uops_issued.stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0e.01*/"uops_issued.core_stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*3c.00*/"cpu_clk_unhalted.thread_p", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*48.01*/"l1d_pend_miss.pending_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*49.04*/"dtlb_store_misses.walk_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5c.01*/"cpl_cycles.ring0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5c.02*/"cpl_cycles.ring123", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5c.xx*/"cpl_cycles.ring0_trans", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5e.01*/"rs_events.empty_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.01*/"offcore_requests_outstanding.cycles_with_demand_data_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.02*/"offcore_requests_outstanding.demand_code_rd_cycles", /*?*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.04*/"offcore_requests_outstanding.demand_rfo_cycles", /*?*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.08*/"offcore_requests_outstanding.cycles_with_data_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*63.01*/"lock_cycles.split_lock_uc_lock_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*63.02*/"lock_cycles.cache_lock_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.00*/"idq.empty", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.04*/"idq.mite_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.08*/"idq.dsb_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.10*/"idq.ms_dsb_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.20*/"idq.ms_mite_uops_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.20*/"idq.ms_mite_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.30*/"idq.ms_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.18*/"idq.all_dsb_cycles_any_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.18*/"idq.all_dsb_cycles_4_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.24*/"idq.all_mite_cycles_any_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.24*/"idq.all_mite_cycles_4_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*80.04*/"icache.ifetch_stall", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*85.04*/"itlb_misses.walk_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*87.01*/"ild_stall.lcp", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE}, // Intel SDM says these are stalls, not cycles
+  {/*87.04*/"ild_stall.iq_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.xx*/"idq_uops_not_delivered.cycles_0_uops_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.xx*/"idq_uops_not_delivered.cycles_le_1_uop_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.xx*/"idq_uops_not_delivered.cycles_le_2_uop_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.xx*/"idq_uops_not_delivered.cycles_le_3_uop_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  //  {/*9c.01*/"idq_uops_not_delivered.cycles_ge_1_uop_deliv.core",   NULL, REGNO_ANY, NULL, PRELOAD_DEF,     1, ABST_NONE},
+  {/*9c.01*/"idq_uops_not_delivered.cycles_fe_was_ok", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {/*a1.01*/"uops_executed_port.port_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.02*/"uops_executed_port.port_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.04*/"uops_executed_port.port_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.08*/"uops_executed_port.port_3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.10*/"uops_executed_port.port_4", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.20*/"uops_executed_port.port_5", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.40*/"uops_executed_port.port_6", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.80*/"uops_executed_port.port_7", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.01*/"uops_executed_port.port_0_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.02*/"uops_executed_port.port_1_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.04*/"uops_executed_port.port_2_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.08*/"uops_executed_port.port_3_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.10*/"uops_executed_port.port_4_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.20*/"uops_executed_port.port_5_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.40*/"uops_executed_port.port_6_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.80*/"uops_executed_port.port_7_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {/*a2.01*/"resource_stalls.any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.04*/"resource_stalls.rs", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.08*/"resource_stalls.sb", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.10*/"resource_stalls.rob", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {/*a3.01*/"cycle_activity.cycles_l2_pending_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  //  {/*a3.01*/"cycle_activity.cycles_l2_pending",                    NULL, REGNO_ANY, NULL, PRELOAD_DEF,     1, ABST_NONE},
+  {/*a3.02*/"cycle_activity.cycles_ldm_pending_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  //  {/*a3.05*/"cycle_activity.stalls_l2_pending",                    NULL, REGNO_ANY, NULL, PRELOAD_DEF,     1, ABST_NONE},
+  {/*a3.08*/"cycle_activity.cycles_l1d_pending_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  //  {/*a3.??*/"cycle_activity.cycles_no_execute",                    NULL, REGNO_ANY, NULL, PRELOAD_DEF,     1, ABST_NONE},
+  //  {/*a3.??*/"cycle_activity.stalls_ldm_pending",/*?*/                      NULL, REGNO_ANY, NULL, PRELOAD_DEF,     1, ABST_NONE},
+
+  {/*ab.02*/"dsb2mite_switches.penalty_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {/*b1.??*/"uops_executed.stall_cycles", /*? not in PRM*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.??*/"uops_executed.cycles_ge_1_uop_exec", /*?*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.??*/"uops_executed.cycles_ge_2_uops_exec", /*?*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.??*/"uops_executed.cycles_ge_3_uops_exec", /*?*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.??*/"uops_executed.cycles_ge_4_uops_exec", /*?*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {/*c2.01*/"uops_retired.stall_cycles", /*cmask==1 + INV*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c2.01*/"uops_retired.total_cycles", /*cmask==0x1*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c2.01*/"uops_retired.core_stall_cycles", /*PEBS Any==1*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {/*c3.01*/"machine_clears.cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {/*ca.1e*/"fp_assist.any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  {/*cd.01*/"mem_trans_retired.load_latency", /*PEBS*/ NULL, REGNO_ANY, NULL, PRELOADS_4, 65, ABST_EXACT_PEBS_PLUS1}, //non-standard overflow
+
+  /* "Architectural" events: */
+  {/*3c*/"unhalted-core-cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  PERF_EVENTS_SW_EVENT_DEFS
+
+  /* additional (hidden) aliases for convenience */
+#if 0
+  USE_INTEL_REF_CYCLES (100),
+#endif
+  {"insts0", "inst_retired.any_p", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "inst_retired.any_p", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+
+static Hwcentry intelBroadwellList[] = {
+  /* see comments for "cycles" and "insts" for intelNehalemList */
+  PERF_EVENTS_SW_EVENT_ALIASES
+  USE_INTEL_REF_CYCLES (100)
+  {"cycles", "cpu_clk_unhalted.thread_p", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "inst_retired.any_p", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+
+  // PEBS (sampling)
+  {"l2m_latency", "mem_trans_retired.load_latency", REGNO_ANY, STXT ("L2 Cache Miss Est. Latency"), PRELOADS_4, 65, ABST_EXACT_PEBS_PLUS1},
+  {/*cd.01*/"mem_trans_retired.load_latency", NULL, REGNO_ANY, NULL, PRELOADS_4, 65, ABST_EXACT_PEBS_PLUS1},
+
+  // aliases (the first set are PEBS, but on Intel the only precise counter we support is l2m_latency)
+  {"dch", "mem_load_uops_retired.l1_hit", REGNO_ANY, STXT ("L1 D-cache Hits"), PRELOADS_7, 0, ABST_NONE},
+  {"dcm", "mem_load_uops_retired.l1_miss", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_65, 0, ABST_NONE},
+  {"l2h", "mem_load_uops_retired.l2_hit", REGNO_ANY, STXT ("L2 Cache Hits"), PRELOADS_65, 0, ABST_NONE},
+  {"l2m", "mem_load_uops_retired.l2_miss", REGNO_ANY, STXT ("L2 Cache Misses"), PRELOADS_6, 0, ABST_NONE},
+  {"l3h", "mem_load_uops_retired.l3_hit", REGNO_ANY, STXT ("L3 Cache Hits"), PRELOADS_6, 0, ABST_NONE},
+  {"l3m", "mem_load_uops_retired.l3_miss", REGNO_ANY, STXT ("L3 Cache Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"dtlbm", "dtlb_load_misses.walk_completed", REGNO_ANY, STXT ("DTLB Misses"), PRELOADS_6, 0, ABST_NONE},
+
+  // counters that can be time converted (add FFCs if we decide to support them)
+  // counters that are load-store (did not include any... do we want to?)
+  {/*08.10*/"dtlb_load_misses.walk_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d.03*/"int_misc.recovery_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0e.01*/"uops_issued.stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0e.01*/"uops_issued.core_stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*14.01*/"arith.fpu_div_active", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*3c.00*/"cpu_clk_unhalted.thread_p_any", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*3c.00*/"cpu_clk_unhalted.thread_p", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*3c.02*/"cpu_clk_thread_unhalted.one_thread_active", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*48.01*/"l1d_pend_miss.pending_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*48.01*/"l1d_pend_miss.pending_cycles_any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*49.10*/"dtlb_store_misses.walk_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*4f.10*/"ept.walk_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5c.01*/"cpl_cycles.ring0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5c.01*/"cpl_cycles.ring0_trans", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5c.02*/"cpl_cycles.ring123", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5e.01*/"rs_events.empty_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.01*/"offcore_requests_outstanding.cycles_with_demand_data_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.02*/"offcore_requests_outstanding.demand_code_rd_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.04*/"offcore_requests_outstanding.demand_rfo_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.08*/"offcore_requests_outstanding.cycles_with_data_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*63.01*/"lock_cycles.split_lock_uc_lock_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*63.02*/"lock_cycles.cache_lock_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.02*/"idq.empty", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.04*/"idq.mite_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.08*/"idq.dsb_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.10*/"idq.ms_dsb_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.18*/"idq.all_dsb_cycles_4_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.18*/"idq.all_dsb_cycles_any_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.24*/"idq.all_mite_cycles_4_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.24*/"idq.all_mite_cycles_any_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.30*/"idq.ms_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*85.10*/"itlb_misses.walk_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.xx*/"idq_uops_not_delivered.cycles_0_uops_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.xx*/"idq_uops_not_delivered.cycles_le_1_uop_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.xx*/"idq_uops_not_delivered.cycles_le_2_uop_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.xx*/"idq_uops_not_delivered.cycles_le_3_uop_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.01*/"idq_uops_not_delivered.cycles_fe_was_ok", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.01*/"uops_executed_port.port_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.02*/"uops_executed_port.port_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.04*/"uops_executed_port.port_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.08*/"uops_executed_port.port_3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.10*/"uops_executed_port.port_4", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.20*/"uops_executed_port.port_5", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.40*/"uops_executed_port.port_6", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.80*/"uops_executed_port.port_7", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.01*/"uops_executed_port.port_0_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.02*/"uops_executed_port.port_1_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.04*/"uops_executed_port.port_2_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.08*/"uops_executed_port.port_3_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.10*/"uops_executed_port.port_4_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.20*/"uops_executed_port.port_5_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.40*/"uops_executed_port.port_6_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.80*/"uops_executed_port.port_7_core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.01*/"resource_stalls.any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.04*/"resource_stalls.rs", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.08*/"resource_stalls.sb", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.10*/"resource_stalls.rob", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.01*/"cycle_activity.cycles_l2_pending", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.02*/"cycle_activity.cycles_ldm_pending", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.04*/"cycle_activity.cycles_no_execute", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.08*/"cycle_activity.cycles_l1d_pending", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a8.01*/"lsd.cycles_active", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a8.01*/"lsd.cycles_4_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*ab.02*/"dsb2mite_switches.penalty_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.01*/"uops_executed.stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c2.01*/"uops_retired.stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c2.01*/"uops_retired.total_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c2.01*/"uops_retired.core_stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c3.01*/"machine_clears.cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*ca.1e*/"fp_assist.any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  /* "Architectural" events: */
+  {/*3c*/"unhalted-core-cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  PERF_EVENTS_SW_EVENT_DEFS
+
+  /* additional (hidden) aliases for convenience */
+#if 0
+  USE_INTEL_REF_CYCLES (100),
+#endif
+  {"insts0", "inst_retired.any_p", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "inst_retired.any_p", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry intelSkylakeList[] = {
+  /* see comments for "cycles" and "insts" for intelNehalemList */
+  PERF_EVENTS_SW_EVENT_ALIASES
+  USE_INTEL_REF_CYCLES (25)
+  {"cycles", "cpu_clk_unhalted.thread_p", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "inst_retired.any_p", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+
+  // PEBS (sampling)
+  {"l2m_latency", "mem_trans_retired.load_latency", REGNO_ANY, STXT ("L2 Cache Miss Est. Latency"), PRELOADS_4, 65, ABST_EXACT_PEBS_PLUS1},
+  {/*cd.01*/"mem_trans_retired.load_latency", NULL, REGNO_ANY, NULL, PRELOADS_4, 65, ABST_EXACT_PEBS_PLUS1},
+
+  // aliases (the first set are PEBS, but on Intel the only precise counter we support is l2m_latency)
+  {"dch", "mem_load_retired.l1_hit", REGNO_ANY, STXT ("L1 D-cache Hits"), PRELOADS_7, 0, ABST_NONE},
+  {"dcm", "mem_load_retired.l1_miss", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_65, 0, ABST_NONE},
+  {"l2h", "mem_load_retired.l2_hit", REGNO_ANY, STXT ("L2 Cache Hits"), PRELOADS_65, 0, ABST_NONE},
+  {"l2m", "mem_load_retired.l2_miss", REGNO_ANY, STXT ("L2 Cache Misses"), PRELOADS_6, 0, ABST_NONE},
+  {"l2m_stall", "cycle_activity.stalls_l2_miss", REGNO_ANY, STXT ("L2 Cache Miss Stall"), PRELOADS_7, 1, ABST_NONE}, // needs validation
+  {"l3h", "mem_load_retired.l3_hit", REGNO_ANY, STXT ("L3 Cache Hits"), PRELOADS_6, 0, ABST_NONE},
+  {"l3m", "mem_load_retired.l3_miss", REGNO_ANY, STXT ("L3 Cache Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"l3m_stall", "cycle_activity.stalls_l3_miss", REGNO_ANY, STXT ("L3 Cache Miss Stall"), PRELOADS_7, 1, ABST_NONE}, // needs validation
+  {"dtlbm_stall", "dtlb_load_misses.walk_active", REGNO_ANY, STXT ("DTLB Miss Est Stall"), PRELOADS_7, 1, ABST_NONE, STXT ("Estimated time stalled on DTLB misses requiring a tablewalk.  Does not include time related to STLB hits.")}, // needs validation
+  // PEBS mem_inst_retired.stlb_miss_loads for finding location of DTLB issues
+  // what about: dtlb_load_misses.walk_completed, dtlb_load_misses.walk_pending, dtlb_load_misses.stlb_hit
+
+  {"fp_scalar", "fp_arith_inst_retired.scalar_double~umask=0x3", REGNO_ANY, STXT ("FP Scalar uOps"), PRELOADS_7, 0, ABST_NONE, STXT ("Floating-point scalar micro-ops that retired")},
+  {"fp_vector", "fp_arith_inst_retired.128b_packed_double~umask=0x3c", REGNO_ANY, STXT ("FP Vector uOps"), /*needs test*/ PRELOADS_7, 0, ABST_NONE, STXT ("Floating-point vector micro-ops that retired")},
+
+  // counters that can be time converted (add FFCs if we decide to support them)
+  // counters that are load-store (did not include any... do we want to?)
+  {/*08.10*/"dtlb_load_misses.walk_active", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*08.10*/"dtlb_load_misses.walk_pending", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d.01*/"int_misc.recovery_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d.01*/"int_misc.recovery_cycles_any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d.80*/"int_misc.clear_resteer_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0e.01*/"uops_issued.stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*14.01*/"arith.divider_active", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*3c.00*/"cpu_clk_unhalted.ring0_trans", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*3c.00*/"cpu_clk_unhalted.thread_p_any", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*3c.00*/"cpu_clk_unhalted.thread_p", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*3c.00*/"cpu_clk_unhalted.core", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*48.01*/"l1d_pend_miss.pending_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*48.01*/"l1d_pend_miss.pending_cycles_any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*49.10*/"dtlb_store_misses.walk_active", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*49.10*/"dtlb_store_misses.walk_pending", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*4f.10*/"ept.walk_pending", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*5e.01*/"rs_events.empty_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.01*/"offcore_requests_outstanding.cycles_with_demand_data_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.01*/"offcore_requests_outstanding.demand_data_rd_ge_6", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.02*/"offcore_requests_outstanding.cycles_with_demand_code_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.04*/"offcore_requests_outstanding.cycles_with_demand_rfo", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.08*/"offcore_requests_outstanding.cycles_with_data_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.10*/"offcore_requests_outstanding.cycles_with_l3_miss_demand_data_rd", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*60.10*/"offcore_requests_outstanding.l3_miss_demand_data_rd_ge_6", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*63.02*/"lock_cycles.cache_lock_duration", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.04*/"idq.mite_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.08*/"idq.dsb_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.10*/"idq.ms_dsb_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.18*/"idq.all_dsb_cycles_4_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.18*/"idq.all_dsb_cycles_any_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.24*/"idq.all_mite_cycles_4_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.24*/"idq.all_mite_cycles_any_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*79.30*/"idq.ms_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*80.04*/"icache_16b.ifdata_stall", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*83.04*/"icache_64b.iftag_stall", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*85.10*/"itlb_misses.walk_active", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*85.10*/"itlb_misses.walk_pending", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*87.01*/"ild_stall.lcp", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.01*/"idq_uops_not_delivered.cycles_0_uops_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.01*/"idq_uops_not_delivered.cycles_le_1_uop_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.01*/"idq_uops_not_delivered.cycles_le_2_uop_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.01*/"idq_uops_not_delivered.cycles_le_3_uop_deliv.core", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*9c.01*/"idq_uops_not_delivered.cycles_fe_was_ok", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.01*/"uops_dispatched_port.port_0", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.02*/"uops_dispatched_port.port_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.04*/"uops_dispatched_port.port_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.08*/"uops_dispatched_port.port_3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.10*/"uops_dispatched_port.port_4", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.20*/"uops_dispatched_port.port_5", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.40*/"uops_dispatched_port.port_6", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a1.80*/"uops_dispatched_port.port_7", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.01*/"resource_stalls.any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a2.08*/"resource_stalls.sb", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.01*/"cycle_activity.cycles_l2_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.02*/"cycle_activity.cycles_l3_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.04*/"cycle_activity.stalls_total", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.05*/"cycle_activity.stalls_l2_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.06*/"cycle_activity.stalls_l3_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.08*/"cycle_activity.cycles_l1d_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.0c*/"cycle_activity.stalls_l1d_miss", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.10*/"cycle_activity.cycles_mem_any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a3.14*/"cycle_activity.stalls_mem_any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a6.01*/"exe_activity.exe_bound_0_ports", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a6.02*/"exe_activity.1_ports_util", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a6.04*/"exe_activity.2_ports_util", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a6.08*/"exe_activity.3_ports_util", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a6.10*/"exe_activity.4_ports_util", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a6.40*/"exe_activity.bound_on_stores", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a8.01*/"lsd.cycles_4_uops", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*a8.01*/"lsd.cycles_active", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*ab.02*/"dsb2mite_switches.penalty_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.01*/"uops_executed.cycles_ge_1_uop_exec", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.01*/"uops_executed.cycles_ge_2_uops_exec", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.01*/"uops_executed.cycles_ge_3_uops_exec", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.01*/"uops_executed.cycles_ge_4_uops_exec", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.01*/"uops_executed.stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.02*/"uops_executed.core_cycles_ge_1", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.02*/"uops_executed.core_cycles_ge_2", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.02*/"uops_executed.core_cycles_ge_3", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.02*/"uops_executed.core_cycles_ge_4", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*b1.02*/"uops_executed.core_cycles_none", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c0.1*/"inst_retired.total_cycles_ps", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c2.01*/"uops_retired.stall_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c2.01*/"uops_retired.total_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*ca.1e*/"fp_assist.any", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  /* "Architectural" events: */
+  {/* FFC */"cpu_clk_unhalted.thread", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/* FFC */"unhalted-core-cycles", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  PERF_EVENTS_SW_EVENT_DEFS
+
+  /* additional (hidden) aliases for convenience */
+#if 0
+  USE_INTEL_REF_CYCLES (25),
+#endif
+  {"insts0", "inst_retired.any_p", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "inst_retired.any_p", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry intelLinuxUnknown[] = {
+  PERF_EVENTS_SW_EVENT_ALIASES
+  //    USE_INTEL_REF_CYCLES(100) // freq is unknown
+  {"cycles", "unhalted-core-cycles", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"cycles", "PERF_COUNT_HW_CPU_CYCLES", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "instruction-retired", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+  {"insts", "PERF_COUNT_HW_INSTRUCTIONS", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+
+  {"dcm", "PERF_COUNT_HW_CACHE_MISSES.L1D", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_65, 0, ABST_NONE},
+  {"llm", "llc-misses", REGNO_ANY, STXT ("Last-Level Cache Misses"), PRELOADS_5, 0, ABST_NONE},
+  {"llm", "PERF_COUNT_HW_CACHE_MISSES.LL", REGNO_ANY, STXT ("Last-Level Cache Misses"), PRELOADS_5, 0, ABST_NONE},
+
+  {"br_msp", "branch-misses-retired", REGNO_ANY, STXT ("Branch Mispredict"), PRELOADS_6, 0, ABST_NONE},
+  {"br_msp", "PERF_COUNT_HW_BRANCH_MISSES", REGNO_ANY, STXT ("Branch Mispredict"), PRELOADS_6, 0, ABST_NONE},
+  {"br_ins", "branch-instruction-retired", REGNO_ANY, STXT ("Branch Instructions"), PRELOADS_7, 0, ABST_NONE},
+  {"br_ins", "PERF_COUNT_HW_BRANCH_INSTRUCTIONS", REGNO_ANY, STXT ("Branch Instructions"), PRELOADS_7, 0, ABST_NONE},
+
+  // counters that can be time converted (add FFCs if we decide to support them)
+  // counters that are load-store (did not include any... do we want to?)
+  /* "Architectural" events: */
+  {/* FFC */"cpu_clk_unhalted.thread", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/* FFC */"unhalted-core-cycles", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  PERF_EVENTS_SW_EVENT_DEFS
+
+  /* additional (hidden) aliases for convenience */
+  {"cycles0", "unhalted-reference-cycles", 0, NULL, PRELOADS_6, -(25), ABST_NONE}, //YXXX -can't do with ref cycles #
+  {"cycles0", "PERF_COUNT_HW_BUS_CYCLES", 0, NULL, PRELOADS_6, -(25), ABST_NONE}, //YXXX -can't do with ref cycles #
+  {"cycles1", "unhalted-reference-cycles", 1, NULL, PRELOADS_65, -(25), ABST_NONE}, //YXXX - can't do with ref cycles #
+  {"cycles1", "PERF_COUNT_HW_BUS_CYCLES", 1, NULL, PRELOADS_65, -(25), ABST_NONE}, //YXXX - can't do with ref cycles #
+  {"insts0", "instruction-retired", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts0", "PERF_COUNT_HW_INSTRUCTIONS", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "instruction-retired", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "PERF_COUNT_HW_INSTRUCTIONS", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry intelAtomList[] = {
+  {"cycles", "cpu_clk_unhalted.core", /*6759307*/ REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"cycles", "cpu_clk_unhalted.thread", /*6759307*/ REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"insts", "instr_retired.any", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_7, 0, ABST_NONE},
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  /* XXXX add core2-related entries if appropriate */
+  {/*30A*/"cpu_clk_unhalted.core", /*6759307*/ NULL, REGNO_ANY, NULL, PRELOADS_7, 1, ABST_NONE},
+  {/*30A*/"cpu_clk_unhalted.thread", /*6759307*/ NULL, REGNO_ANY, NULL, PRELOADS_7, 1, ABST_NONE},
+  {/*0c*/"page_walks.cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*14*/"cycles_div_busy", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*21*/"l2_ads", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*22*/"l2_dbus_busy", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*32*/"l2_no_req", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*3c*/"cpu_clk_unhalted.core_p", NULL, REGNO_ANY, NULL, PRELOADS_7, 1, ABST_NONE},
+  {/*3c*/"cpu_clk_unhalted.bus", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*3c*/"cpu_clk_unhalted.no_other", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*62*/"bus_drdy_clocks", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*63*/"bus_lock_clocks", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*64*/"bus_data_rcv", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*7a*/"bus_hit_drv", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*7b*/"bus_hitm_drv", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*7d*/"busq_empty", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*7e*/"snoop_stall_drv", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*7f*/"bus_io_wait", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c6*/"cycles_int_masked.cycles_int_masked", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*c6*/"cycles_int_masked.cycles_int_pending_and_masked", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  /* "Architectural" events: */
+  {/*3c*/"unhalted-core-cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  /* additional (hidden) aliases for convenience */
+  {"cycles0", "cpu_clk_unhalted.core_p", 0, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"cycles1", "cpu_clk_unhalted.core_p", 1, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"insts0", "inst_retired.any_p", 0, NULL, PRELOADS_75, 0, ABST_NONE},
+  {"insts1", "inst_retired.any_p", 1, NULL, PRELOADS_75, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry amd_opteron_10h_11h[] = {
+  {"cycles", "BU_cpu_clk_unhalted", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "FR_retired_x86_instr_w_excp_intr", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+  {"icr", "IC_fetch", REGNO_ANY, STXT ("L1 I-cache Refs"), PRELOADS_7, 0, ABST_NONE}, /* new */
+  {"icm", "IC_miss", REGNO_ANY, STXT ("L1 I-cache Misses"), PRELOADS_6, 0, ABST_NONE},
+  {"l2itlbh", "IC_itlb_L1_miss_L2_hit", REGNO_ANY, STXT ("L2 ITLB Hits"), PRELOADS_6, 0, ABST_NONE}, /* new */
+  {"l2itlbm", "IC_itlb_L1_miss_L2_miss", REGNO_ANY, STXT ("L2 ITLB Misses"), PRELOADS_5, 0, ABST_NONE}, /* new */
+  {"l2ir", "BU_internal_L2_req~umask=0x1", REGNO_ANY, STXT ("L2 I-cache Refs"), PRELOADS_6, 0, ABST_NONE},
+  {"l2im", "BU_fill_req_missed_L2~umask=0x1", REGNO_ANY, STXT ("L2 I-cache Misses"), PRELOADS_4, 0, ABST_NONE},
+  {"dcr", "DC_access", REGNO_ANY, STXT ("L1 D-cache Refs"), PRELOADS_7, 0, ABST_NONE}, /* new */
+  {"dcm", "DC_miss", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_65, 0, ABST_NONE}, /* new */
+  {"l2dtlbh", "DC_dtlb_L1_miss_L2_hit", REGNO_ANY, STXT ("L2 DTLB Hits"), PRELOADS_6, 0, ABST_NONE}, /* new */
+  {"l2dtlbm", "DC_dtlb_L1_miss_L2_miss", REGNO_ANY, STXT ("L2 DTLB Misses"), PRELOADS_5, 0, ABST_NONE}, /* new */
+  {"l2dr", "BU_internal_L2_req~umask=0x2", REGNO_ANY, STXT ("L2 D-cache Refs"), PRELOADS_65, 0, ABST_NONE}, /* hwc_cache_load: 1.6x overcount on shanghai01 */
+  {"l2dm", "BU_fill_req_missed_L2~umask=0x2", REGNO_ANY, STXT ("L2 D-cache Misses"), PRELOADS_6, 0, ABST_NONE}, /* new */
+  {"fpadd", "FP_dispatched_fpu_ops~umask=0x1", REGNO_ANY, STXT ("FP Adds"), PRELOADS_7, 0, ABST_NONE},
+  {"fpmul", "FP_dispatched_fpu_ops~umask=0x2", REGNO_ANY, STXT ("FP Muls"), PRELOADS_7, 0, ABST_NONE},
+  {"fpustall", "FR_dispatch_stall_fpu_full", REGNO_ANY, STXT ("FPU Stall Cycles"), PRELOADS_7, 1, ABST_NONE},
+  {"memstall", "FR_dispatch_stall_ls_full", REGNO_ANY, STXT ("Memory Unit Stall Cycles"), PRELOADS_7, 1, ABST_NONE},
+  // For PAPI mappings, see hwctable.README.family10h
+  // For PAPI mappings, see hwctable.README.opteron
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {"BU_cpu_clk_unhalted", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {"FP_cycles_no_fpu_ops_retired", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"FP_serialize_ops_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"FR_dispatch_stall_branch_abort_to_retire", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"FR_dispatch_stall_far_ctl_trsfr_resync_branch_pend", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"FR_dispatch_stall_fpu_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"FR_dispatch_stall_ls_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"FR_dispatch_stall_reorder_buffer_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"FR_dispatch_stall_resv_stations_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"FR_dispatch_stall_segment_load", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"FR_dispatch_stall_serialization", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"FR_dispatch_stall_waiting_all_quiet", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"FR_dispatch_stalls", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"FR_intr_masked_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"FR_intr_masked_while_pending_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"FR_nothing_to_dispatch", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"IC_instr_fetch_stall", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"LS_buffer_2_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+  {"NB_mem_ctrlr_dram_cmd_slots_missed", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {"NB_mem_ctrlr_turnaround", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_TBD},
+
+  /* additional (hidden) aliases, for convenience */
+  {"cycles0", "BU_cpu_clk_unhalted", 0, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"cycles1", "BU_cpu_clk_unhalted", 1, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"insts0", "FR_retired_x86_instr_w_excp_intr", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "FR_retired_x86_instr_w_excp_intr", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry amd_15h[] = {
+  {"cycles", "CU_cpu_clk_unhalted", REGNO_ANY, STXT ("CPU Cycles"), PRELOADS_75, 1, ABST_NONE},
+  {"insts", "EX_retired_instr_w_excp_intr", REGNO_ANY, STXT ("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+  {"icr", "IC_fetch", REGNO_ANY, STXT ("L1 I-cache Refs"), PRELOADS_7, 0, ABST_NONE}, /* new */
+  {"icm", "IC_miss", REGNO_ANY, STXT ("L1 I-cache Misses"), PRELOADS_6, 0, ABST_NONE},
+  {"l2im", "IC_refill_from_system", REGNO_ANY, STXT ("L2 I-cache Misses"), PRELOADS_6, 0, ABST_NONE},
+  {"dcr", "DC_access", REGNO_ANY, STXT ("L1 D-cache Refs"), PRELOADS_7, 0, ABST_NONE}, /* new */
+  {"dcm", "DC_miss~umask=0x3", REGNO_ANY, STXT ("L1 D-cache Misses"), PRELOADS_65, 0, ABST_NONE}, /* new */
+  {"l2dm", "DC_refill_from_system", REGNO_ANY, STXT ("L2 D-cache Misses"), PRELOADS_6, 0, ABST_NONE}, /* new */
+  {"dtlbm", "DC_unified_tlb_miss~umask=0x7", REGNO_ANY, STXT ("L2 DTLB Misses"), PRELOADS_5, 0, ABST_NONE}, /* new */
+  // For PAPI mappings, see hwctable.README.family15h
+
+  /* explicit definitions of (hidden) entries for proper counters */
+  /*  Only counters that can be time converted, or are load-store need to be in this table */
+  {/*001.xx*/"FP_scheduler_empty", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*006.xx*/"FP_bottom_execute_uops_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*023.xx*/"LS_ldq_stq_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*024.xx*/"LS_locked_operation", /*umask!=0*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*069.xx*/"CU_mab_wait_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*076.xx*/"CU_cpu_clk_unhalted", NULL, REGNO_ANY, NULL, PRELOADS_75, 1, ABST_NONE},
+  {/*087.xx*/"IC_instr_fetch_stall", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0cd.xx*/"EX_intr_masked_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0ce.xx*/"EX_intr_masked_while_pending_cycles", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d0.xx*/"DE_nothing_to_dispatch", /*future*/ NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d1.xx*/"DE_dispatch_stalls", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d3.xx*/"DE_dispatch_stall_serialization", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d5.xx*/"DE_dispatch_stall_instr_retire_q_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d6.xx*/"DE_dispatch_stall_int_scheduler_q_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d7.xx*/"DE_dispatch_stall_fp_scheduler_q_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d8.xx*/"DE_dispatch_stall_ldq_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*0d9.xx*/"DE_dispatch_stall_waiting_all_quiet", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+  {/*1d8.xx*/"EX_dispatch_stall_stq_full", NULL, REGNO_ANY, NULL, PRELOAD_DEF, 1, ABST_NONE},
+
+  /* additional (hidden) aliases, for convenience */
+  {"cycles0", "CU_cpu_clk_unhalted", 0, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"cycles1", "CU_cpu_clk_unhalted", 1, NULL, PRELOADS_8, 1, ABST_NONE},
+  {"insts0", "EX_retired_instr_w_excp_intr", 0, NULL, PRELOADS_8, 0, ABST_NONE},
+  {"insts1", "EX_retired_instr_w_excp_intr", 1, NULL, PRELOADS_8, 0, ABST_NONE},
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+#define USE_ARM_REF_CYCLES \
+    {"usr_time","cycles",                 REGNO_ANY, STXT("User CPU"),   PRELOADS_85, 1, ABST_NONE}, \
+    {"sys_time","cycles~system=1~user=0", REGNO_ANY, STXT("System CPU"), PRELOADS_85, 1, ABST_NONE}, \
+
+static Hwcentry        armlist[] = {
+  USE_ARM_REF_CYCLES
+// Hardware event:
+  {"branch-instructions",     NULL, REGNO_ANY, STXT("Branch-instructions"), PRELOADS_35, 0, ABST_NONE},
+  {"branch-misses",           NULL, REGNO_ANY, STXT("Branch-misses"), PRELOADS_35, 0, ABST_NONE},
+  {"bus-cycles",              NULL, REGNO_ANY, STXT("Bus Cycles"), PRELOADS_35, 1, ABST_NONE},
+  {"cache-misses",            NULL, REGNO_ANY, STXT("Cache-misses"), PRELOADS_35, 0, ABST_NONE},
+  {"cache-references",        NULL, REGNO_ANY, STXT("Cache-references"), PRELOADS_35, 0, ABST_NONE},
+  {"cycles",                  NULL, REGNO_ANY, STXT("CPU Cycles"), PRELOADS_85, 1, ABST_NONE},
+  {"insts",         "instructions", REGNO_ANY, STXT("Instructions Executed"), PRELOADS_75, 0, ABST_NONE},
+  {"ref-cycles",              NULL, REGNO_ANY, STXT("Total Cycles"), PRELOADS_85, 1, ABST_NONE},
+  {"stalled-cycles-backend",  NULL, REGNO_ANY, STXT("Stalled Cycles during issue."), PRELOADS_85, 1, ABST_NONE},
+  {"stalled-cycles-frontend", NULL, REGNO_ANY, STXT("Stalled Cycles during retirement."), PRELOADS_85, 1, ABST_NONE},
+
+// Software event:
+  {"alignment-faults",        NULL, REGNO_ANY, STXT("Alignment Faults"), PRELOADS_85, 0, ABST_NONE},
+  {"context-switches",        NULL, REGNO_ANY, STXT("Context Switches"), PRELOADS_85, 0, ABST_NONE},
+  {"cpu-clock",               NULL, REGNO_ANY, STXT("CPU Clock"), PRELOADS_85, 1, ABST_NONE},
+  {"cpu-migrations",          NULL, REGNO_ANY, STXT("CPU Migrations"), PRELOADS_85, 0, ABST_NONE},
+  {"emulation-faults",        NULL, REGNO_ANY, STXT("Emulation Faults"), PRELOADS_85, 0, ABST_NONE},
+  {"major-faults",            NULL, REGNO_ANY, STXT("Major Page Faults"), PRELOADS_85, 0, ABST_NONE},
+  {"minor-faults",            NULL, REGNO_ANY, STXT("Minor Page Faults"), PRELOADS_85, 0, ABST_NONE},
+  {"page-faults",             NULL, REGNO_ANY, STXT("Page Faults"), PRELOADS_85, 0, ABST_NONE},
+  {"task-clock",              NULL, REGNO_ANY, STXT("Clock Count Specific"), PRELOADS_85, 1, ABST_NONE},
+
+// Hardware cache event
+  {"L1-dcache-load-misses",   NULL, REGNO_ANY, STXT("L1 D-cache Load Misses"), PRELOADS_35, 0, ABST_NONE},
+  {"L1-dcache-loads",         NULL, REGNO_ANY, STXT("L1 D-cache Loads"), PRELOADS_35, 0, ABST_NONE},
+  {"L1-dcache-store-misses",  NULL, REGNO_ANY, STXT("L1 D-cache Store Misses"), PRELOADS_35, 0, ABST_NONE},
+  {"L1-dcache-stores",        NULL, REGNO_ANY, STXT("L1 D-cache Store Stores"), PRELOADS_35, 0, ABST_NONE},
+  {"L1-icache-load-misses",   NULL, REGNO_ANY, STXT("L1 Instructions Load Misses"), PRELOADS_35, 0, ABST_NONE},
+  {"L1-icache-load-misses",   NULL, REGNO_ANY, STXT("L1 Instructions Loads"), PRELOADS_35, 0, ABST_NONE},
+  {"dTLB-load-misses",        NULL, REGNO_ANY, STXT("D-TLB Load Misses"), PRELOADS_35, 0, ABST_NONE},
+  {"dTLB-loads",              NULL, REGNO_ANY, STXT("D-TLB Loads"), PRELOADS_35, 0, ABST_NONE},
+  {"iTLB-load-misses",        NULL, REGNO_ANY, STXT("The Instruction TLB Load Misses"), PRELOADS_35, 0, ABST_NONE},
+  {"iTLB-loads",              NULL, REGNO_ANY, STXT("The Instruction TLB Loads"), PRELOADS_35, 0, ABST_NONE},
+
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+static Hwcentry unknownlist[] =
+       /*  used for unrecognized CPU type */{
+  {NULL, NULL, 0, NULL, 0, 0, 0, 0, ABST_NONE}
+};
+
+/* structure defining the counters for a CPU type */
+typedef struct
+{
+  int cputag;
+  Hwcentry *stdlist_table;
+#define MAX_DEFAULT_HWC_DEFS 4 // allows multiple defs to handle OS variations; extend as needed
+  char *default_exp_p[MAX_DEFAULT_HWC_DEFS + 1]; // end of list MUST be marked with NULL
+} cpu_list_t;
+
+/*  IMPORTANT NOTE:
+ *
+ *  Any default HWC string must consist of counter names separated by -TWO- commas,
+ *  with a no trailing comma/value after the last counter name
+ *
+ *  Only aliased counters should be specified; non-aliased counters will
+ *  not get the right overflow values set.
+ *  If the string is not formatted that way, -h hi and -h lo will fail
+ */
+static cpu_list_t cputabs[] = {
+  {CPC_ULTRA1, usIlist, {NULL}}, /* bind will fail */
+  {CPC_ULTRA2, usIlist, {NULL}}, /* bind will fail */
+  {CPC_ULTRA3, usIIIlist, {"insts,,ecstall", 0}},
+  {CPC_ULTRA3_PLUS, usIIIlist, {"insts,,ecstall", 0}},
+  {CPC_ULTRA3_I, usIIIlist, {"insts,,ecstall", 0}},
+  {CPC_ULTRA4_PLUS, usIVplist, {"insts,,ecstall", 0}},
+  {CPC_ULTRA_T1, niagara1, {"insts", 0}},
+  {CPC_ULTRA_T2, niagara2, {"insts,,+l2drm", 0}},
+  {CPC_ULTRA_T2P, niagara2, {"insts,,+l2drm", 0}},
+  {CPC_ULTRA_T3, niagara2, {"insts,,+l2drm", 0}},
+  {CPC_SPARC_T4, sparc_t4, {"insts,,cycles,,c_stalls,,dcm", "c_stalls", 0}},
+  {CPC_SPARC_M4, sparc_t5_m6, {"insts,,cycles,,c_stalls,,dcm", "c_stalls", 0}}, // renamed to m5
+  {CPC_SPARC_T5, sparc_t5_m6, {"insts,,cycles,,c_stalls,,dcm", "c_stalls", 0}},
+  {CPC_SPARC_M5, sparc_t5_m6, {"insts,,cycles,,c_stalls,,dcm", "c_stalls", 0}},
+  {CPC_SPARC_T6, sparc_t5_m6, {"insts,,cycles,,c_stalls,,dcm", "c_stalls", 0}}, // no such processor
+  {CPC_SPARC_M6, sparc_t5_m6, {"insts,,cycles,,c_stalls,,dcm", "c_stalls", 0}},
+  {CPC_SPARC_M7, sparc_m7, {"insts,,cycles,,c_stalls,,dcm", "c_stalls", 0}}, // includes T7
+  {CPC_SPARC_M8, sparc_m8, {"insts,,cycles,,c_stalls,,dcm", "c_stalls", 0}},
+  {CPC_PENTIUM_PRO_MMX, pentiumIIlist, {"insts", 0}},
+  {CPC_PENTIUM_PRO, pentiumIIIlist, {"insts", 0}},
+  {CPC_PENTIUM_4, pentium4, {"insts", 0}},
+  {CPC_PENTIUM_4_HT, pentium4, {"insts", 0}},
+  {CPC_INTEL_CORE2, intelCore2list, {"insts,,cycles", 0}},
+  {CPC_INTEL_NEHALEM, intelNehalemList, {"insts,,cycles,,+l2m_latency,,dtlbm_stall",
+      "insts,,cycles,,l3m_stall,,dtlbm_stall", 0}},
+  {CPC_INTEL_WESTMERE, intelNehalemList, {"insts,,cycles,,+l2m_latency,,dtlbm_stall",
+      "insts,,cycles,,l3m_stall,,dtlbm_stall", 0}},
+  {CPC_INTEL_SANDYBRIDGE, intelSandyBridgeList, {"insts,,cycles,,+l2m_latency,,dtlbm_stall",
+      "insts,,cycles,,l3m,,dtlbm", 0}},
+  {CPC_INTEL_IVYBRIDGE, intelSandyBridgeList, {"insts,,cycles,,+l2m_latency,,dtlbm_stall",
+      "insts,,cycles,,l3m,,dtlbm", 0}},
+  {CPC_INTEL_HASWELL, intelHaswellList, {"insts,,cycles,,+l2m_latency,,dtlbm_stall",
+      "insts,,cycles,,l3m,,dtlbm", 0}},
+  {CPC_INTEL_BROADWELL, intelBroadwellList, {"insts,,cycles,,+l2m_latency,,dtlbm",
+      "insts,,cycles,,l3m,,dtlbm", 0}},
+  {CPC_INTEL_SKYLAKE, intelSkylakeList, {"insts,,cycles,,+l2m_latency,,dtlbm_stall",
+      "insts,,cycles,,l2m_stall,,dtlbm_stall", 0}},
+  {CPC_INTEL_UNKNOWN, intelLinuxUnknown, {"cycles,,insts,,llm",
+      "user_time,,system_time,,cycles,,insts,,llm", 0}},
+  {CPC_INTEL_ATOM, intelAtomList, {"insts", 0}},
+  {CPC_AMD_K8C, amd_opteron_10h_11h, {"insts,,cycles,,l2dm,,l2dtlbm", 0}},
+  {CPC_AMD_FAM_10H, amd_opteron_10h_11h, {"insts,,cycles,,l2dm,,l2dtlbm", 0}},
+  {CPC_AMD_FAM_11H, amd_opteron_10h_11h, {"insts,,cycles,,l2dm,,l2dtlbm", 0}},
+  {CPC_AMD_FAM_15H, amd_15h, {"insts,,cycles", 0}},
+  {CPC_SPARC64_V, usfuji_V_list, {"insts,,cycles", 0}},
+  {CPC_SPARC64_VI, usfuji_VI_VII_list, {"insts,,cycles,,dcstall", 0}},
+  {CPC_SPARC64_VII, usfuji_VI_VII_list, {"insts,,cycles,,dcstall", 0}},
+  {CPC_SPARC64_X, usfuji_X_list, {"insts,,cycles,,dcstall", 0}},
+  {CPC_SPARC64_XII, usfuji_XII_list, {"insts,,cycles,,dcstall", 0}},
+  {CPC_KPROF, kproflist, {NULL}}, // OBSOLETE (To support 12.3 and earlier, TBR)
+  {ARM_CPU_IMP_APM, armlist, {"insts,,cycles", 0}},
+  {0, unknownlist, {NULL}} /* processor is unknown, but experiment is allowed */
+};
+
+/*---------------------------------------------------------------------------*/
+/* state variables */
+static int initialized;
+static int signals_disabled;
+
+// Simple array list
+typedef struct
+{
+  void** array;     // array of ptrs, last item set to null
+  int sz;           // num live elements in array
+  int max;          // array allocation size
+} ptr_list;
+
+static void
+ptr_list_init (ptr_list *lst)
+{
+  lst->sz = 0;
+  lst->max = 0;
+  lst->array = 0;
+}
+
+static void
+ptr_list_add (ptr_list *lst, char* ptr)
+{ // ptr must be freeable
+  if (lst->sz >= lst->max - 1)
+    {
+      void * * new;
+      int newmax = lst->max ? lst->max * 2 : 16;
+      new = (void**) realloc (lst->array, newmax * sizeof (void*));
+      if (!new) return; // failed, discard add
+      lst->max = newmax;
+      lst->array = new;
+    }
+  lst->array[lst->sz++] = ptr;
+  lst->array[lst->sz] = NULL; // mark new end-of-list
+}
+
+static void
+ptr_list_free (ptr_list *lst)
+{ // includes shallow free of all elements
+  if (lst->array)
+    {
+      for (int ii = 0; lst->array[ii]; ii++)
+       free (lst->array[ii]);
+      free (lst->array);
+    }
+  lst->sz = 0;
+  lst->max = 0;
+  lst->array = 0;
+}
+
+// Capabilities of this machine (initialized by setup_cpc())
+static int cpcx_cpuver = CPUVER_UNDEFINED;
+static uint_t cpcx_npics;
+static const char *cpcx_cciname;
+static const char *cpcx_docref;
+static uint64_t cpcx_support_bitmask;
+
+// cpcx_*[0]: collect lists
+// cpcx_*[1]: er_kernel lists
+// Each cpcx_*[] list is an array of ptrs with null ptr marking end of list
+static char **cpcx_attrs[2];
+
+static Hwcentry **cpcx_std[2];
+static Hwcentry **cpcx_raw[2];
+static Hwcentry **cpcx_hidden[2];
+
+static uint_t cpcx_max_concurrent[2];
+static char *cpcx_default_hwcs[2];
+static char *cpcx_orig_default_hwcs[2];
+static int cpcx_has_precise[2];
+
+#define VALID_FOR_KERNEL(forKernel) ((forKernel)>=0 && (forKernel)<=1)
+#define IS_KERNEL(forKernel) ((forKernel)==1)
+
+// used to build lists:
+static ptr_list unfiltered_attrs;
+static ptr_list unfiltered_raw;
+
+/*---------------------------------------------------------------------------*/
+/* misc internal utilities */
+
+/* compare 2 strings to either \0 or <termchar> */
+#define IS_EOL(currchar, termchar) ((currchar)==(termchar) || (currchar)==0)
+
+static int
+is_same (const char * regname, const char * int_name, char termchar)
+{
+  do
+    {
+      char a = *regname;
+      char b = *int_name;
+      if (IS_EOL (a, termchar))
+       {
+         if (IS_EOL (b, termchar))
+           return 1; /* strings are the same up to terminating char */
+         else
+           break; /* strings differ */
+       }
+      if (a != b)
+       break;      /* strings differ */
+      regname++;
+      int_name++;
+    }
+  while (1);
+  return 0;
+}
+
+static int
+is_numeric (const char *name, uint64_t *pval)
+{
+  char *endptr;
+  uint64_t val = strtoull (name, &endptr, 0);
+  if (!*name || *endptr)
+    return 0; /* name does not specify a numeric value */
+  if (pval)
+    *pval = val;
+  return 1;
+}
+
+static int
+is_visible_alias (Hwcentry* pctr)
+{
+  if (!pctr)
+    return 0;
+  if (pctr->name && pctr->int_name && pctr->metric)
+    return 1;
+  return 0;
+}
+
+static int
+is_hidden_alias (Hwcentry* pctr)
+{
+  if (!pctr)
+    return 0;
+  if (pctr->name && pctr->int_name && pctr->metric == NULL)
+    return 1;
+  return 0;
+}
+
+static int
+is_numeric_alias (Hwcentry* pctr)
+{
+  int is_numeric_alias = 0;
+  regno_t regno;
+  char *nameOnly = NULL;
+  hwcfuncs_parse_ctr (pctr->int_name, NULL, &nameOnly, NULL, NULL, &regno);
+  if (is_numeric (nameOnly, NULL))
+    is_numeric_alias = 1;
+  free (nameOnly);
+  return is_numeric_alias;
+}
+
+/* print list of register to a buffer */
+/*
+ *  style      e x a m p l e s
+ *    0        NONE    2       {0|1|2|3}
+ *    1        NONE    2       : 0, 1, 2, or 3
+ *    2                        0 1 2 3     6
+ */
+static char *
+get_regnolist (char *buf, size_t sz, const regno_t *reg_list, int style)
+{
+  if (!buf || !sz)
+    return "INTERNAL ERROR";
+  buf[0] = 0;
+  if (style == 2)
+    {
+      int ii;
+      // width should be consistent with that in format_columns()
+      // the format will accommodate cpcx_npics regs
+      if (cpcx_npics < 1)
+       return "INTERNAL ERROR";
+      // clear out the buffer
+      for (ii = 0; ii < sz; ii++)
+       buf[ii] = '_';
+      if (cpcx_npics <= 9)
+       {
+         // one char per reg, plus terminating null char
+         if (cpcx_npics + 1 > sz)
+           return "INTERNAL ERROR";
+         buf[cpcx_npics] = '\0';
+
+         // fill buf with regnos
+         for (ii = 0; ii < MAX_PICS; ii++)
+           {
+             regno_t regno = reg_list[ii];
+             if (REG_LIST_EOL (regno))
+               break;
+             if (regno < 0 || regno >= cpcx_npics)
+               return "INTERNAL ERROR";
+             buf[regno] = '0' + regno;
+           }
+       }
+      else
+       {
+         /* space between regs, which may be 1 or 2 digits each
+          *   1 char  for reg 0
+          *   2 chars for regs 1-9 each
+          *   3 chars for regs 10- each
+          *   1 char  for terminating null char
+          */
+         int nchars = 17 + 3 * (cpcx_npics - 9);
+         if (nchars > sz)
+           return "INTERNAL ERROR";
+         buf[nchars - 1] = '\0';
+
+         // fill buf with regnos
+         for (ii = 0; ii < MAX_PICS; ii++)
+           {
+             regno_t regno = reg_list[ii];
+             if (REG_LIST_EOL (regno))
+               break;
+             if (regno <= 9)
+               buf[2 * regno ] = '0' + regno;
+             else
+               {
+                 buf[3 * (regno - 9) + 17] = '0' + (regno / 10);
+                 buf[3 * (regno - 9) + 18] = '0' + (regno % 10);
+               }
+           }
+       }
+      return buf;
+    }
+  if (REG_LIST_IS_EMPTY (reg_list))
+    {
+      snprintf (buf, sz, GTXT ("NONE"));
+      return buf;
+    }
+  else if (REG_LIST_EOL (reg_list[1]))
+    {
+      /* 1 item in list */
+      snprintf (buf, sz, "%d", reg_list[0]);
+      return buf;
+    }
+  else
+    {
+      /* 2 more items in list */
+      int ii, num_regs;
+      for (ii = 0; ii < MAX_PICS; ii++)
+       {
+         regno_t regno = reg_list[ii];
+         if (REG_LIST_EOL (regno))
+           break;
+       }
+      num_regs = ii;
+      buf[0] = 0;
+      for (ii = 0; ii < num_regs; ii++)
+       {
+         regno_t regno = reg_list[ii];
+         if (style == 0)
+           snprintf (buf + strlen (buf), sz - strlen (buf),
+                     "%c%d", ii ? '|' : '{', regno);
+         else
+           {
+             if (num_regs == 2)
+               snprintf (buf + strlen (buf), sz - strlen (buf),
+                         "%d%s", regno, !ii ? " or " : "");
+             else
+               {
+                 /* 3 or more items in list */
+                 if (ii < num_regs - 2)
+                   snprintf (buf + strlen (buf), sz - strlen (buf),
+                             "%d, ", regno);
+                 else if (ii == num_regs - 2)
+                   snprintf (buf + strlen (buf), sz - strlen (buf),
+                             "%d, or ", regno);
+                 else
+                   snprintf (buf + strlen (buf), sz - strlen (buf),
+                             "%d", regno);
+               }
+           }
+       }
+      if (style == 0)
+       snprintf (buf + strlen (buf), sz - strlen (buf), "}");
+    }
+  return buf;
+}
+
+#if !HWC_DEBUG
+#define hwcentry_print(lvl,x1,x2)
+#else
+
+/* print a Hwcentry */
+static void
+hwcentry_print (int lvl, const char * header, const Hwcentry *pentry)
+{
+  char buf[1024];
+  Tprintf (lvl, "%s '%s', '%s', %d, '%s', %d, %d, %d, %d, %d, %d, /",
+          header,
+          pentry->name ? pentry->name : "NULL",
+          pentry->int_name ? pentry->int_name : "NULL",
+          pentry->reg_num,
+          pentry->metric ? pentry->metric : "NULL",
+          pentry->lval, /* low-resolution/long run */
+          pentry->val, /* normal */
+          pentry->hval, /* high-resolution/short run */
+          pentry->timecvt,
+          pentry->memop, /* type of instruction that can trigger */
+          pentry->sort_order);
+  get_regnolist (buf, sizeof (buf), pentry->reg_list, 0);
+  Tprintf (lvl, "%s\n", buf);
+}
+#endif
+
+/* add <regno> to a Hwcentry's list */
+static void
+regno_add (Hwcentry * pctr, regno_t regno)
+{
+  int jj;
+  regno_t *reg_list;
+  if (!pctr)
+    {
+      Tprintf (0, "hwctable: regno_add(): ERROR: pctr==NULL\n");
+      return;
+    }
+  reg_list = pctr->reg_list;
+  if (!reg_list)
+    {
+      /* create list */
+      reg_list = (regno_t*) malloc (sizeof (regno_t*) * MAX_PICS);
+      if (!reg_list)
+       {
+         hwcentry_print (DBG_LT0, "hwctable: regno_add: ERROR:"
+                         " Out of memory: ", pctr);
+         return;
+       }
+      /* initialize list */
+      for (jj = 0; jj < MAX_PICS; jj++)
+       reg_list[jj] = REGNO_ANY;
+      pctr->reg_list = reg_list;
+    }
+  if (regno == REGNO_ANY)
+    {
+      /* add all counters up to cpcx_npics */
+      for (jj = 0; jj < MAX_PICS && jj < cpcx_npics; jj++)
+       reg_list[jj] = jj;
+    }
+  else
+    {
+      /* add <regno> to list of registers */
+      for (jj = 0; jj < MAX_PICS; jj++)
+       {
+         if (reg_list[jj] == regno)
+           {
+             hwcentry_print (DBG_LT0, "hwctable: regno_add: WARNING: "
+                             "Duplicate regno: ", pctr);
+             break;
+           }
+         if (reg_list[jj] == REGNO_ANY)
+           {
+             reg_list[jj] = regno;
+             break;
+           }
+       }
+    }
+  if (jj == MAX_PICS)
+    hwcentry_print (DBG_LT0, "hwctable: regno_add: WARNING:"
+                   " regno list is full:", pctr);
+}
+
+/*---------------------------------------------------------------------------*/
+/* utilities for rawlist (list of raw counters with reglist[] filled in) */
+
+/* search the 'raw' list of counters for <name> */
+static Hwcentry *
+ptrarray_find_by_name (Hwcentry** array, const char * name)
+{
+  if (name == NULL)
+    return NULL;
+  Tprintf (DBG_LT3, "hwctable: array_find_by_name(%s):\n", name);
+  for (int ii = 0; array && array[ii]; ii++)
+    if (strcmp (array[ii]->name, name) == 0)
+      return array[ii];
+  return NULL; /* not found */
+}
+
+/* add Hwcentry to the 'raw' list of counters */
+static Hwcentry *
+alloc_shallow_copy (const Hwcentry *pctr)
+{
+  Hwcentry *node = (Hwcentry *) malloc (sizeof (Hwcentry));
+  if (!node)
+    return NULL; // fail
+  *node = *pctr; /* shallow copy! */
+  if (pctr->name)
+    node->name = strdup (pctr->name);
+  return node;
+}
+
+/* add Hwcentry to the 'raw' list of counters */
+static Hwcentry *
+list_append_shallow_copy (ptr_list *list, const Hwcentry *pctr)
+{
+  Hwcentry *node = alloc_shallow_copy (pctr);
+  if (!node)
+    return NULL; // fail
+  ptr_list_add (list, (void*) node);
+  return node;
+}
+
+static Hwcentry *
+list_add (ptr_list *list, uint_t regno, const char *name)
+{
+  Hwcentry *praw;
+  praw = ptrarray_find_by_name ((Hwcentry**) list->array, name);
+  if (!praw)
+    {
+      Hwcentry tmpctr = empty_ctr;
+      tmpctr.name = (char *) name;
+      praw = list_append_shallow_copy (list, &tmpctr);
+    }
+  if (praw)
+    regno_add (praw, regno);
+  return praw;
+}
+
+/*---------------------------------------------------------------------------*/
+/* utilities for stdlist (table of aliased, hidden, & convenience, ctrs) */
+
+/* find top level definition for <cpuid> */
+static cpu_list_t*
+cputabs_find_entry (int cpuid)
+{
+  int i;
+  /* now search for the appropriate table */
+  for (i = 0;; i++)
+    {
+      if (cputabs[i].cputag == 0)
+       break;
+      if (cpuid == cputabs[i].cputag)
+       return &cputabs[i];
+    }
+  Tprintf (0, "hwctable: cputabs_find_entry: WARNING: "
+          "cpu_id = %d not defined.  No 'standard' counters are available\n",
+          cpuid);
+  return &cputabs[i];
+}
+
+/* find Hwcentry table for <cpuid> */
+static Hwcentry*
+stdlist_get_table (int cpuid)
+{
+  cpu_list_t* tmp = cputabs_find_entry (cpuid);
+  if (tmp)
+    return tmp->stdlist_table;
+  return NULL;
+}
+
+/* search the 'standard' list of counters for <name>,<regno> */
+/* note: <regno>=REGNO_ANY is a wildcard that matches any value. */
+
+/* note: int_name==NULL is a wildcard */
+static const Hwcentry *
+ptrarray_find (const Hwcentry **array, const char *name, const char *int_name,
+              int check_regno, regno_t regno)
+{
+  const Hwcentry *pctr;
+  if (!array)
+    return NULL;
+  for (int ii = 0; array[ii]; ii++)
+    {
+      pctr = array[ii];
+      if (strcmp (pctr->name, name))
+       continue;
+      if (int_name && int_name[0] != 0 && pctr->int_name)
+       {
+         if (NULL == strstr (int_name, pctr->int_name))
+           continue;
+       }
+      if (!check_regno)
+       return pctr;
+      else
+       {
+         /* duplicates aliases are allowed in table because of 6759307 */
+         if (REG_LIST_IS_EMPTY (pctr->reg_list))
+           {
+             /* skip aliases that don't have a valid list of registers */
+             hwcentry_print (1, "hwctable: stdlist_find_by_name:"
+                             " WARNING: alias found, but event not supported by HW:",
+                             pctr);
+             continue;
+           }
+         if (!regno_is_valid (pctr, regno))
+           {
+             hwcentry_print (1, "hwctable: stdlist_find_by_name():"
+                             " WARNING: alias found, but regno doesn't match:",
+                             pctr);
+             continue;
+           }
+         return pctr;
+       }
+    }
+  return NULL;
+}
+
+/* search the 'standard' list of counters for <name>,<regno> */
+
+/* note: <regno>=REGNO_ANY is a wildcard that matches any value. */
+static const Hwcentry *
+static_table_find (const Hwcentry *table, const char *name, const char *int_name,
+                  int check_regno, regno_t regno)
+{
+  int sz;
+  for (sz = 0; table && table[sz].name; sz++)
+    ;
+  if (!sz)
+    return NULL;
+  const Hwcentry ** list = calloc (sz + 1, sizeof (void*));
+  if (!list)
+    return NULL;
+  for (int ii = 0; ii < sz; ii++)
+    list[ii] = &table[ii];
+  list[sz] = NULL;
+  const Hwcentry *pctr = ptrarray_find (list, name, int_name, check_regno, regno);
+  free (list);
+  return pctr;
+}
+
+#if !HWC_DEBUG
+#define stdlist_print(dbg_lvl,table)
+#else
+
+/* print all Hwcentries in standard table.  Check for weird stuff */
+static void
+stdlist_print (int dbg_lvl, const Hwcentry* table)
+{
+  const Hwcentry *pctr;
+  if (!table)
+    {
+      Tprintf (0, "hwctable: stdlist_print: ERROR: "
+              "table is invalid.\n");
+      return;
+    }
+  for (pctr = table; pctr->name; pctr++)
+    {
+      int ii;
+      hwcentry_print (dbg_lvl, "hwctable: stdlist: ", pctr);
+      if (REG_LIST_IS_EMPTY (pctr->reg_list))
+       {
+         if (pctr->int_name || !pctr->metric)
+           hwcentry_print (DBG_LT1, "hwctable: stdlist_print: WARNING: "
+                           "no hardware event found for table entry", pctr);
+         continue;
+       }
+      /* check if incorrect reg_num used in table */
+      if (!regno_is_valid (pctr, pctr->reg_num))
+       {
+         hwcentry_print (DBG_LT0, "hwctable: stdlist_print: ERROR: "
+                         "reg_num is not in table. ", pctr);
+         continue;
+       }
+      for (ii = 0; ii < MAX_PICS; ii++)
+       {
+         regno_t regno = pctr->reg_list[ii];
+         if (REG_LIST_EOL (regno))
+           break;
+       }
+      if (ii > 1 && pctr->reg_num != REGNO_ANY)
+       {
+         /* several regnos were valid, but only one can be specified */
+         if (pctr->metric || !pctr->int_name)
+           {
+             /* pctr is standard or a raw definition */
+             /* (pctr is not an alias like cycles0) */
+             hwcentry_print (DBG_LT0, "hwctable: stdlist_print: ERROR: "
+                             "regno in table should have been REGNO_ANY. ",
+                             pctr);
+           }
+       }
+    }
+}
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* utilities for init */
+
+/* try to bind counters to hw.  Return 0 on success, nonzero otherwise */
+static int
+test_hwcs (const Hwcentry* entries[], unsigned numctrs)
+{
+  int rc = -1;
+  hwc_event_t sample;
+  int created = 0;
+  hwcdrv_api_t *hwcdrv = get_hwcdrv ();
+  Tprintf (DBG_LT2, "hwctable: test_hwcs()...\n");
+  rc = hwcfuncs_bind_hwcentry (entries, numctrs);
+  if (rc)
+    {
+      Tprintf (0, "hwctable: WARNING: test "
+              "counters could not be created\n");
+      goto end_test_hwcs;
+    }
+  created = 1;
+  if (!signals_disabled)
+    {
+      (void) signal (HWCFUNCS_SIGNAL, SIG_IGN);
+      signals_disabled = 1;
+    }
+  rc = hwcdrv->hwcdrv_start ();
+  if (rc)
+    {
+      Tprintf (0, "hwctable: WARNING: test "
+              "counters could not be started\n");
+      goto end_test_hwcs;
+    }
+  rc = hwcdrv->hwcdrv_read_events (&sample, NULL);
+  if (rc)
+    Tprintf (0, "hwctable: WARNING: test sample failed\n");
+  rc = 0;
+#if HWC_DEBUG
+  {
+    unsigned ii;
+    Tprintf (DBG_LT1, "hwctable: test_hwcs(");
+    for (ii = 0; ii < numctrs; ii++)
+      Tprintf (DBG_LT1, "%s%s", ii ? "," : "", entries[ii]->name);
+    Tprintf (DBG_LT1, ") PASS\n");
+  }
+#endif
+
+end_test_hwcs:
+  if (created && hwcdrv->hwcdrv_free_counters ())
+    Tprintf (0, "hwctable: WARNING: test counters could not be freed\n");
+  return rc;
+}
+
+#if !HWC_DEBUG
+#define check_tables()
+#else
+
+/* check for typos in tables */
+static void
+check_tables ()
+{
+  int i;
+  /* now search the known table of counters */
+  for (i = 0;; i++)
+    {
+      Hwcentry * pentry;
+      int cputag = cputabs[i].cputag;
+      if (cputag == 0)
+       break;
+      if (cputag == CPC_KPROF)
+       continue;
+      pentry = cputabs[i].stdlist_table;
+      for (; pentry; pentry++)
+       {
+         if (!pentry->name)
+           break;
+         if (!pentry->int_name)
+           {/* internal, only to supply ABST and timecvt */
+             if (pentry->metric)
+               Tprintf (DBG_LT0, "hwctable: check_tables: ERROR:"
+                        " internal && metric @%d, %s\n", cputag, pentry->name);
+             if (pentry->reg_num != REGNO_ANY)
+               Tprintf (DBG_LT1, "hwctable: check_tables: WARNING:"
+                        " internal && reg_num!=REGNO_ANY @%d, %s\n",
+                        cputag, pentry->name);
+             if (pentry->val != PRELOAD_DEF
+                 && pentry->memop != ABST_EXACT_PEBS_PLUS1)
+               Tprintf (DBG_LT2, "hwctable: check_tables: INFO:"
+                        " internal && custom val=%d @%d, %s\n",
+                        pentry->val, cputag, pentry->name);
+#if 0
+             if (!pentry->timecvt && pentry->memop == ABST_NONE)
+               Tprintf (DBG_LT0, "hwctable: check_tables: ERROR:"
+                        " internal && not special! @%d, %s\n",
+                        cputag, pentry->name);
+#endif
+           }
+         if (pentry->metric)
+           { /* aliased */
+             if (!pentry->int_name)
+               Tprintf (DBG_LT0, "hwctable: check_tables: ERROR:"
+                        " aliased && !int_name @%d, %s\n", cputag, pentry->name);
+#if 0
+             else if (!strcmp (pentry->name, pentry->int_name))
+               Tprintf (DBG_LT0, "hwctable: check_tables: ERROR:"
+                        " name==int_name @%d, %s\n",
+                        cputag, pentry->name);
+#endif
+             if (pentry->reg_num != REGNO_ANY && pentry->reg_num != REGNO_INVALID)
+               Tprintf (DBG_LT1, "hwctable: check_tables: INFO:"
+                        " aliased && custom reg_num==%d @%d, %s\n",
+                        pentry->reg_num, cputag, pentry->name);
+             if (pentry->reg_num == REGNO_INVALID)
+               Tprintf (DBG_LT2, "hwctable: check_tables: INFO:"
+                        " aliased && reg_num==REGNO_INVALID @%d, %s\n",
+                        cputag, pentry->name);
+           }
+         if (pentry->int_name && !pentry->metric)
+           { /* convenience */
+             if (!strcmp (pentry->name, pentry->int_name))
+                 Tprintf (DBG_LT0, "hwctable: check_tables: ERROR:"
+                          " convenience && name==int_name @%d, %s\n",
+                          cputag, pentry->name);
+             if (pentry->reg_num == REGNO_ANY)
+                 Tprintf (DBG_LT0, "hwctable: check_tables: ERROR:"
+                          " convenience && reg_num==REGNO_ANY @%d, %s\n",
+                          cputag, pentry->name);
+           }
+       }
+    }
+}
+#endif
+
+static int try_a_counter ();
+static void hwc_process_raw_ctrs (int forKernel, Hwcentry ***pstd_out,
+                                 Hwcentry ***praw_out, Hwcentry ***phidden_out,
+                                 Hwcentry**static_tables,
+                                 Hwcentry **raw_unfiltered_in);
+
+/* internal call to initialize libs, ctr tables */
+static void
+setup_cpc_general (int skip_hwc_test)
+{
+  const cpu_list_t* cputabs_entry;
+  int rc = -1;
+  Tprintf (DBG_LT2, "hwctable: setup_cpc()... \n");
+  if (initialized)
+    {
+      Tprintf (0, "hwctable: WARNING: setup_cpc() has already been called\n");
+      return;
+    }
+  initialized = 1;
+  cpcx_cpuver = CPUVER_UNDEFINED;
+  cpcx_cciname = NULL;
+  cpcx_npics = 0;
+  cpcx_docref = NULL;
+  cpcx_support_bitmask = 0;
+  for (int kk = 0; kk < 2; kk++)
+    { // collect-0 and kernel-1
+      cpcx_attrs[kk] = NULL;
+      cpcx_std[kk] = NULL;
+      cpcx_raw[kk] = NULL;
+      cpcx_hidden[kk] = NULL;
+      cpcx_max_concurrent[kk] = 0;
+      cpcx_default_hwcs[kk] = NULL;
+      cpcx_orig_default_hwcs[kk] = NULL;
+      cpcx_has_precise[kk] = 0;
+    }
+  check_tables ();
+  hwcdrv_api_t *hwcdrv = get_hwcdrv ();
+  if (hwcdrv->hwcdrv_init_status)
+    {
+      Tprintf (0, "WARNING: setup_cpc_general() failed. init_status=%d \n",
+              hwcdrv->hwcdrv_init_status);
+      goto setup_cpc_wrapup;
+    }
+  hwcdrv->hwcdrv_get_info (&cpcx_cpuver, &cpcx_cciname, &cpcx_npics,
+                          &cpcx_docref, &cpcx_support_bitmask);
+
+#ifdef DISALLOW_USI_USII_6357446
+  if (cpcx_cpuver == CPC_ULTRA1 || cpcx_cpuver == CPC_ULTRA2)
+    {
+      Tprintf (0, "hwctable: WARNING: setup_cpc(): cpu=%d"
+              " US-I/US-II cannot provide profile interrupts\n", cpcx_cpuver);
+      /* profiling interrupts don't work on US-I, US-II */
+      hwcfuncs_int_logerr (GTXT ("UltraSPARC I and II cannot provide overflow interrupts\n"));
+      goto setup_cpc_wrapup;
+    }
+#endif
+
+#ifdef DISALLOW_PENTIUM_PRO_MMX_7007575
+  if (cpcx_cpuver == CPC_PENTIUM_PRO_MMX)
+    {
+      Tprintf (0, "hwctable: WARNING: setup_cpc(): cpu=%d"
+              " `Pentium Pro with MMX, Pentium II' is not supported\n", cpcx_cpuver);
+      hwcfuncs_int_logerr (GTXT ("libcpc cannot identify processor type\n"));
+      goto setup_cpc_wrapup;
+    }
+#endif
+
+  /* now search the known table of counters */
+  cputabs_entry = cputabs_find_entry (cpcx_cpuver);
+  if (cputabs_entry == NULL)
+    {
+      Tprintf (0, "hwctable: WARNING: setup_cpc(): cpu=%d"
+              " could not be found in the tables\n", cpcx_cpuver);
+      /* strange, should have at least selected "unknownlist" */
+      hwcfuncs_int_logerr (GTXT ("Analyzer CPU table could not be found\n"));
+      goto setup_cpc_wrapup;
+    }
+
+  Hwcentry * valid_cpu_tables[2]; // [0]:static table of counters, [1]:static table of generic counters
+  valid_cpu_tables[0] = cputabs_entry->stdlist_table;
+  if (valid_cpu_tables[0] == NULL)
+    {
+      Tprintf (0, "hwctable: WARNING: setup_cpc(): "
+              " valid_cpu_tables was NULL??\n");
+      /* strange, someone put a NULL in the lookup table? */
+      hwcfuncs_int_logerr (GTXT ("Analyzer CPU table is invalid\n"));
+      goto setup_cpc_wrapup;
+    }
+  valid_cpu_tables[1] = papi_generic_list;
+  Tprintf (DBG_LT2, "hwctable: setup_cpc(): getting descriptions \n");
+  // populate cpcx_raw and cpcx_attr
+  hwcdrv->hwcdrv_get_descriptions (hwc_cb, attrs_cb);
+  for (int kk = 0; kk < 2; kk++)
+    { // collect and er_kernel
+      hwc_process_raw_ctrs (kk, &cpcx_std[kk], &cpcx_raw[kk], &cpcx_hidden[kk],
+                           valid_cpu_tables, (Hwcentry**) unfiltered_raw.array);
+      cpcx_has_precise[kk] = 0;
+      for (int rr = 0; cpcx_raw[kk] && cpcx_raw[kk][rr]; rr++)
+       {
+         int memop = cpcx_raw[kk][rr]->memop;
+         if (ABST_MEMSPACE_ENABLED (memop))
+           {
+             cpcx_has_precise[kk] = 1;
+             break;
+           }
+       }
+      cpcx_attrs[kk] = (char**) unfiltered_attrs.array;
+      cpcx_max_concurrent[kk] = cpcx_npics;
+    }
+#if 1 // 22897042 - DTrace cpc provider does not support profiling on multiple ctrs on some systems
+  if ((cpcx_support_bitmask & HWCFUNCS_SUPPORT_OVERFLOW_CTR_ID) != HWCFUNCS_SUPPORT_OVERFLOW_CTR_ID)
+    {
+      // kernel profiling only supports one counter if overflowing counter can't be identified
+      cpcx_max_concurrent[1] = cpcx_npics ? 1 : 0;
+    }
+#endif
+
+  /* --- quick test of the cpc interface --- */
+  if (skip_hwc_test)
+    rc = 0;
+  else
+    rc = try_a_counter (0);
+
+  /* initialize the default counter string definition */
+  for (int kk = 0; kk < 2; kk++)
+    {
+      char * default_exp = 0;
+      int jj;
+      for (jj = 0; (default_exp = cputabs_entry->default_exp_p[jj]); jj++)
+       {
+         int rc = hwc_lookup (kk, 0, default_exp, NULL, 0, NULL, NULL);
+         if (rc > 0)
+           break;
+       }
+      if (!default_exp)
+       {
+         char * fallback[3] = {NTXT ("insts,,cycles,,l3m"), NTXT ("insts,,cycles"), NTXT ("insts")};
+         for (int ff = 0; ff < 3; ff++)
+           {
+             int rc = hwc_lookup (kk, 0, fallback[ff], NULL, 0, NULL, NULL);
+             if (rc > 0)
+               {
+                 default_exp = strdup (fallback[ff]);
+                 break;
+               }
+           }
+       }
+      cpcx_default_hwcs[kk] = default_exp;
+      cpcx_orig_default_hwcs[kk] = default_exp;
+    }
+
+setup_cpc_wrapup:
+  if (rc)
+    {
+      cpcx_npics = 0;
+      /*
+             ptr_list_free(&tmp_raw); // free stuff... YXXX
+             ptr_list_free(&unfiltered_attrs);
+       */
+    }
+  return;
+}
+
+static void
+setup_cpcx ()
+{
+  if (initialized)
+    return;
+  setup_cpc_general (0); // set up and include a hwc test run
+}
+
+static void
+setup_cpc_skip_hwctest ()
+{
+  if (initialized)
+    return;
+  setup_cpc_general (1); // set up but skip hwc test run
+}
+
+static int
+try_a_counter (int forKernel)
+{
+  if (!VALID_FOR_KERNEL (forKernel))
+    return -1;
+  int rc = -1;
+  const Hwcentry * testevent;
+  if (cpcx_std[forKernel] == NULL)
+    {
+      Tprintf (0, "hwctable: WARNING: cpcx_std not initialized");
+      return 0; /* consider this an automatic PASS */
+    }
+  /* look for a valid table entry, only try valid_cpu_tables[0] */
+  {
+    testevent = cpcx_std[forKernel][0];
+    if (!testevent || !testevent->name)
+      {
+       Tprintf (0, "hwctable: WARNING: no test metric"
+                " available to verify counters\n");
+       return 0; /* consider this an automatic PASS */
+      }
+    if (REG_LIST_IS_EMPTY (testevent->reg_list))
+      return 0; // weird
+  }
+  Hwcentry tmp_testevent;
+  tmp_testevent = *testevent; /* shallow copy */
+  if (tmp_testevent.int_name == NULL)
+    {
+      /* counter is defined in 'hidden' section of table, supply int_name */
+      tmp_testevent.int_name = strdup (tmp_testevent.name);
+    }
+  Hwcentry * test_array[1] = {&tmp_testevent};
+  rc = hwcfuncs_assign_regnos (test_array, 1); /* may modify test_array */
+  if (rc)
+    return rc;
+  rc = test_hwcs ((const Hwcentry**) test_array, 1);
+  if (rc == HWCFUNCS_ERROR_UNAVAIL)
+    {
+      // consider this a pass (allow HWC table to be printed)
+      Tprintf (0, "hwctable: WARNING: "
+              "cpc_bind_event() shows counters busy; allow to continue\n");
+      return 0;
+    }
+  else if (rc)
+    {
+      // failed to start for some other reason
+      Tprintf (0, "hwctable: WARNING: "
+              "test of counter '%s' failed\n",
+              testevent->name);
+      return rc;
+    }
+  return 0;
+}
+
+void
+hwc_update_val (Hwcentry *hwc)
+{
+  if (hwc->ref_val == 0)
+    hwc->ref_val = hwc->val; // save original reference
+  int64_t newVal;
+  hrtime_t min_time_nsec = hwc->min_time;
+  if (min_time_nsec == HWCTIME_TBD)
+    min_time_nsec = hwc->min_time_default;
+  switch (min_time_nsec)
+    {
+    case 0: // disable time-based intervals
+      // do not modify val
+      return;
+    case HWCTIME_ON:
+    case HWCTIME_TBD:
+      newVal = HWC_VAL_ON (hwc->ref_val);
+      break;
+    case HWCTIME_LO:
+      newVal = HWC_VAL_LO (hwc->ref_val);
+      break;
+    case HWCTIME_HI:
+      newVal = HWC_VAL_HI (hwc->ref_val);
+      break;
+    default:
+      newVal = HWC_VAL_CUSTOM (hwc->ref_val, min_time_nsec);
+      break;
+    }
+#define MAX_INT_VAL (2*1000*1000*1000 + 1000100)// yuck, limited to signed int
+  if (newVal >= MAX_INT_VAL)
+    newVal = MAX_INT_VAL;
+  hwc->val = newVal;
+}
+
+/* convert value string to value and store result in hwc->val */
+/* This function moved here from collctrl.cc */
+/*
+ * Keep the HWCTIME_* definitions in sync with those in
+ * collctrl.cc Coll_Ctrl::add_hwcstring().
+ */
+static int
+set_hwcval (Hwcentry *hwc, hrtime_t global_min_time_nsec, const char *valptr)
+{
+  hwc->min_time_default = global_min_time_nsec;
+  if (hwc->val == 1)
+    {
+      // An interval of 1 is used for certain types of count data.
+      // (er_bit, er_generic, er_rock ...)
+      // Hi and Lo do not apply.
+      /* use the default */
+    }
+  else if (valptr == NULL || valptr[0] == 0 || strcmp (valptr, "auto") == 0)
+    hwc->min_time = HWCTIME_TBD;
+  else if (strcmp (valptr, "on") == 0)
+    hwc->min_time = HWCTIME_ON;
+  else if (strcmp (valptr, "lo") == 0 || strcmp (valptr, "low") == 0)
+    hwc->min_time = HWCTIME_LO;
+  else if (strcmp (valptr, "hi") == 0 || strcmp (valptr, "high") == 0
+          || strcmp (valptr, "h") == 0)
+    hwc->min_time = HWCTIME_HI;
+  else
+    {
+      /* the remaining string should be a number > 0 */
+      char *endchar = NULL;
+      long long tmp = strtoll (valptr, &endchar, 0);
+      int value = (int) tmp;
+      if (*endchar != 0 || tmp <= 0 || value != tmp)
+       {
+         // also covers errno == ERANGE
+         Tprintf (0, "hwctable: set_hwcval(): ERROR: "
+                  "Invalid counter value %s for counter `%s'\n",
+                  valptr, hwc->name);
+         return -1;
+       }
+      if (tmp > UINT32_MAX / 2)
+       {
+         /* Roch B. says that we MUST do this check for er_kernel
+            because some platforms deliver overflow interrupts without
+            identifying which counter overflowed.  The only way to
+            determine which counter overflowed is to have enough
+            margin on 32 bit counters to make sure they don't
+            wrap.
+          */
+         Tprintf (0, "hwctable: set_hwcval(): ERROR: "
+                  "Counter value %s exceeds %lu\n",
+                  valptr, (unsigned long) UINT32_MAX / 2);
+         return -1;
+       }
+      /* set the value */
+      if (value != 0)
+       {
+         if (hwc->ref_val == 0)
+           hwc->ref_val = hwc->val; // save original reference
+         hwc->val = value;
+         hwc->min_time = 0; // turn off auto-adjust
+       }
+    }
+  hwc_update_val (hwc);
+  return 0;
+}
+
+static char *
+canonical_name (const char *counter)
+{
+  char *nameOnly = NULL;
+  char *attrs = NULL;
+  char tmpbuf[1024];
+  tmpbuf[0] = 0;
+  hwcfuncs_parse_ctr (counter, NULL, &nameOnly, &attrs, NULL, NULL);
+  snprintf (tmpbuf + strlen (tmpbuf), sizeof (tmpbuf) - strlen (tmpbuf),
+           "%s", nameOnly);
+  if (attrs)
+    {
+      hwcfuncs_attr_t cpc2_attrs[HWCFUNCS_MAX_ATTRS];
+      void * attr_mem;
+      unsigned nattrs;
+      int ii, jj;
+
+      /* extract attributes from counter */
+      attr_mem = hwcfuncs_parse_attrs (counter, cpc2_attrs, HWCFUNCS_MAX_ATTRS,
+                                      &nattrs, NULL);
+      if (!attr_mem)
+       {
+         snprintf (tmpbuf + strlen (tmpbuf), sizeof (tmpbuf) - strlen (tmpbuf),
+                   "~UNKNOWN");
+         goto canonical_attrs_wrapup;
+       }
+
+      /* sort the attributes */
+      for (ii = 0; ii < (int) nattrs - 1; ii++)
+       {
+         for (jj = ii + 1; jj < nattrs; jj++)
+           {
+             int cmp = strcmp (cpc2_attrs[ii].ca_name,
+                               cpc2_attrs[jj].ca_name);
+             if (cmp > 0)
+               {
+                 hwcfuncs_attr_t tmp = cpc2_attrs[jj];
+                 cpc2_attrs[jj] = cpc2_attrs[ii];
+                 cpc2_attrs[ii] = tmp;
+               }
+           }
+       }
+
+      /* print attributes in canonical format */
+      for (ii = 0; ii < nattrs; ii++)
+       snprintf (tmpbuf + strlen (tmpbuf), sizeof (tmpbuf) - strlen (tmpbuf),
+                 "~%s=0x%llx", cpc2_attrs[ii].ca_name, (long long) cpc2_attrs[ii].ca_val);
+      free (attr_mem);
+    }
+canonical_attrs_wrapup:
+  free (nameOnly);
+  free (attrs);
+  return strdup (tmpbuf);
+}
+
+/* process counter and value strings - put results in <*pret_ctr> */
+
+/* Print errors to UEbuf for any failure that results in nonzero return */
+static int
+process_ctr_def (int forKernel, hrtime_t global_min_time_nsec,
+                const char *counter, const char *value, Hwcentry *pret_ctr,
+                char* UWbuf, size_t UWsz, char* UEbuf, size_t UEsz)
+{
+  int rc = -1;
+  char *nameOnly = NULL;
+  char *attrs = NULL;
+  char *regstr = NULL;
+  int plus;
+  regno_t regno;
+  const Hwcentry *pfound = NULL;
+  const char *uname = NULL;
+  int disable_backtrack;
+  UEbuf[0] = 0;
+  UWbuf[0] = 0;
+  Tprintf (DBG_LT3, "hwctable: process_ctr_def(): counter=%s value=%s \n",
+          counter, value ? value : "NULL");
+  hwcfuncs_parse_ctr (counter, &plus, &nameOnly, &attrs, &regstr, &regno);
+
+  /* search for the counter in the std and raw lists */
+  {
+    pfound = ptrarray_find ((const Hwcentry**) cpcx_std[forKernel], nameOnly, NULL, 1, regno);
+    if (pfound)
+      hwcentry_print (DBG_LT1, "hwctable: process_ctr_def: found in stdlist:",
+                     pfound);
+  }
+  if (!pfound)
+    {
+      pfound = ptrarray_find ((const Hwcentry**) cpcx_hidden[forKernel], nameOnly, NULL, 1, regno);
+      if (pfound)
+       hwcentry_print (DBG_LT1, "hwctable: process_ctr_def: found in stdlist(hidden):", pfound);
+    }
+  if (!pfound)
+    {
+      pfound = ptrarray_find_by_name (cpcx_raw[forKernel], nameOnly); /* (regno match checked later) */
+      if (pfound)
+       hwcentry_print (DBG_LT1, "hwctable: process_ctr_def: found in rawlist:", pfound);
+    }
+  if (!pfound)
+    {
+      pfound = ptrarray_find ((const Hwcentry**) cpcx_std[forKernel], nameOnly, NULL, 1, REGNO_ANY);
+      if (pfound)
+       hwcentry_print (DBG_LT1, "hwctable: process_ctr_def: found in stdlist but regno didn't match:", pfound);
+    }
+  if (!pfound)
+    {
+      pfound = ptrarray_find ((const Hwcentry**) cpcx_hidden[forKernel], nameOnly, NULL, 1, REGNO_ANY);
+      if (pfound)
+       hwcentry_print (DBG_LT1, "hwctable: process_ctr_def: found in stdlist(hidden) but regno didn't match:", pfound);
+    }
+  if (!pfound)
+    {
+      uint64_t val = 0;
+      if (is_numeric (nameOnly, &val))
+       {
+         Hwcentry *tmp = alloc_shallow_copy (&empty_ctr); // Leaks?
+         if (tmp)
+           {
+             tmp->name = strdup (nameOnly);
+             regno_add (tmp, REGNO_ANY);
+             pfound = tmp;
+           }
+       }
+      if (pfound)
+       hwcentry_print (DBG_LT1, "hwctable: process_ctr_def: counter specified by numeric value:", pfound);
+    }
+  if (!pfound)
+    {
+      snprintf (UEbuf + strlen (UEbuf), UEsz - strlen (UEbuf),
+               GTXT ("Invalid HW counter name: %s\n"), nameOnly);
+      snprintf (UEbuf + strlen (UEbuf), UEsz - strlen (UEbuf),
+               GTXT ("Run \"%s -h\" with no other arguments for more information on HW counters on this system.\n"),
+               (IS_KERNEL (forKernel) ? "er_kernel" : "collect"));
+      goto process_ctr_def_wrapup;
+    }
+
+  /* counter found */
+  *pret_ctr = *pfound; /* shallow copy */
+  pret_ctr->int_name = NULL; /* so free doesn't try to free these pfound's ptrs */
+  pret_ctr->name = NULL; /* so free doesn't try to free these pfound's ptrs */
+
+  /* update uname,memop */
+  uname = counter;
+  disable_backtrack = 0;
+  if (plus != 0 || ABST_PLUS_BY_DEFAULT (pret_ctr->memop))
+    {
+      // attempt to process memoryspace profiling
+      int message_printed = 0;
+      if (cpcx_cpuver == CPUVER_GENERIC)
+       {
+         // accept plus, since we don't know what this CPU is
+         snprintf (UEbuf + strlen (UEbuf), UEsz - strlen (UEbuf),
+                   GTXT ("`+' may not be correctly supported on `%s' because processor is not recognized."),
+                   cpcx_cciname);
+         pret_ctr->memop = ABST_LDST; // supply a backtracking data type - required for collector
+       }
+      else if (cpcx_cpuver == CPC_ULTRA1 || cpcx_cpuver == CPC_ULTRA2
+              || cpcx_cpuver == CPC_ULTRA3 || cpcx_cpuver == CPC_ULTRA3_PLUS
+              || cpcx_cpuver == CPC_ULTRA3_I || cpcx_cpuver == CPC_ULTRA4_PLUS
+              || cpcx_cpuver == CPC_ULTRA4 || cpcx_cpuver == CPC_ULTRA_T1
+              || cpcx_cpuver == CPC_ULTRA_T2 || cpcx_cpuver == CPC_ULTRA_T2P
+              || cpcx_cpuver == CPC_ULTRA_T3)
+       {
+         if (!ABST_BACKTRACK_ENABLED (pret_ctr->memop))
+           disable_backtrack = 1;
+       }
+      else if (cpcx_cpuver == CPC_SPARC_T4 || cpcx_cpuver == CPC_SPARC_T5
+              || cpcx_cpuver == CPC_SPARC_T6 || cpcx_cpuver == CPC_SPARC_M4
+              || cpcx_cpuver == CPC_SPARC_M5 || cpcx_cpuver == CPC_SPARC_M6
+              || cpcx_cpuver == CPC_SPARC_M7 || cpcx_cpuver == CPC_SPARC_M8)
+       {
+         if (pret_ctr->memop != ABST_EXACT)
+           disable_backtrack = 1;
+       }
+      else if (cpcx_cpuver == CPC_INTEL_NEHALEM || cpcx_cpuver == CPC_INTEL_WESTMERE
+              || cpcx_cpuver == CPC_INTEL_SANDYBRIDGE
+              || cpcx_cpuver == CPC_INTEL_IVYBRIDGE
+              || cpcx_cpuver == CPC_INTEL_HASWELL
+              || cpcx_cpuver == CPC_INTEL_BROADWELL
+              || cpcx_cpuver == CPC_INTEL_SKYLAKE)
+       {
+         if (pret_ctr->memop != ABST_EXACT_PEBS_PLUS1)
+           disable_backtrack = 1;
+         else if (plus < 0)
+           {
+             // disabling memoryspace not supported for
+             // remove specified -
+             uname++;
+             plus = 0;
+             snprintf (UWbuf + strlen (UWbuf), UWsz - strlen (UWbuf),
+                       GTXT ("Warning: `-' is not supported on `%s' -- memory reference backtracking will remain enabled for this counter\n"),
+                       nameOnly);
+           }
+       }
+      else
+       {
+         message_printed = 1;
+         snprintf (UWbuf + strlen (UWbuf), UWsz - strlen (UWbuf),
+                   GTXT ("Warning: `+' is not supported on `%s' -- memory reference backtracking will not be enabled for `%s'\n"),
+                   cpcx_cciname, nameOnly);
+         disable_backtrack = 1;
+       }
+      if (disable_backtrack)
+       {
+         if (plus != 0)
+           uname++;    // remove specified + or -
+         if (!message_printed && plus > 0)
+           snprintf (UWbuf + strlen (UWbuf), UWsz - strlen (UWbuf),
+                     GTXT ("Warning: `+' is not supported on `%s' -- memory reference backtracking will not be enabled for this counter\n"),
+                     nameOnly);
+       }
+    }
+  else
+    disable_backtrack = 1;
+  if (disable_backtrack || plus < 0)
+    if (pret_ctr->memop != ABST_NOPC)
+      pret_ctr->memop = ABST_NONE;
+  if (pret_ctr->memop == ABST_NOPC)
+    snprintf (UWbuf + strlen (UWbuf), UWsz - strlen (UWbuf),
+             GTXT ("Warning: HW counter `%s' is not program-related -- callstacks will be not be recorded for this counter\n"),
+             uname);
+
+  /* update reg_num */
+  if (!regno_is_valid (pfound, regno))
+    {
+      char buf[1024];
+      snprintf (UEbuf + strlen (UEbuf), UEsz - strlen (UEbuf),
+               GTXT ("For counter `%s', %s is not a valid register; valid registers: %s\n"),
+               nameOnly, regstr ? regstr + 1 : "?",
+               get_regnolist (buf, sizeof (buf), pfound->reg_list, 1));
+      goto process_ctr_def_wrapup;
+    }
+  if (pret_ctr->reg_num == REGNO_ANY)
+    { /* table's regno is a wildcard */
+      if (REG_LIST_EOL (pfound->reg_list[1]))
+       {
+         /* valid list only contains one regno, so use it */
+         pret_ctr->reg_num = pfound->reg_list[0];
+       }
+      else
+       pret_ctr->reg_num = regno;  /* use user's selection */
+    }
+
+  /* update name and int_name */
+  {
+    // validate attributes
+    if (attrs)
+      {
+       hwcfuncs_attr_t cpc2_attrs[HWCFUNCS_MAX_ATTRS];
+       void * attr_mem;
+       unsigned nattrs;
+       char *errbuf;
+       /* extract attributes from uname */
+       attr_mem = hwcfuncs_parse_attrs (uname, cpc2_attrs, HWCFUNCS_MAX_ATTRS,
+                                        &nattrs, &errbuf);
+       if (!attr_mem)
+         {
+           snprintf (UEbuf + strlen (UEbuf), UEsz - strlen (UEbuf),
+                     "%s\n", errbuf);
+           free (errbuf);
+           goto process_ctr_def_wrapup;
+         }
+       /* make sure all attributes are valid */
+       for (unsigned ii = 0; ii < nattrs; ii++)
+         {
+           if (!attr_is_valid (forKernel, cpc2_attrs[ii].ca_name))
+             {
+               snprintf (UEbuf + strlen (UEbuf), UEsz - strlen (UEbuf),
+                         GTXT ("Invalid attribute specified for counter `%s': %s\n"),
+                         nameOnly, cpc2_attrs[ii].ca_name);
+               snprintf (UEbuf + strlen (UEbuf), UEsz - strlen (UEbuf),
+                         GTXT ("Run \"%s -h\" with no other arguments for more information on HW counters on this system.\n"),
+                         (IS_KERNEL (forKernel) ? "er_kernel" : "collect"));
+               free (attr_mem);
+               goto process_ctr_def_wrapup;
+             }
+           for (unsigned jj = ii + 1; jj < nattrs; jj++)
+             {
+               if (strcmp (cpc2_attrs[ii].ca_name,
+                           cpc2_attrs[jj].ca_name) == 0)
+                 {
+                   snprintf (UEbuf + strlen (UEbuf), UEsz - strlen (UEbuf),
+                             GTXT ("Duplicate attribute specified for counter `%s': %s\n"),
+                             nameOnly, cpc2_attrs[ii].ca_name);
+                   free (attr_mem);
+                   goto process_ctr_def_wrapup;
+                 }
+             }
+         }
+       free (attr_mem);
+      }
+    pret_ctr->name = strdup (uname);
+
+    // assign int_name
+    if (pfound->int_name)
+      {
+       // Counter is one of the following:
+       // - aliased (e.g. cycles~system=1),
+       // - convenience (e.g. cycles0~system=1),
+       if (!attrs) // convert alias to internal name
+         pret_ctr->int_name = strdup (pfound->int_name);
+       else
+         {
+           // convert alias to internal name and
+           // append user-supplied attributes
+           size_t sz = strlen (pfound->int_name) + strlen (attrs) + 1;
+           char *tbuf = calloc (sz, 1);
+           if (tbuf)
+             snprintf (tbuf, sz, "%s%s", pfound->int_name, attrs);
+           pret_ctr->int_name = tbuf;
+         }
+      }
+    else
+      pret_ctr->int_name = strdup (uname);  // user-supplied name
+  }
+
+  /* update val */
+  if (set_hwcval (pret_ctr, global_min_time_nsec, value))
+    {
+      snprintf (UEbuf + strlen (UEbuf), UEsz - strlen (UEbuf),
+               GTXT ("Invalid interval for HW counter `%s': %s\n"),
+               nameOnly, value);
+      goto process_ctr_def_wrapup;
+    }
+  hwcentry_print (DBG_LT2, "hwctable: process_ctr_def:", pret_ctr);
+  rc = 0;
+
+process_ctr_def_wrapup:
+  free (regstr);
+  free (attrs);
+  free (nameOnly);
+  return rc;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/* external interfaces, see hwcentry.h for descriptions. */
+
+extern int
+hwc_lookup (int forKernel, hrtime_t global_min_time_nsec, const char *instring,
+           Hwcentry *caller_entries[], unsigned maxctrs, char **emsg, char **wmsg)
+{
+  unsigned ii;
+  char *instr_copy = NULL, *ss = NULL;
+  unsigned numctrs = 0;
+  int rc = 0;
+  char *tokenptr[MAX_PICS * 2];
+  unsigned numtokens = 0;
+  char UEbuf[1024 * 5]; /* error message buffer; strdup of it is passed back to user  */
+  char UWbuf[1024 * 5]; /* warning message buffer; strdup of it is passed back to user  */
+  if (emsg)
+    *emsg = NULL;
+  if (wmsg)
+    *wmsg = NULL;
+  UEbuf[0] = 0;
+  UWbuf[0] = 0;
+
+  // supply temporary result buffers as needed
+  Hwcentry tmp_entry_table[MAX_PICS];
+  Hwcentry * tmp_entries[MAX_PICS];
+  Hwcentry **entries;
+  if (caller_entries)
+    entries = caller_entries;
+  else
+    {
+      // user doesn't care about results; provide temporary storage for results
+      for (ii = 0; ii < MAX_PICS; ii++)
+       tmp_entries[ii] = &tmp_entry_table[ii];
+      entries = tmp_entries;
+      maxctrs = MAX_PICS;
+    }
+  Tprintf (DBG_LT1, "hwctable: hwc_lookup(%s)\n",
+          instring ? instring : "NULL");
+
+  /* clear <entries> first - prevent seg faults in hwc_lookup_wrapup */
+  for (ii = 0; ii < maxctrs; ii++)
+    *entries[ii] = empty_ctr;
+  if (!instring)
+    {
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("No HW counters were specified."));
+      rc = -1;
+      goto hwc_lookup_wrapup;
+    }
+
+  /* make sure tables are initialized */
+  setup_cpc_skip_hwctest ();
+  if (cpcx_npics == 0)
+    {
+      if (cpcx_cpuver < 0)
+       {
+         char buf[1024];
+         *buf = 0;
+         char *pch = hwcfuncs_errmsg_get (buf, sizeof (buf), 0); /* get first err msg, disable capture */
+         if (*pch)
+           snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                     GTXT ("HW counter profiling is not supported on this system: %s%s"),
+                     pch, pch[strlen (pch) - 1] == '\n' ? "" : "\n");
+         else
+           snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                     GTXT ("HW counter profiling is not supported on this system\n"));
+       }
+      else
+       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                 GTXT ("HW counter profiling is not supported on '%s'\n"),
+                 cpcx_cciname);
+      rc = -1;
+      goto hwc_lookup_wrapup;
+    }
+  ss = instr_copy = strdup (instring);
+  while (*ss != 0 && (*ss == ' ' || *ss == '\t'))
+    ss++;
+  tokenptr[numtokens++] = ss;
+  do
+    {
+      /* find end of previous token, replace w/ NULL, skip whitespace, set <tokenptr>, repeat */
+      for (; *ss; ss++)
+       {
+         if (*ss == ',' || *ss == ' ' || *ss == '\t')
+           {
+             /* end of previous token found */
+             *ss = 0; /* terminate the previous token */
+             ss++;
+             while (*ss != 0 && (*ss == ' ' || *ss == '\t'))
+               ss++;
+             if (*ss)
+               tokenptr[numtokens++] = ss;
+             break; // from for loop
+           }
+       }
+    }
+  while (*ss && numtokens < (MAX_PICS * 2));
+
+  if (*ss)
+    {
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("The number of HW counters specified exceeds internal resources\n"));
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("Run \"%s -h\" with no other arguments for more information on HW counters on this system.\n"),
+               (IS_KERNEL (forKernel) ? "er_kernel" : "collect"));
+      rc = -1;
+      goto hwc_lookup_wrapup;
+    }
+  Tprintf (DBG_LT3, "hwctable: hwc_lookup(): numtokens=%d\n", numtokens);
+
+  /* look up individual counters */
+  {
+    int fail = 0;
+    for (ii = 0; ii < numtokens && numctrs < maxctrs; ii += 2)
+      {
+       const char *counter;
+       const char *value;
+       Hwcentry *pret_ctr = entries[numctrs];
+
+       /* assign the tokens to ctrnames, timeoutValues. */
+       counter = tokenptr[ii];
+       if (ii + 1 < numtokens)
+         value = tokenptr[ii + 1];
+       else
+         value = 0;
+       if (process_ctr_def (forKernel, global_min_time_nsec, counter, value, pret_ctr,
+                            UWbuf + strlen (UWbuf),
+                            sizeof (UWbuf) - strlen (UWbuf),
+                            UEbuf + strlen (UEbuf),
+                            sizeof (UEbuf) - strlen (UEbuf)))
+         {
+           /* could choose to set fail=1 and continue here,
+              but errmsgs would be aggregated (messy) */
+           rc = -1;
+           goto hwc_lookup_wrapup;
+         }
+       numctrs++;
+      }
+    if (fail)
+      {
+       rc = -1;
+       goto hwc_lookup_wrapup;
+      }
+  }
+
+  if (!numctrs)
+    {
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("No HW counters were specified.\n"));
+      rc = -1;
+      goto hwc_lookup_wrapup;
+    }
+  if (numctrs > cpcx_max_concurrent[forKernel])
+    {
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("The HW counter configuration could not be loaded: More than %d counters were specified\n"), cpcx_max_concurrent[forKernel]);
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("Run \"%s -h\" with no other arguments for more information on HW counters on this system.\n"),
+               (IS_KERNEL (forKernel) ? "er_kernel" : "collect"));
+      rc = -1;
+      goto hwc_lookup_wrapup;
+    }
+
+hwc_lookup_wrapup:
+  free (instr_copy);
+  if (wmsg && strlen (UWbuf))
+    *wmsg = strdup (UWbuf);
+  if (emsg && strlen (UEbuf))
+    *emsg = strdup (UEbuf);
+  if (rc == 0)
+    rc = numctrs;
+  return rc;
+}
+
+extern char *
+hwc_validate_ctrs (int forKernel, Hwcentry *entries[], unsigned numctrs)
+{
+  char UEbuf[1024 * 5];
+  UEbuf[0] = 0;
+
+  /* search for obvious duplicates*/
+  unsigned ii;
+  for (ii = 0; ii < numctrs; ii++)
+    {
+      regno_t reg_a = entries[ii]->reg_num;
+      if (reg_a != REGNO_ANY)
+       {
+         unsigned jj;
+         for (jj = ii + 1; jj < numctrs; jj++)
+           {
+             int reg_b = entries[jj]->reg_num;
+             if (reg_a == reg_b)
+               {
+                 snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                           GTXT ("Only one HW counter is allowed per register.  The following counters use register %d: \n"),
+                           reg_a);
+                 for (jj = 0; jj < numctrs; jj++)
+                   {
+                     char buf[256];
+                     int reg_b = entries[jj]->reg_num;
+                     if (reg_a == reg_b)
+                       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                                 GTXT ("  %d. %s\n"), jj + 1,
+                                 hwc_hwcentry_specd_string (buf, sizeof (buf),
+                                                            entries[jj]));
+                   }
+                 return strdup (UEbuf);
+               }
+           }
+       }
+    }
+
+  /* test counters */
+  hwcfuncs_errmsg_get (NULL, 0, 1); /* enable errmsg capture */
+  int hwc_rc = hwcfuncs_assign_regnos (entries, numctrs);
+  if (!hwc_rc)
+    hwc_rc = test_hwcs ((const Hwcentry**) entries, numctrs);
+  if (hwc_rc)
+    {
+      if (cpcx_cpuver == CPC_PENTIUM_4_HT || cpcx_cpuver == CPC_PENTIUM_4)
+       {
+         snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                   GTXT ("HW counter profiling is disabled unless only one logical CPU per HyperThreaded processor is online (see psradm)\n"));
+         return strdup (UEbuf);
+       }
+      char buf[1024];
+      *buf = 0;
+      char * pch = hwcfuncs_errmsg_get (buf, sizeof (buf), 0); /* get first err msg, disable capture */
+      if (*pch)
+       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                 GTXT ("The HW counter configuration could not be loaded: %s%s"),
+                 pch, pch[strlen (pch) - 1] == '\n' ? "" : "\n");
+      else
+       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                 GTXT ("The HW counter configuration could not be loaded\n"));
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("Run \"%s -h\" with no other arguments for more information on HW counters on this system.\n"),
+               (IS_KERNEL (forKernel) ? "er_kernel" : "collect"));
+      return strdup (UEbuf);
+    }
+  return NULL;
+}
+
+extern Hwcentry *
+hwc_post_lookup (Hwcentry * pret_ctr, char *counter, char * int_name, int cpuver)
+{
+  const Hwcentry *pfound;
+  regno_t regno;
+  char *nameOnly = NULL;
+  char *attrs = NULL;
+
+  /* fields in pret_ctr (name and int_name) should already be free */
+  hwcfuncs_parse_ctr (counter, NULL, &nameOnly, &attrs, NULL, &regno);
+
+  /* look for it in the canonical list */
+  pfound = static_table_find (stdlist_get_table (cpuver),
+                             nameOnly, int_name, 0, REGNO_ANY);
+  if (!pfound)  /* try the generic list */
+    pfound = static_table_find (papi_generic_list,
+                               nameOnly, int_name, 0, REGNO_ANY);
+  if (pfound)
+    {
+      /* in standard list */
+      *pret_ctr = *pfound; /* shallow copy */
+      if (pret_ctr->int_name)
+       {
+         // aliased counter
+         pret_ctr->int_name = strdup (pret_ctr->int_name);
+         if (pret_ctr->short_desc == NULL)
+           {
+             // look for short_desc of corresponding raw counter
+             const Hwcentry *praw = static_table_find (stdlist_get_table (cpuver),
+                                                       pret_ctr->int_name, NULL, 0, REGNO_ANY);
+             if (praw && praw->short_desc)
+               pret_ctr->short_desc = strdup (praw->short_desc);
+           }
+       }
+      else
+       pret_ctr->int_name = strdup (counter);
+      if (pret_ctr->reg_num == REGNO_ANY)
+       pret_ctr->reg_num = regno;  /* table's regno is a wildcard */
+    }
+  else
+    {
+      /* not a standard counter */
+      *pret_ctr = empty_ctr;
+      pret_ctr->int_name = strdup (counter);
+      pret_ctr->reg_num = regno;
+    }
+
+  /* update the name */
+  if (attrs)
+    {
+      pret_ctr->name = canonical_name (counter);
+      if (pret_ctr->metric)
+       {
+         // metric text is supplied from a table. (User supplied HWC alias)
+         // Append user-supplied attributes to metric name:
+         size_t len = strlen (pret_ctr->metric) + strlen (attrs) + 4;
+         char *pch = calloc (len, 1);
+         if (pch)
+           snprintf (pch, len, "%s (%s)", pret_ctr->metric, attrs);
+         pret_ctr->metric = pch; // leaks
+       }
+    }
+  else
+    pret_ctr->name = strdup (nameOnly);
+
+  if (pfound)
+    hwcentry_print (DBG_LT2, "hwctable: hwc_post_lookup: found: ", pret_ctr);
+  else
+    hwcentry_print (DBG_LT2, "hwctable: hwc_post_lookup: default: ", pret_ctr);
+  free (attrs);
+  free (nameOnly);
+  return pret_ctr;
+}
+
+static const char *
+hwc_on_lo_hi (const Hwcentry *pctr)
+{
+  char* rate;
+  {
+    switch (pctr->min_time)
+      {
+      case (HWCTIME_LO):
+       rate = NTXT ("lo");
+       break;
+      case (HWCTIME_ON):
+       rate = NTXT ("on");
+       break;
+      case (HWCTIME_HI):
+       rate = NTXT ("hi");
+       break;
+      case (0):
+       rate = NULL; // null => use interval count
+       break;
+      default:
+      case (HWCTIME_TBD):
+       rate = NTXT ("on");
+       break;
+      }
+  }
+  return rate; //strdup( rate );
+}
+
+extern char *
+hwc_rate_string (const Hwcentry *pctr, int force_numeric)
+{
+  const char * rateString = hwc_on_lo_hi (pctr);
+  char buf[128];
+  if (!rateString || force_numeric)
+    {
+      snprintf (buf, sizeof (buf), NTXT ("%d"), pctr->val);
+      rateString = buf;
+    }
+  return strdup (rateString);
+}
+
+static char metricbuf[2048];
+
+extern char *
+hwc_i18n_metric (const Hwcentry *pctr)
+{
+  if (pctr->metric != NULL)
+    snprintf (metricbuf, sizeof (metricbuf), NTXT ("%s"), PTXT (pctr->metric));
+  else if (pctr->name != NULL)
+    snprintf (metricbuf, sizeof (metricbuf), GTXT ("%s Events"), pctr->name);
+  else if (pctr->int_name != NULL)
+    snprintf (metricbuf, sizeof (metricbuf), GTXT ("%s Events"), pctr->int_name);
+  else
+    snprintf (metricbuf, sizeof (metricbuf), GTXT ("Undefined Events"));
+  return metricbuf;
+}
+
+/* return cpu version, should only be called when about to generate an experiment,
+   not when reading back an experiment */
+#if 0 /* called by ... */
+. / perfan / collect / src / collect.cc : start : 245 : cpuver = hwc_get_cpc_cpuver ();
+. / ccr_components / Collector_Interface / collctrl.cc : constructor : 202 : cpcx_cpuver = hwc_get_cpc_cpuver ();
+. / perfan / dbe / src / Dbe.cc : 3041 : JApplication::cpuver = hwc_get_cpc_cpuver ();
+. / perfan / dbe / src / Dbe.cc : 3164 : JApplication::cpuver = hwc_get_cpc_cpuver ();
+
+note:
+cpc_getcpuver () : only papi, ostest, this and hwprofile.c call it
+#endif
+int
+hwc_get_cpc_cpuver ()
+{
+  setup_cpcx ();
+  return cpcx_cpuver;
+}
+
+extern char*
+hwc_get_cpuname (char *buf, size_t buflen)
+{
+  setup_cpcx ();
+  if (!buf || !buflen)
+    return buf;
+  buf[0] = 0;
+  if (cpcx_cciname)
+    {
+      strncpy (buf, cpcx_cciname, buflen - 1);
+      buf[buflen - 1] = 0;
+    }
+  return buf;
+}
+
+extern char*
+hwc_get_docref (char *buf, size_t buflen)
+{
+  setup_cpcx ();
+  if (!buf || !buflen)
+    return buf;
+  buf[0] = 0;
+  if (cpcx_docref)
+    {
+      strncpy (buf, cpcx_docref, buflen - 1);
+      buf[buflen - 1] = 0;
+    }
+  return buf;
+}
+
+//TBR:
+
+extern char*
+hwc_get_default_cntrs ()
+{
+  setup_cpcx ();
+  if (cpcx_default_hwcs[0] != NULL)
+    return strdup (cpcx_default_hwcs[0]); // TBR deprecate this
+  return NULL;
+}
+
+extern char*
+hwc_get_default_cntrs2 (int forKernel, int style)
+{
+  setup_cpcx ();
+  if (!VALID_FOR_KERNEL (forKernel))
+    return NULL;
+  char *cpcx_default = cpcx_default_hwcs[forKernel];
+  if (cpcx_default == NULL || cpcx_npics == 0)
+    return NULL;
+  if (style == 1)
+    return strdup (cpcx_default);
+
+  // style == 2
+  // we will replace "," delimiters with " -h " (an extra 3 chars per HWC)
+  char *s = (char *) malloc (strlen (cpcx_default) + 3 * cpcx_npics);
+  if (s == NULL) return s;
+  char *p = s;
+  char *q = cpcx_default;
+  int i;
+  for (i = 0; i < cpcx_npics; i++)
+    {
+      int qlen = strlen (q);
+      if (qlen == 0)
+       {
+         p[0] = '\0';
+         break;
+       }
+      // add " -h " if not the first HWC
+      if (i != 0)
+       {
+         p[0] = ' ';
+         p[1] = '-';
+         p[2] = 'h';
+         p[3] = ' ';
+         p += 4;
+       }
+
+      // find second comma
+      char *r = strchr (q, ',');
+      if (r)
+       r = strchr (r + 1, ',');
+
+      // we didn't find one, so the rest of the string is the last HWC
+      if (r == NULL)
+       {
+         // EUGENE could check i==cpcx_npicx-1, but what if it isn't???
+         strcpy (p, q);
+         if (p[qlen - 1] == ',')
+           qlen--;
+         p[qlen] = '\0';
+         break;
+       }
+
+      // copy the HWC, trim trailing comma, add null char
+      qlen = r - q - 1;
+      strcpy (p, q);
+      if (p[qlen - 1] == ',')
+       qlen--;
+      p += qlen;
+      p[0] = '\0';
+      q = r + 1;
+    }
+  return s;
+}
+
+extern char*
+hwc_get_orig_default_cntrs (int forKernel)
+{
+  setup_cpcx ();
+  if (!VALID_FOR_KERNEL (forKernel))
+    return NULL;
+  if (cpcx_orig_default_hwcs[forKernel] != NULL)
+    return strdup (cpcx_orig_default_hwcs[forKernel]);
+  return NULL;
+}
+
+extern const char *
+hwc_memop_string (ABST_type memop)
+{
+  const char * s;
+  switch (memop)
+    {
+    case ABST_NONE:
+      s = "";
+      break;
+    case ABST_LOAD:
+      s = GTXT ("load ");
+      break;
+    case ABST_STORE:
+      s = GTXT ("store ");
+      break;
+    case ABST_LDST:
+    case ABST_US_DTLBM:
+    case ABST_LDST_SPARC64:
+      s = GTXT ("load-store ");
+      break;
+    case ABST_EXACT_PEBS_PLUS1:
+    case ABST_EXACT:
+      s = GTXT ("memoryspace ");
+      break;
+    case ABST_COUNT:
+      s = GTXT ("count ");
+      break;
+    case ABST_NOPC:
+      s = GTXT ("not-program-related ");
+      break;
+    default:
+      s = ""; // was "ABST_UNK", but that's meaningless to users
+      break;
+    }
+  return s;
+}
+
+static const char *
+timecvt_string (int timecvt)
+{
+  if (timecvt > 0)
+    return GTXT ("CPU-cycles");
+  if (timecvt < 0)
+    return GTXT ("ref-cycles");
+  return GTXT ("events");
+}
+
+int show_regs = 0;  // The register setting is available on Solaris only
+
+/*
+ * print the specified strings in aligned columns
+ */
+static void
+format_columns (char *buf, int bufsiz, char *s1, char *s2, const char *s3,
+               const char *s4, char *s5, const char *s6)
+{
+  // NULL strings are blanks
+  char *blank = NTXT ("");
+  if (s2 == NULL)
+    s2 = blank;
+  if (s3 == NULL)
+    s3 = blank;
+  if (s6 == NULL)
+    s6 = blank;
+
+  // get the lengths and target widths
+  // (s6 can be as wide as it likes)
+  int l1 = strlen (s1), n1 = 10, l2 = strlen (s2), n2 = 13;
+  int l3 = strlen (s3), n3 = 20, l4 = strlen (s4), n4 = 10, n5;
+  char divide = ' ';
+
+  // adjust widths, stealing from one column to help a neighbor
+  // There's a ragged boundary between s2 and s3.
+  // So push this boundary to the right.
+  n2 += n3 - l3;
+  n3 -= n3 - l3;
+
+  // If s3 is empty, push the boundary over to s4.
+  if (l3 == 0)
+    {
+      n2 += n4 - l4;
+      n4 -= n4 - l4;
+    }
+
+  // If there's enough room to fit s1 and s2, do so.
+  if (n1 + n2 >= l1 + l2)
+    {
+      if (n1 < l1)
+       {
+         n2 -= l1 - n1;
+         n1 += l1 - n1;
+       }
+      if (n2 < l2)
+       {
+         n1 -= l2 - n2;
+         n2 += l2 - n2;
+       }
+    }
+  else
+    {
+      // not enough room, so we need to divide the line
+      n3 += 4 // 4-blank margin
+             + n1 // 1st column
+             + 1 // space between 1st and 2nd columns
+             + n2 // 2nd column
+             + 1; // space between 2nd and 3th columns
+      divide = '\n';
+
+      // make 1st column large enough
+      if (n1 < l1)
+       n1 = l1;
+
+      // width of 2nd column no longer matters since we divided the line
+      n2 = 0;
+    }
+
+  if (show_regs)
+    {
+      // fifth column should be wide enough for regnolist
+      //     see function get_regnolist()
+      if (cpcx_npics < 10)
+       n5 = cpcx_npics; // one char per regno
+      else
+       n5 = 16 + 3 * (cpcx_npics - 9); // spaces between regnos and some regnos are 2-char wide
+      // ... and be wide enough for header "regs"
+      if (n5 < 4)
+       n5 = 4;
+
+      // print to buffer
+      // (don't need a space before s4 since historical precedent to have a trailing space in s3)
+      snprintf (buf, bufsiz, "%-*s %-*s%c%*s%*s %-*s %s",
+               n1, s1, n2, s2, divide, n3, s3, n4, s4, n5, s5, s6);
+    }
+  else
+    snprintf (buf, bufsiz, "%-*s %-*s%c%*s%*s %s",
+             n1, s1, n2, s2, divide, n3, s3, n4, s4, s6);
+  for (int i = strlen (buf); i > 0; i--)
+    if (buf[i] == ' ' || buf[i] == '\t')
+      buf[i] = 0;
+    else
+      break;
+}
+
+/* routine to return HW counter string formatted and i18n'd */
+static char *
+hwc_hwcentry_string_internal (char *buf, size_t buflen, const Hwcentry *ctr,
+                             int show_short_desc)
+{
+  char stderrbuf[1024];
+  char regnolist[256];
+  if (!buf || !buflen)
+    return buf;
+  buf[0] = 0;
+  if (ctr == NULL)
+    {
+      snprintf (stderrbuf, sizeof (stderrbuf), GTXT ("HW counter not available"));
+      goto hwc_hwcentry_string_done;
+    }
+  char *desc = NULL;
+  if (show_short_desc)
+    desc = ctr->short_desc;
+  if (desc == NULL)
+    desc = ctr->metric ? hwc_i18n_metric (ctr) : NULL;
+  format_columns (stderrbuf, sizeof (stderrbuf), ctr->name, ctr->int_name,
+                 hwc_memop_string (ctr->memop), timecvt_string (ctr->timecvt),
+                 get_regnolist (regnolist, sizeof (regnolist), ctr->reg_list, 2),
+                 desc);
+
+hwc_hwcentry_string_done:
+  strncpy (buf, stderrbuf, buflen - 1);
+  buf[buflen - 1] = 0;
+  return buf;
+}
+
+/* routine to return HW counter string formatted and i18n'd */
+extern char *
+hwc_hwcentry_string (char *buf, size_t buflen, const Hwcentry *ctr)
+{
+  return hwc_hwcentry_string_internal (buf, buflen, ctr, 0);
+}
+
+/* routine to return HW counter string formatted and i18n'd */
+extern char *
+hwc_hwcentry_specd_string (char *buf, size_t buflen, const Hwcentry *ctr)
+{
+  char stderrbuf[1024];
+  const char *memop, *timecvt;
+  char descstr[1024];
+  if (!buf || !buflen)
+    return buf;
+  buf[0] = 0;
+  if (ctr == NULL)
+    {
+      snprintf (stderrbuf, sizeof (stderrbuf), GTXT ("HW counter not available"));
+      goto hwc_hwcentry_specd_string_done;
+    }
+  timecvt = timecvt_string (ctr->timecvt);
+  if (ctr->memop)
+    memop = hwc_memop_string (ctr->memop);
+  else
+    memop = "";
+  if (ctr->metric != NULL)  /* a standard counter for a specific register */
+    snprintf (descstr, sizeof (descstr), GTXT (" (`%s'; %s%s)"),
+             hwc_i18n_metric (ctr), memop, timecvt);
+  else  /* raw counter */
+    snprintf (descstr, sizeof (descstr), GTXT (" (%s%s)"), memop, timecvt);
+
+  char *rateString = hwc_rate_string (ctr, 1);
+  snprintf (stderrbuf, sizeof (stderrbuf), NTXT ("%s,%s%s"), ctr->name,
+           rateString ? rateString : "", descstr);
+  free (rateString);
+
+hwc_hwcentry_specd_string_done:
+  strncpy (buf, stderrbuf, buflen - 1);
+  buf[buflen - 1] = 0;
+  return buf;
+}
+
+unsigned
+hwc_get_max_regs ()
+{
+  setup_cpcx ();
+  return cpcx_npics;
+}
+
+unsigned
+hwc_get_max_concurrent (int forKernel)
+{
+  setup_cpcx ();
+  if (!VALID_FOR_KERNEL (forKernel))
+    return 0;
+  return cpcx_max_concurrent[forKernel];
+}
+
+char**
+hwc_get_attrs (int forKernel)
+{
+  setup_cpcx ();
+  if (!VALID_FOR_KERNEL (forKernel))
+    return NULL;
+  return cpcx_attrs[forKernel];
+}
+
+Hwcentry **
+hwc_get_std_ctrs (int forKernel)
+{
+  setup_cpcx ();
+  if (!VALID_FOR_KERNEL (forKernel))
+    return NULL;
+  return cpcx_std[forKernel];
+}
+
+Hwcentry **
+hwc_get_raw_ctrs (int forKernel)
+{
+  setup_cpcx ();
+  if (!VALID_FOR_KERNEL (forKernel))
+    return NULL;
+  return cpcx_raw[forKernel];
+}
+
+/* Call an action function for each attribute supported */
+unsigned
+hwc_scan_attrs (void (*action)(const char *attr, const char *desc))
+{
+  setup_cpcx ();
+  int cnt = 0;
+  for (int ii = 0; cpcx_attrs[0] && cpcx_attrs[0][ii]; ii++, cnt++)
+    {
+      if (action)
+       action (cpcx_attrs[0][ii], NULL);
+    }
+  if (!cnt && action)
+    action (NULL, NULL);
+  return cnt;
+}
+
+unsigned
+hwc_scan_std_ctrs (void (*action)(const Hwcentry *))
+{
+  setup_cpcx ();
+  Tprintf (DBG_LT1, "hwctable: hwc_scan_standard_ctrs()...\n");
+  int cnt = 0;
+  for (int ii = 0; cpcx_std[0] && cpcx_std[0][ii]; ii++, cnt++)
+    if (action)
+      action (cpcx_std[0][ii]);
+  if (!cnt && action)
+    action (NULL);
+  return cnt;
+}
+
+/* Call an action function for each counter supported */
+/* action is called with NULL when all counters have been seen */
+unsigned
+hwc_scan_raw_ctrs (void (*action)(const Hwcentry *))
+{
+  setup_cpcx ();
+  Tprintf (DBG_LT1, "hwctable: hwc_scan_raw_ctrs()...\n");
+  int cnt = 0;
+  for (int ii = 0; cpcx_raw[0] && cpcx_raw[0][ii]; ii++, cnt++)
+    if (action)
+      action (cpcx_raw[0][ii]);
+  if (!cnt && action)
+    action (NULL);
+  return cnt;
+}
+
+static void
+hwc_usage_raw_overview_sparc (FILE *f_usage, int cpuver)
+{
+  /* All these cpuver's use cputabs[]==sparc_t5_m6 anyhow. */
+  if ((cpuver == CPC_SPARC_M5) || (cpuver == CPC_SPARC_M6)
+      || (cpuver == CPC_SPARC_T5) || (cpuver == CPC_SPARC_T6))
+    cpuver = CPC_SPARC_M4; // M4 was renamed to M5
+
+  /* While there are small differences between
+   *     cputabs[]== sparc_t4
+   *     cputabs[]== sparc_t5_m6
+   * they are in HWCs we don't discuss in the overview anyhow.
+   * So just lump them in with T4.
+   */
+  if (cpuver == CPC_SPARC_M4)
+    cpuver = CPC_SPARC_T4;
+
+  /* Check for the cases we support. */
+  if (cpuver != CPC_SPARC_T4 && cpuver != CPC_SPARC_M7 && cpuver != CPC_SPARC_M8)
+    return;
+  fprintf (f_usage, GTXT ("    While the above aliases represent the most useful hardware counters\n"
+                         "    for this processor, a full list of raw (unaliased) counter names appears\n"
+                         "    below.  First is an overview of some of these names.\n\n"));
+  fprintf (f_usage, GTXT ("        == Cycles.\n"
+                         "        Count active cycles with\n"
+                         "            Cycles_user\n"
+                         "        Set attributes to choose user, system, and/or hyperprivileged cycles.\n\n"));
+  fprintf (f_usage, GTXT ("        == Instructions.\n"
+                         "        Count instructions when they are committed with:\n"));
+  fprintf (f_usage, NTXT ("            Instr_all\n"));
+  if (cpuver != CPC_SPARC_M8)
+    fprintf (f_usage, GTXT ("        It is the total of these counters:\n"));
+  else
+    fprintf (f_usage, GTXT ("        Some subsets of instructions can be counted separately:\n"));
+  fprintf (f_usage, NTXT ("            Branches               %s\n"), GTXT ("branches"));
+  fprintf (f_usage, NTXT ("            Instr_FGU_crypto       %s\n"), GTXT ("Floating Point and Graphics Unit"));
+  fprintf (f_usage, NTXT ("            Instr_ld               %s\n"), GTXT ("loads"));
+  fprintf (f_usage, NTXT ("            Instr_st               %s\n"), GTXT ("stores"));
+  fprintf (f_usage, NTXT ("            %-19s    %s\n"),
+          cpuver == CPC_SPARC_M7 ? NTXT ("Instr_SPR_ring_ops")
+          : NTXT ("SPR_ring_ops"),
+          GTXT ("internal use of SPR ring"));
+  fprintf (f_usage, NTXT ("            Instr_other            %s\n"), GTXT ("basic arithmetic and logical instructions"));
+  if (cpuver != CPC_SPARC_M8)
+    fprintf (f_usage, GTXT ("        Some subsets of these instructions can be counted separately:\n"));
+  fprintf (f_usage, NTXT ("            Br_taken               %s\n"), GTXT ("Branches that are taken"));
+  fprintf (f_usage, NTXT ("            %-19s    %s\n"),
+          cpuver == CPC_SPARC_M7 ? NTXT ("Instr_block_ld_st")
+          : NTXT ("Block_ld_st"),
+          GTXT ("block load/store"));
+  fprintf (f_usage, NTXT ("            %-19s    %s\n"),
+          cpuver == CPC_SPARC_M7 ? NTXT ("Instr_atomic")
+          : NTXT ("Atomics"),
+          GTXT ("atomic instructions"));
+  fprintf (f_usage, NTXT ("            %-19s    %s\n"),
+          cpuver == CPC_SPARC_M7 ? NTXT ("Instr_SW_prefetch")
+          : NTXT ("SW_prefetch"),
+          GTXT ("prefetches"));
+  fprintf (f_usage, NTXT ("            %-19s    %s\n"),
+          cpuver == CPC_SPARC_M7 ? NTXT ("Instr_SW_count")
+          : NTXT ("Sw_count_intr"),
+          GTXT ("SW Count instructions (counts special no-op assembler instructions)"));
+  fprintf (f_usage, NTXT ("\n"));
+
+#ifdef TMPLEN
+  compilation error : we're trying to use a macro that's already defined
+#endif
+#define TMPLEN 32
+         char s0[TMPLEN], s1[TMPLEN], s2[TMPLEN], s3[TMPLEN];
+  if (cpuver == CPC_SPARC_M7)
+    {
+      snprintf (s0, TMPLEN, "Commit_0_cyc");
+      snprintf (s1, TMPLEN, "Commit_1_cyc");
+      snprintf (s2, TMPLEN, "Commit_2_cyc");
+      snprintf (s3, TMPLEN, "Commit_1_or_2_cyc");
+    }
+  else
+    {
+      snprintf (s0, TMPLEN, "Commit_0");
+      snprintf (s1, TMPLEN, "Commit_1");
+      snprintf (s2, TMPLEN, "Commit_2");
+      snprintf (s3, TMPLEN, "Commit_1_or_2");
+    }
+#undef TMPLEN
+  fprintf (f_usage, GTXT ("        == Commit.\n"
+                         "        Instructions may be launched speculatively, executed out of order, etc.\n"));
+  if (cpuver != CPC_SPARC_M8)
+    {
+      fprintf (f_usage, GTXT ("        We can count the number of cycles during which 0, 1, or 2 instructions are\n"
+                             "        actually completed and their results committed:\n"));
+      fprintf (f_usage, GTXT ("            %s\n"
+                             "            %s\n"
+                             "            %s\n"
+                             "            %s\n"
+                             "        %s is a useful way of identifying parts of your application with\n"
+                             "        high-latency instructions.\n\n"),
+              s0, s1, s2, s3, s0);
+    }
+  else
+    {
+      fprintf (f_usage, GTXT ("        We can count the number of cycles during which no instructions were\n"
+                             "        able to commit results using:\n"));
+      fprintf (f_usage, GTXT ("            %s\n"
+                             "        %s is a useful way of identifying parts of your application with\n"
+                             "        high-latency instructions.\n\n"),
+              s0, s0);
+    }
+
+  fprintf (f_usage, GTXT ("        == Cache/memory hierarchy.\n"));
+  if (cpuver == CPC_SPARC_M7)
+    {
+      fprintf (f_usage, GTXT ("        In the cache hierarchy:\n"
+                             "         * Each socket has memory and multiple SPARC core clusters (scc).\n"
+                             "         * Each scc has an L3 cache and multiple L2 and L1 caches.\n"));
+      fprintf (f_usage, GTXT ("        Loads can be counted by where they hit on socket:\n"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_hit"), GTXT ("hit own L1 data cache"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_L2_hit"), GTXT ("hit own L2"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_L3_hit"), GTXT ("hit own L3"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_nbr_L2_hit"), GTXT ("hit neighbor L2  (same scc)"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_nbr_scc_hit"), GTXT ("hit neighbor scc (same socket)"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_nbr_scc_miss"), GTXT ("miss all caches  (same socket)"));
+      fprintf (f_usage, GTXT ("        These loads can also be grouped:\n"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss"), GTXT ("all - DC_hit"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_L2_miss"), GTXT ("all - DC_hit - DC_miss_L2_hit"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_L3_miss"), GTXT ("DC_miss_nbr_scc_hit + DC_miss_nbr_scc_miss"));
+      fprintf (f_usage, GTXT ("        Loads that miss all caches on this socket can be counted:\n"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_remote_scc_hit"), GTXT ("hit cache on different socket"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_local_mem_hit"), GTXT ("hit local memory (same socket)"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_remote_mem_hit"), GTXT ("hit remote memory (off socket)"));
+      fprintf (f_usage, GTXT ("        These events are for speculative loads, launched in anticipation\n"
+                             "        of helping performance but whose results might not be committed.\n"));
+#if 0 // was: #if defined(linux).  See 22236226 - sparc-Linux: Support basic Memoryspace and Dataspace profiling (capture VADDR)
+      /* 21869427 should not look like memoryspace profiling is supported on Linux */
+      /* 21869424 desire memoryspace profiling on Linux */
+      fprintf (f_usage, GTXT ("        To count only data-cache misses that commit, use:\n"));
+      fprintf (f_usage, NTXT ("            DC_miss_commit\n"));
+#else
+      fprintf (f_usage, GTXT ("        To count only data-cache misses that commit, or for memoryspace profiling,\n"
+                             "        use the 'memoryspace' counter:\n"));
+      fprintf (f_usage, NTXT ("            DC_miss_commit\n"));
+#endif
+      fprintf (f_usage, NTXT ("\n"));
+    }
+  else if (cpuver == CPC_SPARC_M8)
+    {
+      fprintf (f_usage, GTXT ("        In the cache hierarchy:\n"
+                             "         * Each processor has 4 memory controllers and 2 quad core clusters (QCC).\n"
+                             "         * Each QCC contains 4 cache processor clusters (CPC).\n"
+                             "         * Each CPC contains 4 cores.\n"
+                             "         * Each core supports 8 hardware threads.\n"
+                             "         * The L3 consists of 2 partitions with 1 QCC per partition.\n"
+                             ));
+      fprintf (f_usage, GTXT ("        Loads can be counted by where they hit on socket:\n"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_L2_hit"), GTXT ("hit own L2"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_L3_hit"), GTXT ("hit own L3"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_L3_dirty_copyback"), GTXT ("hit own L3 but require copyback from L2D"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_nbr_L3_hit"), GTXT ("hit neighbor L3 (same socket)"));
+      fprintf (f_usage, GTXT ("        Loads that miss all caches on this socket can be counted:\n"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_remote_L3_hit"), GTXT ("hit cache on different socket"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_local_mem_hit"), GTXT ("hit local memory (same socket)"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("DC_miss_remote_mem_hit"), GTXT ("hit remote memory (off socket)"));
+      fprintf (f_usage, GTXT ("        These events are for speculative loads, launched in anticipation\n"
+                             "        of helping performance but whose results might not be committed.\n"));
+#if 0 // was: #if defined(linux).  See 22236226 - sparc-Linux: Support basic Memoryspace and Dataspace profiling (capture VADDR)
+      /* 21869427 should not look like memoryspace profiling is supported on Linux */
+      /* 21869424 desire memoryspace profiling on Linux */
+      fprintf (f_usage, GTXT ("        To count only data-cache misses that commit, use:\n"));
+      fprintf (f_usage, NTXT ("            DC_miss_commit\n"));
+#else
+      fprintf (f_usage, GTXT ("        To count only data-cache misses that commit, or for memoryspace profiling,\n"
+                             "        use the 'memoryspace' counter:\n"));
+      fprintf (f_usage, NTXT ("            DC_miss_commit\n"));
+#endif
+      fprintf (f_usage, NTXT ("\n"));
+    }
+  else
+    {
+      fprintf (f_usage, GTXT ("        Total data-cache misses can be counted with:\n"));
+      fprintf (f_usage, NTXT ("            DC_miss                DC_miss_nospec\n"));
+      fprintf (f_usage, GTXT ("        They are the totals of misses that hit in L2/L3 cache, local memory, or\n"
+                             "        remote memory:\n"));
+      fprintf (f_usage, NTXT ("            DC_miss_L2_L3_hit      DC_miss_L2_L3_hit_nospec\n"));
+      fprintf (f_usage, NTXT ("            DC_miss_local_hit      DC_miss_local_hit_nospec\n"));
+      fprintf (f_usage, NTXT ("            DC_miss_remote_L3_hit  DC_miss_remote_L3_hit_nospec\n"));
+      fprintf (f_usage, GTXT ("        The events in the left column include speculative operations.  Use the\n"
+                             "        right-hand _nospec events to count only data accesses that commit\n"
+                             "        or for memoryspace profiling.\n\n"));
+    }
+
+  fprintf (f_usage, GTXT ("        == TLB misses.\n"
+                         "        The Translation Lookaside Buffer (TLB) is a cache of virtual-to-physical\n"
+                         "        page translations."));
+  fprintf (f_usage, GTXT ("  If a virtual address (VA) is not represented in the\n"
+                         "        TLB, an expensive hardware table walk (HWTW) must be conducted."));
+  fprintf (f_usage, GTXT ("  If the\n"
+                         "        page is still not found, a trap results.  There is a data TLB (DTLB) and\n"
+                         "        an instruction TLB (ITLB).\n\n"));
+  fprintf (f_usage, GTXT ("        TLB misses can be counted by:\n"));
+  fprintf (f_usage, NTXT ("            %s\n"),
+          cpuver == CPC_SPARC_M7 ?
+          NTXT ("DTLB_HWTW_search            ITLB_HWTW_search") :
+          cpuver == CPC_SPARC_M8 ?
+          NTXT ("DTLB_HWTW                   ITLB_HWTW") :
+          NTXT ("DTLB_miss_asynch            ITLB_miss_asynch"));
+  fprintf (f_usage, GTXT ("        or broken down by page size:\n"));
+  fprintf (f_usage, NTXT ("            %s"),
+          cpuver == CPC_SPARC_M7 ?
+          NTXT ("DTLB_HWTW_hit_8K            ITLB_HWTW_hit_8K\n"
+                "            DTLB_HWTW_hit_64K           ITLB_HWTW_hit_64K\n"
+                "            DTLB_HWTW_hit_4M            ITLB_HWTW_hit_4M\n") :
+          NTXT ("DTLB_fill_8KB               ITLB_fill_8KB\n"
+                "            DTLB_fill_64KB              ITLB_fill_64KB\n"
+                "            DTLB_fill_4MB               ITLB_fill_4MB\n"));
+  fprintf (f_usage, NTXT ("            %s\n\n"),
+          cpuver == CPC_SPARC_M7 ?
+          NTXT ("DTLB_HWTW_hit_256M          ITLB_HWTW_hit_256M\n"
+                "            DTLB_HWTW_hit_2G_16G        ITLB_HWTW_hit_2G_16G\n"
+                "            DTLB_HWTW_miss_trap         ITLB_HWTW_miss_trap") :
+          cpuver == CPC_SPARC_M8 ?
+          NTXT ("DTLB_HWTW_hit_256M          ITLB_HWTW_hit_256M\n"
+                "            DTLB_HWTW_hit_16G           ITLB_HWTW_hit_16G\n"
+                "            DTLB_HWTW_hit_1T            ITLB_HWTW_hit_1T") :
+          NTXT ("DTLB_fill_256MB             ITLB_fill_256MB\n"
+                "            DTLB_fill_2GB               ITLB_fill_2GB\n"
+                "            DTLB_fill_trap              ITLB_fill_trap"));
+  if (cpuver == CPC_SPARC_M8)
+    {
+      fprintf (f_usage, GTXT ("        TLB traps, which can require hundreds of cycles, can be counted with:\n"));
+      fprintf (f_usage, NTXT ("            %s\n\n"),
+              NTXT ("DTLB_fill_trap              ITLB_fill_trap"));
+    }
+
+  fprintf (f_usage, GTXT ("        == Branch misprediction.\n"
+                         "        Count branch mispredictions with:\n"
+                         "            Br_mispred\n"
+                         "        It is the total of:\n"
+                         "            Br_dir_mispred         direction was mispredicted\n"
+                         "            %s         target    was mispredicted\n"
+                         "\n"), cpuver == CPC_SPARC_M7 ? NTXT ("Br_tgt_mispred") : NTXT ("Br_trg_mispred"));
+
+  fprintf (f_usage, GTXT ("        == RAW hazards.\n"
+                         "        A read-after-write (RAW) delay occurs when we attempt to read a datum\n"
+                         "        before an earlier write has had time to complete:\n"));
+  if (cpuver == CPC_SPARC_M8)
+    {
+      fprintf (f_usage, NTXT ("            RAW_hit\n"));
+      fprintf (f_usage, GTXT ("        RAW_hit events can be broken down into:\n"));
+    }
+  else
+    {
+      fprintf (f_usage, NTXT ("            RAW_hit_st_q~emask=0xf\n"));
+      fprintf (f_usage, GTXT ("        The mask 0xf counts the total of all types such as:\n"));
+    }
+  fprintf (f_usage, NTXT ("            RAW_hit_st_buf         write is still in store buffer\n"
+                         "            RAW_hit_st_q           write is still in store queue\n"
+                         "\n"));
+  if (cpuver == CPC_SPARC_M7)
+    {
+      fprintf (f_usage, GTXT ("        == Flush.\n"
+                             "        One can count the number of times the pipeline must be flushed:\n"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("Flush_L3_miss"), GTXT ("load missed L3 and >1 strand is active on the core"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("Flush_br_mispred"), GTXT ("branch misprediction"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("Flush_arch_exception"), GTXT ("SPARC exceptions and trap entry/return"));
+      fprintf (f_usage, NTXT ("            %-22s %s\n"),
+              NTXT ("Flush_other"), GTXT ("state change to/from halted/paused"));
+      fprintf (f_usage, NTXT ("\n"));
+    }
+}
+
+static void
+hwc_usage_internal (int forKernel, FILE *f_usage, const char *cmd, const char *dataspace_msg, int show_syntax, int show_short_desc)
+{
+  if (!VALID_FOR_KERNEL (forKernel))
+    return;
+  char cpuname[128];
+  hwc_get_cpuname (cpuname, 128);
+  Hwcentry** raw_ctrs = hwc_get_raw_ctrs (forKernel);
+  int has_raw_ctrs = (raw_ctrs && raw_ctrs[0]);
+  Hwcentry** std_ctrs = hwc_get_std_ctrs (forKernel);
+  int has_std_ctrs = (std_ctrs && std_ctrs[0]);
+  unsigned hwc_maxregs = hwc_get_max_concurrent (forKernel);
+  int cpuver = hwc_get_cpc_cpuver ();
+  if (hwc_maxregs != 0)
+    {
+      if (show_syntax)
+       {
+         fprintf (f_usage, GTXT ("\nSpecifying HW counters on `%s' (cpuver=%d):\n\n"), cpuname, cpuver);
+         fprintf (f_usage, GTXT ("    -h {auto|lo|on|hi}\n"));
+         fprintf (f_usage, GTXT ("\tturn on default set of HW counters at the specified rate\n"));
+         if (hwc_maxregs == 1)
+           {
+             fprintf (f_usage, GTXT ("    -h <ctr_def>\n"));
+             fprintf (f_usage, GTXT ("\tspecify HW counter profiling for one HW counter only\n"));
+           }
+         else
+           {
+             fprintf (f_usage, GTXT ("    -h <ctr_def> [-h <ctr_def>]...\n"));
+             fprintf (f_usage, GTXT ("    -h <ctr_def>[,<ctr_def>]...\n"));
+             fprintf (f_usage, GTXT ("\tspecify HW counter profiling for up to %u HW counters\n"), hwc_maxregs);
+           }
+         fprintf (f_usage, NTXT ("\n"));
+       }
+      else
+       {
+         fprintf (f_usage, GTXT ("\nSpecifying HW counters on `%s' (cpuver=%d)\n\n"), cpuname, cpuver);
+         if (hwc_maxregs == 1)
+           fprintf (f_usage, GTXT ("           Hardware counter profiling is supported for only one counter.\n"));
+         else
+           fprintf (f_usage, GTXT ("           Hardware counter profiling is supported for up to %u HW counters.\n"), hwc_maxregs);
+       }
+    }
+  else
+    {
+      if (!IS_KERNEL (forKernel))
+       { // EUGENE I don't see why we don't also use this for er_kernel
+         char buf[1024];
+         *buf = 0;
+         char *pch = hwcfuncs_errmsg_get (buf, sizeof (buf), 0);
+         if (*pch)
+           fprintf (f_usage, GTXT ("HW counter profiling is not supported on this system: %s%s"),
+                    pch, pch[strlen (pch) - 1] == '\n' ? "" : "\n");
+         else
+           fprintf (f_usage, GTXT ("HW counter profiling is not supported on this system\n"));
+       }
+      return;
+    }
+
+  /* At this point, we know we have counters */
+  char**hwc_attrs = hwc_get_attrs (forKernel);
+  int has_attrs = (hwc_attrs && hwc_attrs[0]);
+  if (show_syntax)
+    {
+      const char *reg_s = show_regs ? "[/<reg#>]" : "";
+      const char *attr_s = has_attrs ? "[[~<attr>=<val>]...]" : "";
+      fprintf (f_usage, GTXT ("    <ctr_def> == <ctr>%s%s,[<rate>]\n"), attr_s, reg_s);
+      if (dataspace_msg)
+       fprintf (f_usage, NTXT ("%s"), dataspace_msg);
+      fprintf (f_usage, GTXT ("        <ctr>\n"));
+      fprintf (f_usage, GTXT ("           counter name, "));
+    }
+  else
+    fprintf (f_usage, GTXT ("           Counter name "));
+  fprintf (f_usage, GTXT ("must be selected from the available counters\n"
+                         "           listed below.  On most systems, if a counter is not listed\n"
+                         "           below, it may still be specified by its numeric value.\n"));
+  if (cpcx_has_precise[forKernel])
+    {
+      if (!forKernel)
+       fprintf (f_usage, GTXT ("           Counters labeled as 'memoryspace' in the list below will\n"
+                               "           collect memoryspace data by default.\n"));
+    }
+  fprintf (f_usage, GTXT ("\n"));
+  if (has_attrs)
+    {
+      if (show_syntax)
+       {
+         fprintf (f_usage, GTXT ("        ~<attr>=<val>\n"));
+         fprintf (f_usage, GTXT ("           optional attribute where <val> can be in decimal or hex\n"
+                                 "           format, and <attr> can be one of: \n"));
+       }
+      else
+       fprintf (f_usage, GTXT ("           Optional attribute where <val> can be in decimal or hex\n"
+                               "           format, and <attr> can be one of: \n"));
+      for (char **pattr = hwc_attrs; *pattr; pattr++)
+       fprintf (f_usage, NTXT ("             `%s'\n"), *pattr);
+      if (show_syntax)
+       fprintf (f_usage, GTXT ("           Multiple attributes may be specified, and each must be preceded by a ~.\n\n"));
+      else
+       fprintf (f_usage, GTXT ("           Multiple attributes may be specified.\n\n"));
+      if (IS_KERNEL (forKernel))
+       fprintf (f_usage, GTXT ("           Other attributes may be supported by the chip, but are not supported by DTrace and will be ignored by er_kernel.\n\n"));
+    }
+
+  if (show_syntax)
+    {
+      if (show_regs)
+       fprintf (f_usage, GTXT ("        /<reg#>\n"
+                               "           forces use of a specific hardware register.  (Solaris only)\n"
+                               "           If not specified, %s will attempt to place the counter into the first\n"
+                               "           available register and as a result may be unable to place\n"
+                               "           subsequent counters due to register conflicts.\n"
+                               "           The / in front of the register number is required if a register is specified.\n\n"),
+                cmd);
+
+      fprintf (f_usage, GTXT ("        <rate> == {auto|lo|on|hi}\n"));
+      fprintf (f_usage, GTXT ("           `auto'   (default) match the rate used by clock profiling.\n"));
+      fprintf (f_usage, GTXT ("                    If clock profiling is disabled, use `on'.\n"));
+      fprintf (f_usage, GTXT ("           `lo'     per-thread maximum rate of ~10 samples/second\n"));
+      fprintf (f_usage, GTXT ("           `on'     per-thread maximum rate of ~100 samples/second\n"));
+      fprintf (f_usage, GTXT ("           `hi'     per-thread maximum rate of ~1000 samples/second\n\n"));
+      fprintf (f_usage, GTXT ("        <rate> == <interval>\n"));
+      fprintf (f_usage, GTXT ("           event interval; see collect (1) for details\n\n"));
+
+      fprintf (f_usage, GTXT ("        A comma ',' followed immediately by white space may be omitted.\n\n"));
+    }
+
+  /* default counters */
+  fprintf (f_usage, GTXT ("Default set of HW counters:\n\n"));
+  char * defctrs = hwc_get_default_cntrs2 (forKernel, 1);
+  if (defctrs == NULL)
+    fprintf (f_usage, GTXT ("    No default HW counter set defined for this system.\n"));
+  else if (strlen (defctrs) == 0)
+    {
+      char *s = hwc_get_orig_default_cntrs (forKernel);
+      fprintf (f_usage, GTXT ("    The default HW counter set (%s) defined for %s cannot be loaded on this system.\n"),
+              s, cpuname);
+      free (s);
+      free (defctrs);
+    }
+  else
+    {
+      char *defctrs2 = hwc_get_default_cntrs2 (forKernel, 2);
+      fprintf (f_usage, GTXT ("    -h %s\n"), defctrs);
+      free (defctrs2);
+      free (defctrs);
+    }
+
+  /* long listings */
+  char tmp[1024];
+  if (has_std_ctrs)
+    {
+      fprintf (f_usage, GTXT ("\nAliases for most useful HW counters:\n\n"));
+      format_columns (tmp, 1024, "alias", "raw name", "type ", "units", "regs", "description");
+      fprintf (f_usage, NTXT ("    %s\n\n"), tmp);
+      for (Hwcentry **pctr = std_ctrs; *pctr; pctr++)
+       {
+         Hwcentry *ctr = *pctr;
+         hwc_hwcentry_string_internal (tmp, sizeof (tmp), ctr, 0);
+         fprintf (f_usage, NTXT ("    %s\n"), tmp);
+       }
+    }
+  if (has_raw_ctrs)
+    {
+      fprintf (f_usage, GTXT ("\nRaw HW counters:\n\n"));
+      hwc_usage_raw_overview_sparc (f_usage, cpuver);
+      format_columns (tmp, 1024, "name", NULL, "type ", "units", "regs", "description");
+      fprintf (f_usage, NTXT ("    %s\n\n"), tmp);
+      for (Hwcentry **pctr = raw_ctrs; *pctr; pctr++)
+       {
+         Hwcentry *ctr = *pctr;
+         hwc_hwcentry_string_internal (tmp, sizeof (tmp), ctr, show_short_desc);
+         fprintf (f_usage, NTXT ("    %s\n"), tmp);
+       }
+    }
+
+  /* documentation notice */
+  hwc_get_docref (tmp, 1024);
+  if (strlen (tmp))
+    fprintf (f_usage, NTXT ("\n%s\n"), tmp);
+}
+
+/* Print a description of "-h" usage, largely common to collect and er_kernel. */
+void
+hwc_usage (int forKernel, const char *cmd, const char *dataspace_msg)
+{
+  hwc_usage_internal (forKernel, stdout, cmd, dataspace_msg, 1, 0);
+}
+
+void
+hwc_usage_f (int forKernel, FILE *f, const char *cmd, const char *dataspace_msg, int show_syntax, int show_short_desc)
+{
+  hwc_usage_internal (forKernel, f, cmd, dataspace_msg, show_syntax, show_short_desc);
+}
+
+/*---------------------------------------------------------------------------*/
+/* init functions */
+
+static char* supported_pebs_counters[] = {
+  "mem_inst_retired.latency_above_threshold",
+  "mem_trans_retired.load_latency",
+  "mem_trans_retired.precise_store",
+  NULL
+};
+
+/* callback, (see setup_cpc()) called for each valid regno/name combo */
+
+/* builds rawlist,, creates and updates reg_list[] arrays in stdlist table */
+static void
+hwc_cb (uint_t cpc_regno, const char *name)
+{
+  regno_t regno = cpc_regno; /* convert type */
+  list_add (&unfiltered_raw, regno, name);
+}
+
+/* input:
+ *   forKernel: 1 - generate lists for er_kernel, 0 - generate lists for collect
+ *
+ *   raw_orig: HWCs as generated by hwc_cb()
+ * output:
+ *   pstd_out[], praw_out[]: malloc'd array of pointers to malloc'd hwcentry, or NULL
+ */
+static void
+hwc_process_raw_ctrs (int forKernel, Hwcentry ***pstd_out,
+                     Hwcentry ***praw_out, Hwcentry ***phidden_out,
+                     Hwcentry**static_tables, Hwcentry **raw_unfiltered_in)
+{
+  // set up output buffers
+  ptr_list s_outbufs[3];
+  ptr_list *std_out = &s_outbufs[0];
+  ptr_list_init (std_out);
+  ptr_list *raw_out = &s_outbufs[1];
+  ptr_list_init (raw_out);
+  ptr_list *hidden_out = &s_outbufs[2];
+  ptr_list_init (hidden_out);
+
+#define NUM_TABLES 3
+  ptr_list table_copy[NUM_TABLES]; // copy of data from static tables. [0]std, [1]generic, and [2]hidden
+  for (int tt = 0; tt < NUM_TABLES; tt++)
+    ptr_list_init (&table_copy[tt]);
+
+  // copy records from std [0] and generic [1] static input tables into table_copy[0],[1],or[2]
+  for (int tt = 0; tt < 2; tt++)
+    for (Hwcentry *pctr = static_tables[tt]; pctr && pctr->name; pctr++)
+      if (is_hidden_alias (pctr))
+       list_append_shallow_copy (&table_copy[2], pctr); // hidden list
+      else
+       list_append_shallow_copy (&table_copy[tt], pctr);
+
+  // copy raw_unfiltered_in to raw_out
+  for (int ii = 0; raw_unfiltered_in && raw_unfiltered_in[ii]; ii++)
+    {
+      Hwcentry *pctr = raw_unfiltered_in[ii];
+      // filter out raw counters that don't work correctly
+
+#ifdef WORKAROUND_6231196_NIAGARA1_NO_CTR_0
+      if (cpcx_cpuver == CPC_ULTRA_T1)
+       if (!regno_is_valid (pctr, 1))
+         continue;   /* Niagara can not profile on register zero; skip this */
+#endif
+      // remove specific PEBs counters when back end doesn't support sampling
+      const char *name = pctr->name;
+      if ((cpcx_support_bitmask & HWCFUNCS_SUPPORT_PEBS_SAMPLING) == 0 || forKernel)
+       {
+         int skip = 0;
+         for (int ii = 0; supported_pebs_counters[ii]; ii++)
+           if (strcmp (supported_pebs_counters[ii], name) == 0)
+             {
+               skip = 1;
+               break;
+             }
+         if (skip)
+           continue;
+       }
+
+      Hwcentry *pnew = list_append_shallow_copy (raw_out, pctr);
+#ifdef WORKAROUND_6231196_NIAGARA1_NO_CTR_0
+      if (cpcx_cpuver == CPC_ULTRA_T1)
+       {
+         free (pnew->reg_list);
+         pnew->reg_list = NULL;
+         regno_add (pnew, 1); // only allow register 1
+       }
+#endif
+    } // raw_unfiltered_in
+
+  // Scan raw counters to populate Hwcentry fields from matching static_tables entries
+  // Also populate reg_list for aliases found in table_copy[]
+  for (int uu = 0; uu < raw_out->sz; uu++)
+    {
+      Hwcentry *praw = (Hwcentry*) raw_out->array[uu];
+      Hwcentry *pstd = NULL; // set if non-alias entry from std table matches
+      char *name = praw->name;
+      /* in the standard counter and generic lists,
+        update reg_list for all matching items  */
+      for (int tt = 0; tt < NUM_TABLES; tt++)
+       { // std, generic, and hidden
+         if (table_copy[tt].sz == 0)
+           continue;
+         Hwcentry **array = (Hwcentry**) table_copy[tt].array;
+         for (int jj = 0; array[jj]; jj++)
+           { // all table counters
+             Hwcentry *pctr = array[jj];
+             char *pname;
+             if (pctr->int_name)
+               pname = pctr->int_name;
+             else
+               pname = pctr->name;
+             if (!is_same (name, pname, '~'))
+               continue;
+
+             /* truncated pname matches <name>... */
+             // check to see if table entry applies only to specific register
+             int specific_reg_num_only = 0;
+             if (pctr->reg_num != REGNO_ANY)
+               {
+                 // table entry applies only to specific register
+                 if (!regno_is_valid (praw, pctr->reg_num))
+                   continue;
+                 specific_reg_num_only = 1;
+               }
+
+             // Match!
+             // Update cpu_table_copy's supported registers
+             if (specific_reg_num_only)
+               regno_add (pctr, pctr->reg_num);
+             else
+               pctr->reg_list = praw->reg_list;
+
+             if (!is_visible_alias (pctr) && !is_hidden_alias (pctr))
+               {
+                 // Note: we could expand criteria to also allow aliases to set default rates for raw HWCs
+                 /* This is an 'internal' raw counter */
+                 if (!pstd)
+                   pstd = pctr; /* use info as a template when adding to raw list */
+                 else
+                   hwcentry_print (DBG_LT0, "hwctable: hwc_cb: Warning: "
+                                   "counter %s appears in table more than once: ",
+                                   pstd);
+               }
+           }/* for table rows */
+       }/* for std and generic tables */
+
+      if (pstd)
+       {
+         /* the main table had an entry that matched <name> exactly */
+         /* Apply the main table entry as a template */
+         *praw = *pstd;
+       }
+    }/* for (raw_out) */
+
+  // update std_out and hidden_out
+  for (int tt = 0; tt < NUM_TABLES; tt++)
+    {
+      if (tt == 1 /*skip std_raw*/ || table_copy[tt].sz == 0)
+       continue;
+      Hwcentry *pctr;
+      for (int ii = 0; (pctr = table_copy[tt].array[ii]); ii++)
+       {
+         // prune unsupported rows from std table
+         if (!is_visible_alias (pctr) && !is_hidden_alias (pctr))
+           continue; // only aliases
+         if (REG_LIST_IS_EMPTY (pctr->reg_list))
+           {
+             if (is_numeric_alias (pctr))
+               {
+#if 1 //22844570 DTrace cpc provider does not accept numeric counter names
+                 if (forKernel)
+                   continue;
+#endif
+                 regno_add (pctr, REGNO_ANY); // hwcs specified by number allowed on any register
+               }
+             else
+               continue;
+           }
+
+         ptr_list *dest = (tt == 0) ? std_out : hidden_out;
+         Hwcentry *isInList;
+         if (pctr->short_desc == NULL)
+           {
+             isInList = ptrarray_find_by_name ((Hwcentry**) raw_out->array, pctr->int_name);
+             if (isInList)
+               pctr->short_desc = isInList->short_desc; // copy the raw counter's detailed description
+           }
+         isInList = ptrarray_find_by_name ((Hwcentry**) dest->array, pctr->name);
+         if (isInList)
+           hwcentry_print (DBG_LT0, "hwctable: hwc_cb: Warning: "
+                           "counter %s appears in alias list more than once: ",
+                           pctr);
+         else
+           list_append_shallow_copy (dest, pctr);
+       }
+    }
+  for (int tt = 0; tt < NUM_TABLES; tt++)
+    ptr_list_free (&table_copy[tt]);
+
+  if (forKernel)
+    {
+      // for er_kernel, use baseline value of PRELOAD_DEF_ERKERNEL instead of PRELOAD_DEF
+      for (int tt = 0; tt < 3; tt++)
+       { // std_out-0, raw_out-1, hidden_out-2
+         Hwcentry** hwcs = (Hwcentry**) (s_outbufs[tt].array);
+         for (int ii = 0; hwcs && hwcs[ii]; ii++)
+           {
+             Hwcentry *hwc = hwcs[ii];
+             if (hwc->val == PRELOAD_DEF)
+               hwc->val = PRELOAD_DEF_ERKERNEL;
+           }
+       }
+    }
+  *pstd_out = (Hwcentry**) std_out->array;
+  *praw_out = (Hwcentry**) raw_out->array;
+  *phidden_out = (Hwcentry**) hidden_out->array;
+}
+
+/* callback, (see setup_cpc()) called for each valid attribute */
+/* builds attrlist */
+static void
+attrs_cb (const char *attr)
+{
+  Tprintf (DBG_LT3, "hwctable: attrs_cb(): %s\n", attr);
+  if (strcmp (attr, "picnum") == 0)
+    return;     /* don't make this attribute available to users */
+  ptr_list_add (&unfiltered_attrs, (void*) strdup (attr));
+}
+
+/* returns true if attribute is valid for this platform */
+static int
+attr_is_valid (int forKernel, const char *attr)
+{
+  setup_cpcx ();
+  if (!VALID_FOR_KERNEL (forKernel) || !cpcx_attrs[forKernel])
+    return 0;
+  for (int ii = 0; cpcx_attrs[forKernel][ii]; ii++)
+    if (strcmp (attr, cpcx_attrs[forKernel][ii]) == 0)
+      return 1;
+  return 0;
+}
diff --git a/gprofng/common/opteron_pcbe.c b/gprofng/common/opteron_pcbe.c
new file mode 100644 (file)
index 0000000..d479945
--- /dev/null
@@ -0,0 +1,448 @@
+/* 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.  */
+
+/*
+ * This file contains preset event names from the Performance Application
+ * Programming Interface v3.5 which included the following notice:
+ *
+ *                             Copyright (c) 2005,6
+ *                           Innovative Computing Labs
+ *                         Computer Science Department,
+ *                            University of Tennessee,
+ *                                 Knoxville, TN.
+ *                              All Rights Reserved.
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *    * Redistributions of source code must retain the above copyright notice,
+ *      this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *    * Neither the name of the University of Tennessee nor the names of its
+ *      contributors may be used to endorse or promote products derived from
+ *     this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * This open source software license conforms to the BSD License template.
+ */
+
+/*
+ * Performance Counter Back-End for AMD Opteron and AMD Athlon 64 processors.
+ */
+
+#include <sys/types.h>
+#include "hwcdrv.h"
+
+#define CPU /* used by cpuid_get*() functions */
+
+typedef struct _amd_event
+{
+  char *name;
+  uint16_t emask;       /* Event mask setting */
+  uint8_t umask_valid;  /* Mask of unreserved UNIT_MASK bits */
+} amd_event_t;
+
+typedef struct _amd_generic_event
+{
+  char *name;
+  char *event;
+  uint8_t umask;
+} amd_generic_event_t;
+
+#define EV_END      { NULL, 0, 0 }
+#define GEN_EV_END  { NULL, NULL, 0 }
+
+#define AMD_cmn_events       \
+  { "FP_dispatched_fpu_ops",                            0x00, 0x3F }, \
+  { "FP_cycles_no_fpu_ops_retired",                     0x01, 0x0 }, \
+  { "FP_dispatched_fpu_ops_ff",                         0x02, 0x0 }, \
+  { "LS_seg_reg_load",                                  0x20, 0x7F }, \
+  { "LS_uarch_resync_self_modify",                      0x21, 0x0 }, \
+  { "LS_uarch_resync_snoop",                            0x22, 0x0 }, \
+  { "LS_buffer_2_full",                                 0x23, 0x0 }, \
+  { "LS_retired_cflush",                                0x26, 0x0 }, \
+  { "LS_retired_cpuid",                                 0x27, 0x0 }, \
+  { "DC_access",                                        0x40, 0x0 }, \
+  { "DC_miss",                                          0x41, 0x0 }, \
+  { "DC_refill_from_L2",                                0x42, 0x1F }, \
+  { "DC_refill_from_system",                            0x43, 0x1F }, \
+  { "DC_misaligned_data_ref",                           0x47, 0x0 }, \
+  { "DC_uarch_late_cancel_access",                      0x48, 0x0 }, \
+  { "DC_uarch_early_cancel_access",                     0x49, 0x0 }, \
+  { "DC_dispatched_prefetch_instr",                     0x4B, 0x7 }, \
+  { "DC_dcache_accesses_by_locks",                      0x4C, 0x2 }, \
+  { "BU_memory_requests",                               0x65, 0x83}, \
+  { "BU_data_prefetch",                                 0x67, 0x3 }, \
+  { "BU_cpu_clk_unhalted",                              0x76, 0x0 }, \
+  { "IC_fetch",                                         0x80, 0x0 }, \
+  { "IC_miss",                                          0x81, 0x0 }, \
+  { "IC_refill_from_L2",                                0x82, 0x0 }, \
+  { "IC_refill_from_system",                            0x83, 0x0 }, \
+  { "IC_itlb_L1_miss_L2_hit",                           0x84, 0x0 }, \
+  { "IC_uarch_resync_snoop",                            0x86, 0x0 }, \
+  { "IC_instr_fetch_stall",                             0x87, 0x0 }, \
+  { "IC_return_stack_hit",                              0x88, 0x0 }, \
+  { "IC_return_stack_overflow",                         0x89, 0x0 }, \
+  { "FR_retired_x86_instr_w_excp_intr",                 0xC0, 0x0 }, \
+  { "FR_retired_uops",                                  0xC1, 0x0 }, \
+  { "FR_retired_branches_w_excp_intr",                  0xC2, 0x0 }, \
+  { "FR_retired_branches_mispred",                      0xC3, 0x0 }, \
+  { "FR_retired_taken_branches",                        0xC4, 0x0 }, \
+  { "FR_retired_taken_branches_mispred",                0xC5, 0x0 }, \
+  { "FR_retired_far_ctl_transfer",                      0xC6, 0x0 }, \
+  { "FR_retired_resyncs",                               0xC7, 0x0 }, \
+  { "FR_retired_near_rets",                             0xC8, 0x0 }, \
+  { "FR_retired_near_rets_mispred",                     0xC9, 0x0 }, \
+  { "FR_retired_taken_branches_mispred_addr_miscomp",   0xCA, 0x0 }, \
+  { "FR_retired_fastpath_double_op_instr",              0xCC, 0x7 }, \
+  { "FR_intr_masked_cycles",                            0xCD, 0x0 }, \
+  { "FR_intr_masked_while_pending_cycles",              0xCE, 0x0 }, \
+  { "FR_taken_hardware_intrs",                          0xCF, 0x0 }, \
+  { "FR_nothing_to_dispatch",                           0xD0, 0x0 }, \
+  { "FR_dispatch_stalls",                               0xD1, 0x0 }, \
+  { "FR_dispatch_stall_branch_abort_to_retire",         0xD2, 0x0 }, \
+  { "FR_dispatch_stall_serialization",                  0xD3, 0x0 }, \
+  { "FR_dispatch_stall_segment_load",                   0xD4, 0x0 }, \
+  { "FR_dispatch_stall_reorder_buffer_full",            0xD5, 0x0 }, \
+  { "FR_dispatch_stall_resv_stations_full",             0xD6, 0x0 }, \
+  { "FR_dispatch_stall_fpu_full",                       0xD7, 0x0 }, \
+  { "FR_dispatch_stall_ls_full",                        0xD8, 0x0 }, \
+  { "FR_dispatch_stall_waiting_all_quiet",              0xD9, 0x0 }, \
+  { "FR_dispatch_stall_far_ctl_trsfr_resync_branch_pend", 0xDA, 0x0 },\
+  { "FR_fpu_exception",                                 0xDB, 0xF }, \
+  { "FR_num_brkpts_dr0",                                0xDC, 0x0 }, \
+  { "FR_num_brkpts_dr1",                                0xDD, 0x0 }, \
+  { "FR_num_brkpts_dr2",                                0xDE, 0x0 }, \
+  { "FR_num_brkpts_dr3",                                0xDF, 0x0 }, \
+  { "NB_mem_ctrlr_bypass_counter_saturation",           0xE4, 0xF }
+
+#define OPT_events \
+  { "LS_locked_operation",                              0x24, 0x7 }, \
+  { "DC_copyback",                                      0x44, 0x1F }, \
+  { "DC_dtlb_L1_miss_L2_hit",                           0x45, 0x0 }, \
+  { "DC_dtlb_L1_miss_L2_miss",                          0x46, 0x0 }, \
+  { "DC_1bit_ecc_error_found",                          0x4A, 0x3 }, \
+  { "BU_system_read_responses",                         0x6C, 0x7 }, \
+  { "BU_quadwords_written_to_system",                   0x6D, 0x1 }, \
+  { "BU_internal_L2_req",                               0x7D, 0x1F }, \
+  { "BU_fill_req_missed_L2",                            0x7E, 0x7 }, \
+  { "BU_fill_into_L2",                                  0x7F, 0x1 }, \
+  { "IC_itlb_L1_miss_L2_miss",                          0x85, 0x0 }, \
+  { "FR_retired_fpu_instr",                             0xCB, 0xF }, \
+  { "NB_mem_ctrlr_page_access",                         0xE0, 0x7 }, \
+  { "NB_mem_ctrlr_page_table_overflow",                 0xE1, 0x0 }, \
+  { "NB_mem_ctrlr_turnaround",                          0xE3, 0x7 }, \
+  { "NB_ECC_errors",                                    0xE8, 0x80}, \
+  { "NB_sized_commands",                                0xEB, 0x7F }, \
+  { "NB_probe_result",                                  0xEC, 0x7F}, \
+  { "NB_gart_events",                                   0xEE, 0x7 }, \
+  { "NB_ht_bus0_bandwidth",                             0xF6, 0xF }, \
+  { "NB_ht_bus1_bandwidth",                             0xF7, 0xF }, \
+  { "NB_ht_bus2_bandwidth",                             0xF8, 0xF }
+
+#define OPT_RevD_events \
+  { "NB_sized_blocks",                                  0xE5, 0x3C }
+
+#define OPT_RevE_events \
+  { "NB_cpu_io_to_mem_io",                              0xE9, 0xFF}, \
+  { "NB_cache_block_commands",                          0xEA, 0x3D}
+
+#define AMD_FAMILY_10h_cmn_events \
+  { "FP_retired_sse_ops",                               0x3,   0x7F}, \
+  { "FP_retired_move_ops",                              0x4,   0xF}, \
+  { "FP_retired_serialize_ops",                         0x5,   0xF}, \
+  { "FP_serialize_ops_cycles",                          0x6,   0x3}, \
+  { "DC_copyback",                                      0x44,  0x7F }, \
+  { "DC_dtlb_L1_miss_L2_hit",                           0x45,  0x3 }, \
+  { "DC_dtlb_L1_miss_L2_miss",                          0x46,  0x7 }, \
+  { "DC_1bit_ecc_error_found",                          0x4A,  0xF }, \
+  { "DC_dtlb_L1_hit",                                   0x4D,  0x7 }, \
+  { "BU_system_read_responses",                         0x6C,  0x17 }, \
+  { "BU_octwords_written_to_system",                    0x6D,  0x1 }, \
+  { "BU_internal_L2_req",                               0x7D,  0x3F }, \
+  { "BU_fill_req_missed_L2",                            0x7E,  0xF }, \
+  { "BU_fill_into_L2",                                  0x7F,  0x3 }, \
+  { "IC_itlb_L1_miss_L2_miss",                          0x85,  0x3 }, \
+  { "IC_eviction",                                      0x8B,  0x0 }, \
+  { "IC_cache_lines_invalidate",                        0x8C,  0xF }, \
+  { "IC_itlb_reload",                                   0x99,  0x0 }, \
+  { "IC_itlb_reload_aborted",                           0x9A,  0x0 }, \
+  { "FR_retired_mmx_sse_fp_instr",                      0xCB,  0x7 }, \
+  { "NB_mem_ctrlr_page_access",                         0xE0,  0xFF }, \
+  { "NB_mem_ctrlr_page_table_overflow",                 0xE1,  0x3 }, \
+  { "NB_mem_ctrlr_turnaround",                          0xE3,  0x3F }, \
+  { "NB_thermal_status",                                0xE8,  0x7C}, \
+  { "NB_sized_commands",                                0xEB,  0x3F }, \
+  { "NB_probe_results_upstream_req",                    0xEC,  0xFF}, \
+  { "NB_gart_events",                                   0xEE,  0xFF }, \
+  { "NB_ht_bus0_bandwidth",                             0xF6,  0xBF }, \
+  { "NB_ht_bus1_bandwidth",                             0xF7,  0xBF }, \
+  { "NB_ht_bus2_bandwidth",                             0xF8,  0xBF }, \
+  { "NB_ht_bus3_bandwidth",                             0x1F9, 0xBF }, \
+  { "LS_locked_operation",                              0x24,  0xF }, \
+  { "LS_cancelled_store_to_load_fwd_ops",               0x2A,  0x7 }, \
+  { "LS_smi_received",                                  0x2B,  0x0 }, \
+  { "LS_ineffective_prefetch",                          0x52,  0x9 }, \
+  { "LS_global_tlb_flush",                              0x54,  0x0 }, \
+  { "NB_mem_ctrlr_dram_cmd_slots_missed",               0xE2,  0x3 }, \
+  { "NB_mem_ctrlr_req",                                 0x1F0, 0xFF }, \
+  { "CB_cpu_to_dram_req_to_target",                     0x1E0, 0xFF }, \
+  { "CB_io_to_dram_req_to_target",                      0x1E1, 0xFF }, \
+  { "CB_cpu_read_cmd_latency_to_target_0_to_3",         0x1E2, 0xFF }, \
+  { "CB_cpu_read_cmd_req_to_target_0_to_3",             0x1E3, 0xFF }, \
+  { "CB_cpu_read_cmd_latency_to_target_4_to_7",         0x1E4, 0xFF }, \
+  { "CB_cpu_read_cmd_req_to_target_4_to_7",             0x1E5, 0xFF }, \
+  { "CB_cpu_cmd_latency_to_target_0_to_7",              0x1E6, 0xFF }, \
+  { "CB_cpu_req_to_target_0_to_7",                      0x1E7, 0xFF }, \
+  { "L3_read_req",                                      0x4E0, 0xF7 }, \
+  { "L3_miss",                                          0x4E1, 0xF7 }, \
+  { "L3_l2_eviction_l3_fill",                           0x4E2, 0xFF }, \
+  { "L3_eviction",                                      0x4E3, 0xF  }
+
+#define AMD_cmn_generic_events \
+  { "PAPI_br_ins", "FR_retired_branches_w_excp_intr",   0x0 },\
+  { "PAPI_br_msp", "FR_retired_branches_mispred",       0x0 }, \
+  { "PAPI_br_tkn", "FR_retired_taken_branches",         0x0 }, \
+  { "PAPI_fp_ops", "FP_dispatched_fpu_ops",             0x3 }, \
+  { "PAPI_fad_ins", "FP_dispatched_fpu_ops",            0x1 }, \
+  { "PAPI_fml_ins", "FP_dispatched_fpu_ops",            0x2 }, \
+  { "PAPI_fpu_idl", "FP_cycles_no_fpu_ops_retired",     0x0 }, \
+  { "PAPI_tot_cyc", "BU_cpu_clk_unhalted",              0x0 }, \
+  { "PAPI_tot_ins", "FR_retired_x86_instr_w_excp_intr", 0x0 }, \
+  { "PAPI_l1_dca", "DC_access",                         0x0 }, \
+  { "PAPI_l1_dcm", "DC_miss",                           0x0 }, \
+  { "PAPI_l1_ldm", "DC_refill_from_L2",                 0xe }, \
+  { "PAPI_l1_stm", "DC_refill_from_L2",                 0x10 }, \
+  { "PAPI_l1_ica", "IC_fetch",                          0x0 }, \
+  { "PAPI_l1_icm", "IC_miss",                           0x0 }, \
+  { "PAPI_l1_icr", "IC_fetch",                          0x0 }, \
+  { "PAPI_l2_dch", "DC_refill_from_L2",                 0x1e }, \
+  { "PAPI_l2_dcm", "DC_refill_from_system",             0x1e }, \
+  { "PAPI_l2_dcr", "DC_refill_from_L2",                 0xe }, \
+  { "PAPI_l2_dcw", "DC_refill_from_L2",                 0x10 }, \
+  { "PAPI_l2_ich", "IC_refill_from_L2",                 0x0 }, \
+  { "PAPI_l2_icm", "IC_refill_from_system",             0x0 }, \
+  { "PAPI_l2_ldm", "DC_refill_from_system",             0xe }, \
+  { "PAPI_l2_stm", "DC_refill_from_system",             0x10 }, \
+  { "PAPI_res_stl", "FR_dispatch_stalls",               0x0 }, \
+  { "PAPI_stl_icy", "FR_nothing_to_dispatch",           0x0 }, \
+  { "PAPI_hw_int", "FR_taken_hardware_intrs",           0x0 }
+
+#define OPT_cmn_generic_events \
+  { "PAPI_tlb_dm", "DC_dtlb_L1_miss_L2_miss",           0x0 }, \
+  { "PAPI_tlb_im", "IC_itlb_L1_miss_L2_miss",           0x0 }, \
+  { "PAPI_fp_ins", "FR_retired_fpu_instr",              0xd }, \
+  { "PAPI_vec_ins", "FR_retired_fpu_instr",             0x4 }
+
+#define AMD_FAMILY_10h_generic_events \
+  { "PAPI_tlb_dm", "DC_dtlb_L1_miss_L2_miss",           0x7 }, \
+  { "PAPI_tlb_im", "IC_itlb_L1_miss_L2_miss",           0x3 }, \
+  { "PAPI_l3_dcr", "L3_read_req",                       0xf1 }, \
+  { "PAPI_l3_icr", "L3_read_req",                       0xf2 }, \
+  { "PAPI_l3_tcr", "L3_read_req",                       0xf7 }, \
+  { "PAPI_l3_stm", "L3_miss",                           0xf4 }, \
+  { "PAPI_l3_ldm", "L3_miss",                           0xf3 }, \
+  { "PAPI_l3_tcm", "L3_miss",                           0xf7 }
+
+static amd_event_t opt_events_rev_E[] = {
+  AMD_cmn_events,
+  OPT_events,
+  OPT_RevD_events,
+  OPT_RevE_events,
+  EV_END
+};
+
+static amd_event_t family_10h_events[] = {
+  AMD_cmn_events,
+  OPT_RevE_events,
+  AMD_FAMILY_10h_cmn_events,
+  EV_END
+};
+
+static amd_generic_event_t opt_generic_events[] = {
+  AMD_cmn_generic_events,
+  OPT_cmn_generic_events,
+  GEN_EV_END
+};
+
+static amd_generic_event_t family_10h_generic_events[] = {
+  AMD_cmn_generic_events,
+  AMD_FAMILY_10h_generic_events,
+  GEN_EV_END
+};
+
+static amd_event_t *amd_events = NULL;
+static uint_t amd_family;
+static amd_generic_event_t *amd_generic_events = NULL;
+
+#define BITS(v, u, l)       (((v) >> (l)) & ((1 << (1 + (u) - (l))) - 1))
+#define OPTERON_FAMILY      0x0f
+#define AMD_FAMILY_10H      0x10
+
+static int
+opt_pcbe_init (void)
+{
+  amd_family = cpuid_getfamily ();
+  /*
+   * Make sure this really _is_ an Opteron or Athlon 64 system. The kernel
+   * loads this module based on its name in the module directory, but it
+   * could have been renamed.
+   */
+  if (cpuid_getvendor () != X86_VENDOR_AMD
+      || (amd_family != OPTERON_FAMILY && amd_family != AMD_FAMILY_10H))
+    return (-1);
+
+  /*
+   * Figure out processor revision here and assign appropriate
+   * event configuration.
+   */
+  if (amd_family == OPTERON_FAMILY)
+    {
+      amd_events = opt_events_rev_E;
+      amd_generic_events = opt_generic_events;
+    }
+  else
+    {
+      amd_events = family_10h_events;
+      amd_generic_events = family_10h_generic_events;
+    }
+  return (0);
+}
+
+static uint_t
+opt_pcbe_ncounters (void)
+{
+  return (4);
+}
+
+static const char *
+opt_pcbe_impl_name (void)
+{
+  if (amd_family == OPTERON_FAMILY)
+    return ("AMD Opteron & Athlon64");
+  else if (amd_family == AMD_FAMILY_10H)
+    return ("AMD Family 10h");
+  else
+    return ("Unknown AMD processor");
+}
+
+static const char *
+opt_pcbe_cpuref (void)
+{
+  if (amd_family == OPTERON_FAMILY)
+    return GTXT ("See Chapter 10 of the \"BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD Opteron Processors,\"\nAMD publication #26094");
+  else if (amd_family == AMD_FAMILY_10H)
+    return GTXT ("See section 3.15 of the \"BIOS and Kernel Developer's Guide (BKDG) For AMD Family 10h Processors,\"\nAMD publication #31116");
+  else
+    return GTXT ("Unknown AMD processor");
+}
+
+static int
+opt_pcbe_get_events (hwcf_hwc_cb_t *hwc_cb)
+{
+  int count = 0;
+  for (uint_t kk = 0; amd_events && amd_events[kk].name; kk++)
+    for (uint_t jj = 0; jj < opt_pcbe_ncounters (); jj++)
+      {
+       hwc_cb (jj, amd_events[kk].name);
+       count++;
+      }
+  for (uint_t kk = 0; amd_generic_events && amd_generic_events[kk].name; kk++)
+    for (uint_t jj = 0; jj < opt_pcbe_ncounters (); jj++)
+      {
+       hwc_cb (jj, amd_generic_events[kk].name);
+       count++;
+      }
+  return count;
+}
+
+static int
+opt_pcbe_get_eventnum (const char *eventname, uint_t pmc, eventsel_t *eventsel,
+                      eventsel_t *event_valid_umask, uint_t *pmc_sel)
+{
+  uint_t kk;
+  *pmc_sel = pmc; /* for AMD, pmc doesn't need to be adjusted */
+  *eventsel = (eventsel_t) - 1;
+  *event_valid_umask = 0x0;
+
+  /* search table */
+  for (kk = 0; amd_events && amd_events[kk].name; kk++)
+    {
+      if (strcmp (eventname, amd_events[kk].name) == 0)
+       {
+         *eventsel = EXTENDED_EVNUM_2_EVSEL (amd_events[kk].emask);
+         *event_valid_umask = amd_events[kk].umask_valid;
+         return 0;
+       }
+    }
+
+  /* search generic */
+  int generic = 0;
+  eventsel_t tmp_umask = 0;
+  for (kk = 0; amd_generic_events && amd_generic_events[kk].name; kk++)
+    {
+      if (strcmp (eventname, amd_generic_events[kk].name) == 0)
+       {
+         generic = 1;
+         eventname = amd_generic_events[kk].event;
+         tmp_umask = amd_generic_events[kk].umask;
+         break;
+       }
+    }
+  if (!generic)
+    return -1;
+
+  /* find real event # for generic event */
+  for (kk = 0; amd_events && amd_events[kk].name; kk++)
+    {
+      if (strcmp (eventname, amd_events[kk].name) == 0)
+       {
+         *eventsel = EXTENDED_EVNUM_2_EVSEL (amd_events[kk].emask);
+         *eventsel |= (tmp_umask << PERFCTR_UMASK_SHIFT);
+         *event_valid_umask = 0; /* user umask not allowed w/generic events */
+         return 0;
+       }
+    }
+  return -1;
+}
+
+static hdrv_pcbe_api_t hdrv_pcbe_opteron_api = {
+  opt_pcbe_init,
+  opt_pcbe_ncounters,
+  opt_pcbe_impl_name,
+  opt_pcbe_cpuref,
+  opt_pcbe_get_events,
+  opt_pcbe_get_eventnum
+};
diff --git a/gprofng/config/bison.m4 b/gprofng/config/bison.m4
new file mode 100644 (file)
index 0000000..0493587
--- /dev/null
@@ -0,0 +1,92 @@
+# serial 10
+
+# Copyright (C) 2002-2006, 2008-2021 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 two types of parser skeletons:
+#
+# * Those that can be used with any Yacc implementation, including bison.
+#   For these, in the configure.ac, up to Autoconf 2.69, you could use
+#     AC_PROG_YACC
+#   In newer Autoconf versions, however, this macro is broken. See
+#     https://lists.gnu.org/archive/html/autoconf-patches/2013-03/msg00000.html
+#     https://lists.gnu.org/archive/html/bug-autoconf/2018-12/msg00001.html
+#   In the Makefile.am you could use
+#     $(SHELL) $(YLWRAP) $(srcdir)/foo.y \
+#                        y.tab.c foo.c \
+#                        y.tab.h foo.h \
+#                        y.output foo.output \
+#                        -- $(YACC) $(YFLAGS) $(AM_YFLAGS)
+#   or similar.
+#
+# * Those that make use of Bison extensions. For example,
+#     - %define api.pure   requires bison 2.7 or newer,
+#     - %precedence        requires bison 3.0 or newer.
+#   For these, in the configure.ac you will need an invocation of
+#     gl_PROG_BISON([VARIABLE], [MIN_BISON_VERSION])
+#   Example:
+#     gl_PROG_BISON([PARSE_DATETIME_BISON], [2.4])
+#   With this preparation, in the Makefile.am there are two ways to formulate
+#   the invocation. Both are direct, without use of 'ylwrap'.
+#   (a) You can invoke
+#         $(VARIABLE) -d $(SOME_BISON_OPTIONS) --output foo.c $(srcdir)/foo.y
+#       or similar.
+#   (b) If you want the invocation to honor an YFLAGS=... parameter passed to
+#       'configure' or an YFLAGS environment variable present at 'configure'
+#       time, add an invocation of gl_BISON to the configure.ac, and write
+#         $(VARIABLE) -d $(YFLAGS) $(AM_YFLAGS) $(srcdir)/foo.y
+#       or similar.
+
+# This macro defines the autoconf variable VARIABLE to 'bison' if the specified
+# minimum version of bison is found in $PATH, or to ':' otherwise.
+AC_DEFUN([gl_PROG_BISON],
+[
+  AC_CHECK_PROGS([$1], [bison])
+  if test -z "$[$1]"; then
+    ac_verc_fail=yes
+  else
+    cat >conftest.y <<_ACEOF
+%require "$2"
+%%
+exp:
+_ACEOF
+    AC_MSG_CHECKING([for bison $2 or newer])
+    ac_prog_version=`$$1 --version 2>&1 | sed -n 's/^.*GNU Bison.* \([[0-9]]*\.[[0-9.]]*\).*$/\1/p'`
+    : ${ac_prog_version:='v. ?.??'}
+    if $$1 conftest.y -o conftest.c 2>/dev/null; then
+      ac_prog_version="$ac_prog_version, ok"
+      ac_verc_fail=no
+    else
+      ac_prog_version="$ac_prog_version, bad"
+      ac_verc_fail=yes
+    fi
+    rm -f conftest.y conftest.c
+    AC_MSG_RESULT([$ac_prog_version])
+  fi
+  if test $ac_verc_fail = yes; then
+    [$1]=:
+  fi
+  AC_SUBST([$1])
+])
+
+# This macro sets the autoconf variables YACC (for old-style yacc Makefile
+# rules) and YFLAGS (to allow options to be passed as 'configure' time).
+AC_DEFUN([gl_BISON],
+[
+  : ${YACC='bison -o y.tab.c'}
+dnl
+dnl Declaring YACC & YFLAGS precious will not be necessary after GNULIB
+dnl requires an Autoconf greater than 2.59c, but it will probably still be
+dnl useful to override the description of YACC in the --help output, re
+dnl parse-datetime.y assuming 'bison -o y.tab.c'.
+  AC_ARG_VAR([YACC],
+[The "Yet Another C Compiler" implementation to use.  Defaults to
+'bison -o y.tab.c'.  Values other than 'bison -o y.tab.c' will most likely
+break on most systems.])dnl
+  AC_ARG_VAR([YFLAGS],
+[YFLAGS contains the list arguments that will be passed by default to Bison.
+This script will default YFLAGS to the empty string to avoid a default value of
+'-d' given by some make applications.])dnl
+])
diff --git a/gprofng/configure b/gprofng/configure
new file mode 100755 (executable)
index 0000000..3cf4dc7
--- /dev/null
@@ -0,0 +1,19350 @@
+#! /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=''
+
+# 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"
+
+enable_option_checking=no
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+BUILD_SUBDIRS
+GPROFNG_LIBDIR
+GPROFNG_CPPFLAGS
+GPROFNG_CFLAGS
+LD_NO_AS_NEEDED
+BUILD_MAN_FALSE
+BUILD_MAN_TRUE
+HELP2MAN
+TCL_TRY_FALSE
+TCL_TRY_TRUE
+EXPECT
+jdk_inc
+JAVA
+JAVAC
+PTHREAD_CFLAGS
+PTHREAD_LIBS
+PTHREAD_CC
+ax_pthread_config
+RUN_TESTS_FALSE
+RUN_TESTS_TRUE
+subdirs
+BUILD_SRC_FALSE
+BUILD_SRC_TRUE
+BUILD_COLLECTOR_FALSE
+BUILD_COLLECTOR_TRUE
+gprofng_cflags
+WERROR
+GPROFNG_LIBADD
+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
+enable_werror_always
+enable_gprofng_tools
+with_jdk
+enable_gprofng_debug
+'
+      ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+CXX
+CXXFLAGS
+CCC
+CXXCPP'
+ac_subdirs_all='libcollector'
+
+# 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=no]
+  --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)
+  --enable-werror-always  enable -Werror despite compiler version
+  --disable-gprofng-tools do not build gprofng/src directory
+  --enable-gprofng-debug  Enable debugging output [default=no]
+
+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]
+  --with-jdk=PATH         specify prefix directory for installed JDK.
+
+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
+
+# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES
+# ---------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly.
+ac_fn_c_check_decl ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  as_decl_name=`echo $2|sed 's/ *(.*//'`
+  as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+$4
+int
+main ()
+{
+#ifndef $as_decl_name
+#ifdef __cplusplus
+  (void) $as_decl_use;
+#else
+  (void) $as_decl_name;
+#endif
+#endif
+
+  ;
+  return 0;
+}
+_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_decl
+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
+
+
+am__api_version='1.15'
+
+ac_aux_dir=
+for ac_dir in "$srcdir" "$srcdir/.." "$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\" \"$srcdir/..\" \"$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.
+
+
+# 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
+
+
+# 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=no
+fi
+
+
+
+
+
+
+
+
+
+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-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 12092 "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 12198 "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:
+
+
+
+GPROFNG_LIBADD="-L../../libiberty -liberty"
+if test "$enable_shared" = "yes"; then
+  GPROFNG_LIBADD="-L../../libiberty/pic -liberty"
+fi
+
+
+# Figure out what compiler warnings we can enable.
+# See config/warnings.m4 for details.
+
+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
+
+WERROR=
+# Check whether --enable-werror-always was given.
+if test "${enable_werror_always+set}" = set; then :
+  enableval=$enable_werror_always;
+else
+  enable_werror_always=no
+fi
+
+if test $enable_werror_always = yes; then :
+  WERROR="$WERROR${WERROR:+ }-Werror"
+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
+
+gprofng_cflags=
+save_CFLAGS="$CFLAGS"
+for real_option in -Wall; do
+  # Do the check with the no- prefix removed since gcc silently
+  # accepts any -Wno-* option on purpose
+  case $real_option in
+    -Wno-*) option=-W`expr x$real_option : 'x-Wno-\(.*\)'` ;;
+    *) option=$real_option ;;
+  esac
+  as_acx_Woption=`$as_echo "acx_cv_prog_cc_warning_$option" | $as_tr_sh`
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports $option" >&5
+$as_echo_n "checking whether $CC supports $option... " >&6; }
+if eval \${$as_acx_Woption+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  CFLAGS="$option"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$as_acx_Woption=yes"
+else
+  eval "$as_acx_Woption=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+eval ac_res=\$$as_acx_Woption
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  if test `eval 'as_val=${'$as_acx_Woption'};$as_echo "$as_val"'` = yes; then :
+  gprofng_cflags="$gprofng_cflags${gprofng_cflags:+ }$real_option"
+fi
+  done
+CFLAGS="$save_CFLAGS"
+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
+
+
+gprofng_cppflags="-U_ASM"
+build_collector=
+build_src=
+
+# This is annoying: it means we have to pass --enable-shared explicitly to
+# get gprofng, while the configure default is supposed to be that shared libs
+# are on by default.  But as long as libiberty has code like this, so must
+# we...
+
+  case "${target}" in
+    x86_64-*-linux*)
+      build_src=true
+      build_collector=true
+      ;;
+    i?86-*-linux*)
+      build_collector=true
+      build_collector=true
+      ;;
+    aarch64-*-linux*)
+      build_src=true
+      build_collector=true
+      ;;
+  esac
+  # Check whether --enable-gprofng-tools was given.
+if test "${enable_gprofng_tools+set}" = set; then :
+  enableval=$enable_gprofng_tools; build_src=$enableval
+fi
+
+
+ if test x$build_collector = xtrue; then
+  BUILD_COLLECTOR_TRUE=
+  BUILD_COLLECTOR_FALSE='#'
+else
+  BUILD_COLLECTOR_TRUE='#'
+  BUILD_COLLECTOR_FALSE=
+fi
+
+ if test x$build_src = xtrue; then
+  BUILD_SRC_TRUE=
+  BUILD_SRC_FALSE='#'
+else
+  BUILD_SRC_TRUE='#'
+  BUILD_SRC_FALSE=
+fi
+
+
+run_tests=false
+if test x$build_collector = xtrue; then
+
+
+subdirs="$subdirs libcollector"
+
+  if test x${host} = x${target}; then
+    run_tests=true
+  fi
+fi
+ if test x$run_tests = xtrue; then
+  RUN_TESTS_TRUE=
+  RUN_TESTS_FALSE='#'
+else
+  RUN_TESTS_TRUE='#'
+  RUN_TESTS_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
+
+ax_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on Tru64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
+        ax_pthread_save_CC="$CC"
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
+        if test "x$PTHREAD_CC" != "x"; then :
+  CC="$PTHREAD_CC"
+fi
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS" >&5
+$as_echo_n "checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS... " >&6; }
+        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 pthread_join ();
+int
+main ()
+{
+return pthread_join ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ax_pthread_ok=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5
+$as_echo "$ax_pthread_ok" >&6; }
+        if test "x$ax_pthread_ok" = "xno"; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        CC="$ax_pthread_save_CC"
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try.  Items starting with a "-" are
+# C compiler flags, and other items are library names, except for "none"
+# which indicates that we try without any flags at all, and "pthread-config"
+# which is a program returning the flags for the Pth emulation library.
+
+ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
+#           (Note: HP C rejects this with "bad form for `-t' option")
+# -pthreads: Solaris/gcc (Note: HP C also rejects)
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads and
+#      -D_REENTRANT too), HP C (must be checked before -lpthread, which
+#      is present but should not be used directly; and before -mthreads,
+#      because the compiler interprets this as "-mt" + "-hreads")
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case $host_os in
+
+        freebsd*)
+
+        # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+        # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+
+        ax_pthread_flags="-kthread lthread $ax_pthread_flags"
+        ;;
+
+        hpux*)
+
+        # From the cc(1) man page: "[-mt] Sets various -D flags to enable
+        # multi-threading and also sets -lpthread."
+
+        ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
+        ;;
+
+        openedition*)
+
+        # IBM z/OS requires a feature-test macro to be defined in order to
+        # enable POSIX threads at all, so give the user a hint if this is
+        # not set. (We don't define these ourselves, as they can affect
+        # other portions of the system API in unpredictable ways.)
+
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#            if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
+             AX_PTHREAD_ZOS_MISSING
+#            endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "AX_PTHREAD_ZOS_MISSING" >/dev/null 2>&1; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&5
+$as_echo "$as_me: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&2;}
+fi
+rm -f conftest*
+
+        ;;
+
+        solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed. (N.B.: The stubs are missing
+        # pthread_cleanup_push, or rather a function called by this macro,
+        # so we could check for that, but who knows whether they'll stub
+        # that too in a future libc.)  So we'll check first for the
+        # standard Solaris way of linking pthreads (-mt -lpthread).
+
+        ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
+        ;;
+esac
+
+# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
+
+if test "x$GCC" = "xyes"; then :
+  ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"
+fi
+
+# The presence of a feature test macro requesting re-entrant function
+# definitions is, on some systems, a strong hint that pthreads support is
+# correctly enabled
+
+case $host_os in
+        darwin* | hpux* | linux* | osf* | solaris*)
+        ax_pthread_check_macro="_REENTRANT"
+        ;;
+
+        aix*)
+        ax_pthread_check_macro="_THREAD_SAFE"
+        ;;
+
+        *)
+        ax_pthread_check_macro="--"
+        ;;
+esac
+if test "x$ax_pthread_check_macro" = "x--"; then :
+  ax_pthread_check_cond=0
+else
+  ax_pthread_check_cond="!defined($ax_pthread_check_macro)"
+fi
+
+# Are we compiling with Clang?
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC is Clang" >&5
+$as_echo_n "checking whether $CC is Clang... " >&6; }
+if ${ax_cv_PTHREAD_CLANG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ax_cv_PTHREAD_CLANG=no
+     # Note that Autoconf sets GCC=yes for Clang as well as GCC
+     if test "x$GCC" = "xyes"; then
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
+#            if defined(__clang__) && defined(__llvm__)
+             AX_PTHREAD_CC_IS_CLANG
+#            endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "AX_PTHREAD_CC_IS_CLANG" >/dev/null 2>&1; then :
+  ax_cv_PTHREAD_CLANG=yes
+fi
+rm -f conftest*
+
+     fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG" >&5
+$as_echo "$ax_cv_PTHREAD_CLANG" >&6; }
+ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
+
+ax_pthread_clang_warning=no
+
+# Clang needs special handling, because older versions handle the -pthread
+# option in a rather... idiosyncratic way
+
+if test "x$ax_pthread_clang" = "xyes"; then
+
+        # Clang takes -pthread; it has never supported any other flag
+
+        # (Note 1: This will need to be revisited if a system that Clang
+        # supports has POSIX threads in a separate library.  This tends not
+        # to be the way of modern systems, but it's conceivable.)
+
+        # (Note 2: On some systems, notably Darwin, -pthread is not needed
+        # to get POSIX threads support; the API is always present and
+        # active.  We could reasonably leave PTHREAD_CFLAGS empty.  But
+        # -pthread does define _REENTRANT, and while the Darwin headers
+        # ignore this macro, third-party headers might not.)
+
+        PTHREAD_CFLAGS="-pthread"
+        PTHREAD_LIBS=
+
+        ax_pthread_ok=yes
+
+        # However, older versions of Clang make a point of warning the user
+        # that, in an invocation where only linking and no compilation is
+        # taking place, the -pthread option has no effect ("argument unused
+        # during compilation").  They expect -pthread to be passed in only
+        # when source code is being compiled.
+        #
+        # Problem is, this is at odds with the way Automake and most other
+        # C build frameworks function, which is that the same flags used in
+        # compilation (CFLAGS) are also used in linking.  Many systems
+        # supported by AX_PTHREAD require exactly this for POSIX threads
+        # support, and in fact it is often not straightforward to specify a
+        # flag that is used only in the compilation phase and not in
+        # linking.  Such a scenario is extremely rare in practice.
+        #
+        # Even though use of the -pthread flag in linking would only print
+        # a warning, this can be a nuisance for well-run software projects
+        # that build with -Werror.  So if the active version of Clang has
+        # this misfeature, we search for an option to squash it.
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread" >&5
+$as_echo_n "checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread... " >&6; }
+if ${ax_cv_PTHREAD_CLANG_NO_WARN_FLAG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
+             # Create an alternate version of $ac_link that compiles and
+             # links in two steps (.c -> .o, .o -> exe) instead of one
+             # (.c -> exe), because the warning occurs only in the second
+             # step
+             ax_pthread_save_ac_link="$ac_link"
+             ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
+             ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
+             ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
+             ax_pthread_save_CFLAGS="$CFLAGS"
+             for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
+                if test "x$ax_pthread_try" = "xunknown"; then :
+  break
+fi
+                CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
+                ac_link="$ax_pthread_save_ac_link"
+                cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void){return 0;}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_link="$ax_pthread_2step_ac_link"
+                     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void){return 0;}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+             done
+             ac_link="$ax_pthread_save_ac_link"
+             CFLAGS="$ax_pthread_save_CFLAGS"
+             if test "x$ax_pthread_try" = "x"; then :
+  ax_pthread_try=no
+fi
+             ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&5
+$as_echo "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&6; }
+
+        case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
+                no | unknown) ;;
+                *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
+        esac
+
+fi # $ax_pthread_clang = yes
+
+if test "x$ax_pthread_ok" = "xno"; then
+for ax_pthread_try_flag in $ax_pthread_flags; do
+
+        case $ax_pthread_try_flag in
+                none)
+                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5
+$as_echo_n "checking whether pthreads work without any flags... " >&6; }
+                ;;
+
+                -mt,pthread)
+                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with -mt -lpthread" >&5
+$as_echo_n "checking whether pthreads work with -mt -lpthread... " >&6; }
+                PTHREAD_CFLAGS="-mt"
+                PTHREAD_LIBS="-lpthread"
+                ;;
+
+                -*)
+                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $ax_pthread_try_flag" >&5
+$as_echo_n "checking whether pthreads work with $ax_pthread_try_flag... " >&6; }
+                PTHREAD_CFLAGS="$ax_pthread_try_flag"
+                ;;
+
+                pthread-config)
+                # Extract the first word of "pthread-config", so it can be a program name with args.
+set dummy pthread-config; 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_ax_pthread_config+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ax_pthread_config"; then
+  ac_cv_prog_ax_pthread_config="$ax_pthread_config" # 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_ax_pthread_config="yes"
+    $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
+
+  test -z "$ac_cv_prog_ax_pthread_config" && ac_cv_prog_ax_pthread_config="no"
+fi
+fi
+ax_pthread_config=$ac_cv_prog_ax_pthread_config
+if test -n "$ax_pthread_config"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5
+$as_echo "$ax_pthread_config" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+                if test "x$ax_pthread_config" = "xno"; then :
+  continue
+fi
+                PTHREAD_CFLAGS="`pthread-config --cflags`"
+                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+                ;;
+
+                *)
+                { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$ax_pthread_try_flag" >&5
+$as_echo_n "checking for the pthreads library -l$ax_pthread_try_flag... " >&6; }
+                PTHREAD_LIBS="-l$ax_pthread_try_flag"
+                ;;
+        esac
+
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <pthread.h>
+#                       if $ax_pthread_check_cond
+#                        error "$ax_pthread_check_macro must be defined"
+#                       endif
+                        static void routine(void *a) { a = 0; }
+                        static void *start_routine(void *a) { return a; }
+int
+main ()
+{
+pthread_t th; pthread_attr_t attr;
+                        pthread_create(&th, 0, start_routine, 0);
+                        pthread_join(th, 0);
+                        pthread_attr_init(&attr);
+                        pthread_cleanup_push(routine, 0);
+                        pthread_cleanup_pop(0) /* ; */
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ax_pthread_ok=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5
+$as_echo "$ax_pthread_ok" >&6; }
+        if test "x$ax_pthread_ok" = "xyes"; then :
+  break
+fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+# Various other checks:
+if test "x$ax_pthread_ok" = "xyes"; then
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5
+$as_echo_n "checking for joinable pthread attribute... " >&6; }
+if ${ax_cv_PTHREAD_JOINABLE_ATTR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ax_cv_PTHREAD_JOINABLE_ATTR=unknown
+             for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+                 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <pthread.h>
+int
+main ()
+{
+int attr = $ax_pthread_attr; return attr /* ; */
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+             done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_JOINABLE_ATTR" >&5
+$as_echo "$ax_cv_PTHREAD_JOINABLE_ATTR" >&6; }
+        if test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
+               test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
+               test "x$ax_pthread_joinable_attr_defined" != "xyes"; then :
+
+cat >>confdefs.h <<_ACEOF
+#define PTHREAD_CREATE_JOINABLE $ax_cv_PTHREAD_JOINABLE_ATTR
+_ACEOF
+
+               ax_pthread_joinable_attr_defined=yes
+
+fi
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether more special flags are required for pthreads" >&5
+$as_echo_n "checking whether more special flags are required for pthreads... " >&6; }
+if ${ax_cv_PTHREAD_SPECIAL_FLAGS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ax_cv_PTHREAD_SPECIAL_FLAGS=no
+             case $host_os in
+             solaris*)
+             ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
+             ;;
+             esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_SPECIAL_FLAGS" >&5
+$as_echo "$ax_cv_PTHREAD_SPECIAL_FLAGS" >&6; }
+        if test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
+               test "x$ax_pthread_special_flags_added" != "xyes"; then :
+  PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
+               ax_pthread_special_flags_added=yes
+fi
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_PRIO_INHERIT" >&5
+$as_echo_n "checking for PTHREAD_PRIO_INHERIT... " >&6; }
+if ${ax_cv_PTHREAD_PRIO_INHERIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <pthread.h>
+int
+main ()
+{
+int i = PTHREAD_PRIO_INHERIT;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ax_cv_PTHREAD_PRIO_INHERIT=yes
+else
+  ax_cv_PTHREAD_PRIO_INHERIT=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5
+$as_echo "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; }
+        if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
+               test "x$ax_pthread_prio_inherit_defined" != "xyes"; then :
+
+$as_echo "#define HAVE_PTHREAD_PRIO_INHERIT 1" >>confdefs.h
+
+               ax_pthread_prio_inherit_defined=yes
+
+fi
+
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
+
+        # More AIX lossage: compile with *_r variant
+        if test "x$GCC" != "xyes"; then
+            case $host_os in
+                aix*)
+                case "x/$CC" in #(
+  x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6) :
+    #handle absolute path differently from PATH based program lookup
+                     case "x$CC" in #(
+  x/*) :
+    if as_fn_executable_p ${CC}_r; then :
+  PTHREAD_CC="${CC}_r"
+fi ;; #(
+  *) :
+    for ac_prog in ${CC}_r
+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_PTHREAD_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$PTHREAD_CC"; then
+  ac_cv_prog_PTHREAD_CC="$PTHREAD_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_PTHREAD_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
+PTHREAD_CC=$ac_cv_prog_PTHREAD_CC
+if test -n "$PTHREAD_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5
+$as_echo "$PTHREAD_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$PTHREAD_CC" && break
+done
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+ ;;
+esac ;; #(
+  *) :
+     ;;
+esac
+                ;;
+            esac
+        fi
+fi
+
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+
+
+
+
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test "x$ax_pthread_ok" = "xyes"; then
+
+$as_echo "#define HAVE_PTHREAD 1" >>confdefs.h
+
+        :
+else
+        ax_pthread_ok=no
+
+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
+
+
+
+# Specify a location for JDK
+enable_gprofng_jp=
+jdk_inc=
+
+# Check whether --with-jdk was given.
+if test "${with_jdk+set}" = set; then :
+  withval=$with_jdk;
+fi
+
+
+if test "x$with_jdk" != x; then
+  jdk_inc="-I$with_jdk/include -I$with_jdk/include/linux"
+  enable_gprofng_jp=yes
+else
+  # Extract the first word of "javac", so it can be a program name with args.
+set dummy javac; 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_path_JAVAC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $JAVAC in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_JAVAC="$JAVAC" # Let the user override the test with a path.
+  ;;
+  *)
+  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_path_JAVAC="$as_dir/$ac_word$ac_exec_ext"
+    $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
+
+  test -z "$ac_cv_path_JAVAC" && ac_cv_path_JAVAC="javac"
+  ;;
+esac
+fi
+JAVAC=$ac_cv_path_JAVAC
+if test -n "$JAVAC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAVAC" >&5
+$as_echo "$JAVAC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  if test -f $JAVAC; then
+    x=`readlink -f $JAVAC`
+    x=`dirname $x`
+    x=`dirname $x`
+    if ! test -f $x/include/jni.h; then
+      x=`dirname $x`
+    fi
+    if test -f $x/include/jni.h; then
+      jdk_inc="-I$x/include -I$x/include/linux"
+      enable_gprofng_jp=yes
+    fi
+  fi
+fi
+if test "x$enable_gprofng_jp" = x; then
+  # Extract the first word of "java", so it can be a program name with args.
+set dummy java; 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_path_JAVA+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $JAVA in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_JAVA="$JAVA" # Let the user override the test with a path.
+  ;;
+  *)
+  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_path_JAVA="$as_dir/$ac_word$ac_exec_ext"
+    $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
+
+  test -z "$ac_cv_path_JAVA" && ac_cv_path_JAVA="java"
+  ;;
+esac
+fi
+JAVA=$ac_cv_path_JAVA
+if test -n "$JAVA"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAVA" >&5
+$as_echo "$JAVA" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  if test -f $JAVA; then
+    x=`readlink -f $JAVA`
+    x=`dirname $x`
+    x=`dirname $x`
+    if ! test -f $x/include/jni.h; then
+      x=`dirname $x`
+    fi
+    if test -f $x/include/jni.h; then
+      jdk_inc="-I$x/include -I$x/include/linux"
+      enable_gprofng_jp=yes
+    fi
+  fi
+fi
+if test "x$enable_gprofng_jp" = x; then
+  ac_fn_c_check_header_compile "$LINENO" "jni.h" "ac_cv_header_jni_h" "
+"
+if test "x$ac_cv_header_jni_h" = xyes; then :
+   enable_gprofng_jp=yes
+fi
+
+
+fi
+if test "x$enable_gprofng_jp" = x; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING:  Cannot find the JDK include directory.
+      gprofng will be build without support for profiling Java applications.
+      Use --with-jdk=PATH to specify directory for the installed JDK" >&5
+$as_echo "$as_me: WARNING:  Cannot find the JDK include directory.
+      gprofng will be build without support for profiling Java applications.
+      Use --with-jdk=PATH to specify directory for the installed JDK" >&2;}
+else
+
+$as_echo "#define GPROFNG_JAVA_PROFILING 1" >>confdefs.h
+
+fi
+
+
+DEBUG=
+ # Check whether --enable-gprofng-debug was given.
+if test "${enable_gprofng_debug+set}" = set; then :
+  enableval=$enable_gprofng_debug;
+      case "$enableval" in
+       yes|no) ;;
+       *) as_fn_error $? "Argument to enable/disable gprofng-debug must be yes or no" "$LINENO" 5 ;;
+      esac
+
+else
+  enable_gprofng_debug=no
+fi
+
+
+if test "${enable_gprofng_debug}" = yes; then
+
+$as_echo "#define DEBUG 1" >>confdefs.h
+
+fi
+
+# Check if linker supports --as-needed and --no-as-needed options.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking linker --as-needed support" >&5
+$as_echo_n "checking linker --as-needed support... " >&6; }
+if ${bfd_cv_ld_as_needed+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  bfd_cv_ld_as_needed=no
+       if $LD --help 2>/dev/null | grep as-needed > /dev/null; then
+               bfd_cv_ld_as_needed=yes
+       fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $bfd_cv_ld_as_needed" >&5
+$as_echo "$bfd_cv_ld_as_needed" >&6; }
+
+no_as_needed=
+if test x"$bfd_cv_ld_as_needed" = xyes; then
+    no_as_needed='-Wl,--no-as-needed'
+fi
+
+# Extract the first word of "expect", so it can be a program name with args.
+set dummy expect; 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_path_EXPECT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $EXPECT in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_EXPECT="$EXPECT" # Let the user override the test with a path.
+  ;;
+  *)
+  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_path_EXPECT="$as_dir/$ac_word$ac_exec_ext"
+    $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
+
+  ;;
+esac
+fi
+EXPECT=$ac_cv_path_EXPECT
+if test -n "$EXPECT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $EXPECT" >&5
+$as_echo "$EXPECT" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for Tcl supporting try/catch" >&5
+$as_echo_n "checking for Tcl supporting try/catch... " >&6; }
+if ${ac_cv_libctf_tcl_try+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_libctf_tcl_try=`if test -z $EXPECT; then echo no; else $EXPECT << EOF
+if [llength [info commands try]] then { puts yes } else { puts no }
+EOF
+fi`
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libctf_tcl_try" >&5
+$as_echo "$ac_cv_libctf_tcl_try" >&6; }
+ if test "${ac_cv_libctf_tcl_try}" = yes; then
+  TCL_TRY_TRUE=
+  TCL_TRY_FALSE='#'
+else
+  TCL_TRY_TRUE='#'
+  TCL_TRY_FALSE=
+fi
+
+
+
+# Generate manpages, if possible.
+if test $cross_compiling = no; then
+
+HELP2MAN=${HELP2MAN-"${am_missing_run}help2man"}
+
+  build_man=true
+else
+  build_man=false
+fi
+ if test x$build_man = xtrue; then
+  BUILD_MAN_TRUE=
+  BUILD_MAN_FALSE='#'
+else
+  BUILD_MAN_TRUE='#'
+  BUILD_MAN_FALSE=
+fi
+
+
+LD_NO_AS_NEEDED=${no_as_needed}
+
+GPROFNG_CFLAGS=${gprofng_cflags}
+
+GPROFNG_CPPFLAGS=${gprofng_cppflags}
+
+GPROFNG_LIBDIR=${libdir}
+
+
+ac_fn_c_check_decl "$LINENO" "basename" "ac_cv_have_decl_basename" "$ac_includes_default"
+if test "x$ac_cv_have_decl_basename" = xyes; then :
+  ac_have_decl=1
+else
+  ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_BASENAME $ac_have_decl
+_ACEOF
+
+for ac_func in strsignal
+do :
+  ac_fn_c_check_func "$LINENO" "strsignal" "ac_cv_func_strsignal"
+if test "x$ac_cv_func_strsignal" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_STRSIGNAL 1
+_ACEOF
+
+fi
+done
+
+
+
+
+ac_config_files="$ac_config_files Makefile src/Makefile gp-display-html/Makefile doc/Makefile"
+
+ac_config_headers="$ac_config_headers 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
+if test -z "${BUILD_COLLECTOR_TRUE}" && test -z "${BUILD_COLLECTOR_FALSE}"; then
+  as_fn_error $? "conditional \"BUILD_COLLECTOR\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUILD_SRC_TRUE}" && test -z "${BUILD_SRC_FALSE}"; then
+  as_fn_error $? "conditional \"BUILD_SRC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${RUN_TESTS_TRUE}" && test -z "${RUN_TESTS_FALSE}"; then
+  as_fn_error $? "conditional \"RUN_TESTS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${TCL_TRY_TRUE}" && test -z "${TCL_TRY_FALSE}"; then
+  as_fn_error $? "conditional \"TCL_TRY\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BUILD_MAN_TRUE}" && test -z "${BUILD_MAN_FALSE}"; then
+  as_fn_error $? "conditional \"BUILD_MAN\" 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'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $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" ;;
+    "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;;
+    "gp-display-html/Makefile") CONFIG_FILES="$CONFIG_FILES gp-display-html/Makefile" ;;
+    "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
+    "config.h") CONFIG_HEADERS="$CONFIG_HEADERS 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 = "\a"
+
+}
+{
+  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 = "\a"
+}
+/^[\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
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# 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
+
+#
+# CONFIG_SUBDIRS section.
+#
+if test "$no_recursion" != yes; then
+
+  # Remove --cache-file, --srcdir, and --disable-option-checking arguments
+  # so they do not pile up.
+  ac_sub_configure_args=
+  ac_prev=
+  eval "set x $ac_configure_args"
+  shift
+  for ac_arg
+  do
+    if test -n "$ac_prev"; then
+      ac_prev=
+      continue
+    fi
+    case $ac_arg in
+    -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=*)
+      ;;
+    --config-cache | -C)
+      ;;
+    -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+      ac_prev=srcdir ;;
+    -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+      ;;
+    -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+      ac_prev=prefix ;;
+    -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+      ;;
+    --disable-option-checking)
+      ;;
+    *)
+      case $ac_arg in
+      *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+      esac
+      as_fn_append ac_sub_configure_args " '$ac_arg'" ;;
+    esac
+  done
+
+  # Always prepend --prefix to ensure using the same prefix
+  # in subdir configurations.
+  ac_arg="--prefix=$prefix"
+  case $ac_arg in
+  *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+  esac
+  ac_sub_configure_args="'$ac_arg' $ac_sub_configure_args"
+
+  # Pass --silent
+  if test "$silent" = yes; then
+    ac_sub_configure_args="--silent $ac_sub_configure_args"
+  fi
+
+  # Always prepend --disable-option-checking to silence warnings, since
+  # different subdirs can have different --enable and --with options.
+  ac_sub_configure_args="--disable-option-checking $ac_sub_configure_args"
+
+  ac_popdir=`pwd`
+  for ac_dir in : $subdirs; do test "x$ac_dir" = x: && continue
+
+    # Do not complain, so a configure script can configure whichever
+    # parts of a large source tree are present.
+    test -d "$srcdir/$ac_dir" || continue
+
+    ac_msg="=== configuring in $ac_dir (`pwd`/$ac_dir)"
+    $as_echo "$as_me:${as_lineno-$LINENO}: $ac_msg" >&5
+    $as_echo "$ac_msg" >&6
+    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
+
+
+    cd "$ac_dir"
+
+    # Check for guested configure; otherwise get Cygnus style configure.
+    if test -f "$ac_srcdir/configure.gnu"; then
+      ac_sub_configure=$ac_srcdir/configure.gnu
+    elif test -f "$ac_srcdir/configure"; then
+      ac_sub_configure=$ac_srcdir/configure
+    elif test -f "$ac_srcdir/configure.in"; then
+      # This should be Cygnus configure.
+      ac_sub_configure=$ac_aux_dir/configure
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: no configuration information is in $ac_dir" >&5
+$as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2;}
+      ac_sub_configure=
+    fi
+
+    # The recursion is here.
+    if test -n "$ac_sub_configure"; then
+      # Make the cache file name correct relative to the subdirectory.
+      case $cache_file in
+      [\\/]* | ?:[\\/]* ) ac_sub_cache_file=$cache_file ;;
+      *) # Relative name.
+       ac_sub_cache_file=$ac_top_build_prefix$cache_file ;;
+      esac
+
+      { $as_echo "$as_me:${as_lineno-$LINENO}: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&5
+$as_echo "$as_me: running $SHELL $ac_sub_configure $ac_sub_configure_args --cache-file=$ac_sub_cache_file --srcdir=$ac_srcdir" >&6;}
+      # The eval makes quoting arguments work.
+      eval "\$SHELL \"\$ac_sub_configure\" $ac_sub_configure_args \
+          --cache-file=\"\$ac_sub_cache_file\" --srcdir=\"\$ac_srcdir\"" ||
+       as_fn_error $? "$ac_sub_configure failed for $ac_dir" "$LINENO" 5
+    fi
+
+    cd "$ac_popdir"
+  done
+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/configure.ac b/gprofng/configure.ac
new file mode 100644 (file)
index 0000000..8977e8b
--- /dev/null
@@ -0,0 +1,189 @@
+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)
+AM_INIT_AUTOMAKE([subdir-objects])
+AM_MAINTAINER_MODE
+
+AC_USE_SYSTEM_EXTENSIONS
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+AM_PROG_AR
+
+AC_DISABLE_SHARED
+LT_INIT
+
+GPROFNG_LIBADD="-L../../libiberty -liberty"
+if test "$enable_shared" = "yes"; then
+  GPROFNG_LIBADD="-L../../libiberty/pic -liberty"
+fi
+AC_SUBST(GPROFNG_LIBADD)
+
+# Figure out what compiler warnings we can enable.
+# See config/warnings.m4 for details.
+
+ACX_PROG_CC_WARNINGS_ARE_ERRORS([manual])
+ACX_PROG_CC_WARNING_OPTS([-Wall], [gprofng_cflags])
+gprofng_cppflags="-U_ASM"
+build_collector=
+build_src=
+
+# This is annoying: it means we have to pass --enable-shared explicitly to
+# get gprofng, while the configure default is supposed to be that shared libs
+# are on by default.  But as long as libiberty has code like this, so must
+# we...
+
+  case "${target}" in
+    x86_64-*-linux*)
+      build_src=true
+      build_collector=true
+      ;;
+    i?86-*-linux*)
+      build_collector=true
+      build_collector=true
+      ;;
+    aarch64-*-linux*)
+      build_src=true
+      build_collector=true
+      ;;
+  esac
+  AC_ARG_ENABLE(gprofng-tools,
+    AS_HELP_STRING([--disable-gprofng-tools], [do not build gprofng/src directory]),
+    build_src=$enableval)
+
+AM_CONDITIONAL([BUILD_COLLECTOR], [test x$build_collector = xtrue])
+AM_CONDITIONAL([BUILD_SRC], [test x$build_src = xtrue])
+
+run_tests=false
+if test x$build_collector = xtrue; then
+  AC_CONFIG_SUBDIRS([libcollector])
+  if test x${host} = x${target}; then
+    run_tests=true
+  fi
+fi
+AM_CONDITIONAL([RUN_TESTS], [test x$run_tests = xtrue])
+AX_PTHREAD
+
+# Specify a location for JDK
+enable_gprofng_jp=
+jdk_inc=
+AC_ARG_WITH(jdk,
+[AS_HELP_STRING([--with-jdk=PATH],
+               [specify prefix directory for installed JDK.])])
+
+if test "x$with_jdk" != x; then
+  jdk_inc="-I$with_jdk/include -I$with_jdk/include/linux"
+  enable_gprofng_jp=yes
+else
+  AC_PATH_PROG([JAVAC], [javac], [javac])
+  if test -f $JAVAC; then
+    x=`readlink -f $JAVAC`
+    x=`dirname $x`
+    x=`dirname $x`
+    if ! test -f $x/include/jni.h; then
+      x=`dirname $x`
+    fi
+    if test -f $x/include/jni.h; then
+      jdk_inc="-I$x/include -I$x/include/linux"
+      enable_gprofng_jp=yes
+    fi
+  fi
+fi
+if test "x$enable_gprofng_jp" = x; then
+  AC_PATH_PROG([JAVA], [java], [java])
+  if test -f $JAVA; then
+    x=`readlink -f $JAVA`
+    x=`dirname $x`
+    x=`dirname $x`
+    if ! test -f $x/include/jni.h; then
+      x=`dirname $x`
+    fi
+    if test -f $x/include/jni.h; then
+      jdk_inc="-I$x/include -I$x/include/linux"
+      enable_gprofng_jp=yes
+    fi
+  fi
+fi
+if test "x$enable_gprofng_jp" = x; then
+  AC_CHECK_HEADER([jni.h], [ enable_gprofng_jp=yes ], [], [] )
+fi
+if test "x$enable_gprofng_jp" = x; then
+    AC_MSG_WARN([ Cannot find the JDK include directory.
+      gprofng will be build without support for profiling Java applications.
+      Use --with-jdk=PATH to specify directory for the installed JDK])
+else
+    AC_DEFINE(GPROFNG_JAVA_PROFILING, 1, [Enable java profiling])
+fi
+AC_SUBST(jdk_inc)
+
+DEBUG=
+GCC_ENABLE([gprofng-debug], [no], [], [Enable debugging output])
+if test "${enable_gprofng_debug}" = yes; then
+    AC_DEFINE(DEBUG, 1, [Enable debugging output.])
+fi
+
+# Check if linker supports --as-needed and --no-as-needed options.
+AC_CACHE_CHECK(linker --as-needed support, bfd_cv_ld_as_needed,
+       [bfd_cv_ld_as_needed=no
+       if $LD --help 2>/dev/null | grep as-needed > /dev/null; then
+               bfd_cv_ld_as_needed=yes
+       fi
+       ])
+
+no_as_needed=
+if test x"$bfd_cv_ld_as_needed" = xyes; then
+    no_as_needed='-Wl,--no-as-needed'
+fi
+
+AC_PATH_PROG([EXPECT], [expect])
+AC_CACHE_CHECK([for Tcl supporting try/catch], [ac_cv_libctf_tcl_try],
+  [ac_cv_libctf_tcl_try=`if test -z $EXPECT; then echo no; else $EXPECT << EOF
+if @<:@llength @<:@info commands try@:>@@:>@ then { puts yes } else { puts no }
+EOF
+fi`
+])
+AM_CONDITIONAL(TCL_TRY, test "${ac_cv_libctf_tcl_try}" = yes)
+
+
+# Generate manpages, if possible.
+if test $cross_compiling = no; then
+  AM_MISSING_PROG(HELP2MAN, help2man)
+  build_man=true
+else
+  build_man=false
+fi
+AM_CONDITIONAL([BUILD_MAN], [test x$build_man = xtrue])
+
+AC_SUBST(LD_NO_AS_NEEDED, [${no_as_needed}])
+AC_SUBST(GPROFNG_CFLAGS, [${gprofng_cflags}])
+AC_SUBST(GPROFNG_CPPFLAGS, [${gprofng_cppflags}])
+AC_SUBST(GPROFNG_LIBDIR, [${libdir}])
+
+AC_CHECK_DECLS([basename])
+AC_CHECK_FUNCS([strsignal])
+
+AC_SUBST(BUILD_SUBDIRS)
+
+AC_CONFIG_FILES([Makefile src/Makefile gp-display-html/Makefile doc/Makefile])
+AC_CONFIG_HEADERS([config.h:common/config.h.in])
+
+AC_OUTPUT
+
diff --git a/gprofng/doc/Makefile.am b/gprofng/doc/Makefile.am
new file mode 100644 (file)
index 0000000..3dc2cac
--- /dev/null
@@ -0,0 +1,37 @@
+## Process this file with automake to generate Makefile.in
+#
+#   Copyright (C) 2012-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 no-texinfo.tex
+
+info_TEXINFOS       = gprofng.texi
+gprofng_TEXINFOS    = fdl.texi
+BUILT_SOURCES       = version.texi
+CLEANFILES          = version.texi
+TEXINFO_TEX         = .
+MAKEINFOHTML        = $(MAKEINFO) --html --no-split
+
+version.texi: 
+       @echo "@set EDITION 1.0"                    > $@
+       @echo "@set VERSION 1.0"                   >> $@
+       @echo "@set UPDATED 22 February 2022"      >> $@
+       @echo "@set UPDATED-MONTH February 2022"   >> $@
+#      @echo "@set UPDATED `date +"%-d %B %Y"`"   >> $@
+#      @echo "@set UPDATED-MONTH `date +"%B %Y"`" >> $@
+
+MAINTAINERCLEANFILES = gprofng.info
diff --git a/gprofng/doc/Makefile.in b/gprofng/doc/Makefile.in
new file mode 100644 (file)
index 0000000..31e298c
--- /dev/null
@@ -0,0 +1,834 @@
+# 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) 2012-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 = doc
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../libtool.m4 \
+       $(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
+       $(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+       $(top_srcdir)/acinclude.m4 $(top_srcdir)/../config/warnings.m4 \
+       $(top_srcdir)/../config/enable.m4 \
+       $(top_srcdir)/../config/ax_pthread.m4 \
+       $(top_srcdir)/config/bison.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 $(srcdir)/version.texi \
+       $(srcdir)/stamp-vti $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+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 = 
+SOURCES =
+DIST_SOURCES =
+AM_V_DVIPS = $(am__v_DVIPS_@AM_V@)
+am__v_DVIPS_ = $(am__v_DVIPS_@AM_DEFAULT_V@)
+am__v_DVIPS_0 = @echo "  DVIPS   " $@;
+am__v_DVIPS_1 = 
+AM_V_MAKEINFO = $(am__v_MAKEINFO_@AM_V@)
+am__v_MAKEINFO_ = $(am__v_MAKEINFO_@AM_DEFAULT_V@)
+am__v_MAKEINFO_0 = @echo "  MAKEINFO" $@;
+am__v_MAKEINFO_1 = 
+AM_V_INFOHTML = $(am__v_INFOHTML_@AM_V@)
+am__v_INFOHTML_ = $(am__v_INFOHTML_@AM_DEFAULT_V@)
+am__v_INFOHTML_0 = @echo "  INFOHTML" $@;
+am__v_INFOHTML_1 = 
+AM_V_TEXI2DVI = $(am__v_TEXI2DVI_@AM_V@)
+am__v_TEXI2DVI_ = $(am__v_TEXI2DVI_@AM_DEFAULT_V@)
+am__v_TEXI2DVI_0 = @echo "  TEXI2DVI" $@;
+am__v_TEXI2DVI_1 = 
+AM_V_TEXI2PDF = $(am__v_TEXI2PDF_@AM_V@)
+am__v_TEXI2PDF_ = $(am__v_TEXI2PDF_@AM_DEFAULT_V@)
+am__v_TEXI2PDF_0 = @echo "  TEXI2PDF" $@;
+am__v_TEXI2PDF_1 = 
+AM_V_texinfo = $(am__v_texinfo_@AM_V@)
+am__v_texinfo_ = $(am__v_texinfo_@AM_DEFAULT_V@)
+am__v_texinfo_0 = -q
+am__v_texinfo_1 = 
+AM_V_texidevnull = $(am__v_texidevnull_@AM_V@)
+am__v_texidevnull_ = $(am__v_texidevnull_@AM_DEFAULT_V@)
+am__v_texidevnull_0 = > /dev/null
+am__v_texidevnull_1 = 
+INFO_DEPS = $(srcdir)/gprofng.info
+am__TEXINFO_TEX_DIR = $(srcdir)/.
+DVIS = gprofng.dvi
+PDFS = gprofng.pdf
+PSS = gprofng.ps
+HTMLS = gprofng.html
+TEXINFOS = gprofng.texi
+TEXI2DVI = texi2dvi
+TEXI2PDF = $(TEXI2DVI) --pdf --batch
+AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS)
+DVIPS = dvips
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+am__installdirs = "$(DESTDIR)$(infodir)"
+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__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(gprofng_TEXINFOS) $(srcdir)/Makefile.in \
+       $(top_srcdir)/../mkinstalldirs mdate-sh texinfo.tex
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_SUBDIRS = @BUILD_SUBDIRS@
+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@
+EXPECT = @EXPECT@
+FGREP = @FGREP@
+GPROFNG_CFLAGS = @GPROFNG_CFLAGS@
+GPROFNG_CPPFLAGS = @GPROFNG_CPPFLAGS@
+GPROFNG_LIBADD = @GPROFNG_LIBADD@
+GPROFNG_LIBDIR = @GPROFNG_LIBDIR@
+GREP = @GREP@
+HELP2MAN = @HELP2MAN@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA = @JAVA@
+JAVAC = @JAVAC@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LD_NO_AS_NEEDED = @LD_NO_AS_NEEDED@
+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@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WERROR = @WERROR@
+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@
+ax_pthread_config = @ax_pthread_config@
+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@
+gprofng_cflags = @gprofng_cflags@
+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@
+jdk_inc = @jdk_inc@
+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@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = foreign no-texinfo.tex
+info_TEXINFOS = gprofng.texi
+gprofng_TEXINFOS = fdl.texi
+BUILT_SOURCES = version.texi
+CLEANFILES = version.texi
+TEXINFO_TEX = .
+MAKEINFOHTML = $(MAKEINFO) --html --no-split
+#      @echo "@set UPDATED `date +"%-d %B %Y"`"   >> $@
+#      @echo "@set UPDATED-MONTH `date +"%B %Y"`" >> $@
+MAINTAINERCLEANFILES = gprofng.info
+all: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .dvi .html .info .pdf .ps .texi
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign doc/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+.texi.info:
+       $(AM_V_MAKEINFO)restore=: && backupdir="$(am__leading_dot)am$$$$" && \
+       am__cwd=`pwd` && $(am__cd) $(srcdir) && \
+       rm -rf $$backupdir && mkdir $$backupdir && \
+       if ($(MAKEINFO) --version) >/dev/null 2>&1; then \
+         for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \
+           if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \
+         done; \
+       else :; fi && \
+       cd "$$am__cwd"; \
+       if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+        -o $@ $<; \
+       then \
+         rc=0; \
+         $(am__cd) $(srcdir); \
+       else \
+         rc=$$?; \
+         $(am__cd) $(srcdir) && \
+         $$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \
+       fi; \
+       rm -rf $$backupdir; exit $$rc
+
+.texi.dvi:
+       $(AM_V_TEXI2DVI)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+       MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
+       $(TEXI2DVI) $(AM_V_texinfo) --build-dir=$(@:.dvi=.t2d) -o $@ $(AM_V_texidevnull) \
+       $<
+
+.texi.pdf:
+       $(AM_V_TEXI2PDF)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+       MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
+       $(TEXI2PDF) $(AM_V_texinfo) --build-dir=$(@:.pdf=.t2p) -o $@ $(AM_V_texidevnull) \
+       $<
+
+.texi.html:
+       $(AM_V_MAKEINFO)rm -rf $(@:.html=.htp)
+       $(AM_V_at)if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
+        -o $(@:.html=.htp) $<; \
+       then \
+         rm -rf $@ && mv $(@:.html=.htp) $@; \
+       else \
+         rm -rf $(@:.html=.htp); exit 1; \
+       fi
+$(srcdir)/gprofng.info: gprofng.texi $(srcdir)/version.texi $(gprofng_TEXINFOS)
+gprofng.dvi: gprofng.texi $(srcdir)/version.texi $(gprofng_TEXINFOS)
+gprofng.pdf: gprofng.texi $(srcdir)/version.texi $(gprofng_TEXINFOS)
+gprofng.html: gprofng.texi $(srcdir)/version.texi $(gprofng_TEXINFOS)
+$(srcdir)/version.texi: @MAINTAINER_MODE_TRUE@ $(srcdir)/stamp-vti
+$(srcdir)/stamp-vti: gprofng.texi $(top_srcdir)/configure
+       @(dir=.; test -f ./gprofng.texi || dir=$(srcdir); \
+       set `$(SHELL) $(srcdir)/mdate-sh $$dir/gprofng.texi`; \
+       echo "@set UPDATED $$1 $$2 $$3"; \
+       echo "@set UPDATED-MONTH $$2 $$3"; \
+       echo "@set EDITION $(VERSION)"; \
+       echo "@set VERSION $(VERSION)") > vti.tmp$$$$ && \
+       (cmp -s vti.tmp$$$$ $(srcdir)/version.texi \
+         || (echo "Updating $(srcdir)/version.texi" && \
+             cp vti.tmp$$$$ $(srcdir)/version.texi.tmp$$$$ && \
+             mv $(srcdir)/version.texi.tmp$$$$ $(srcdir)/version.texi)) && \
+       rm -f vti.tmp$$$$ $(srcdir)/version.texi.$$$$
+       @cp $(srcdir)/version.texi $@
+
+mostlyclean-vti:
+       -rm -f vti.tmp* $(srcdir)/version.texi.tmp*
+
+maintainer-clean-vti:
+@MAINTAINER_MODE_TRUE@ -rm -f $(srcdir)/stamp-vti $(srcdir)/version.texi
+.dvi.ps:
+       $(AM_V_DVIPS)TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
+       $(DVIPS) $(AM_V_texinfo) -o $@ $<
+
+uninstall-dvi-am:
+       @$(NORMAL_UNINSTALL)
+       @list='$(DVIS)'; test -n "$(dvidir)" || list=; \
+       for p in $$list; do \
+         $(am__strip_dir) \
+         echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \
+         rm -f "$(DESTDIR)$(dvidir)/$$f"; \
+       done
+
+uninstall-html-am:
+       @$(NORMAL_UNINSTALL)
+       @list='$(HTMLS)'; test -n "$(htmldir)" || list=; \
+       for p in $$list; do \
+         $(am__strip_dir) \
+         echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \
+         rm -rf "$(DESTDIR)$(htmldir)/$$f"; \
+       done
+
+uninstall-info-am:
+       @$(PRE_UNINSTALL)
+       @if test -d '$(DESTDIR)$(infodir)' && $(am__can_run_installinfo); then \
+         list='$(INFO_DEPS)'; \
+         for file in $$list; do \
+           relfile=`echo "$$file" | sed 's|^.*/||'`; \
+           echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \
+           if install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \
+           then :; else test ! -f "$(DESTDIR)$(infodir)/$$relfile" || exit 1; fi; \
+         done; \
+       else :; fi
+       @$(NORMAL_UNINSTALL)
+       @list='$(INFO_DEPS)'; \
+       for file in $$list; do \
+         relfile=`echo "$$file" | sed 's|^.*/||'`; \
+         relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \
+         (if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \
+            echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \
+            rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \
+          else :; fi); \
+       done
+
+uninstall-pdf-am:
+       @$(NORMAL_UNINSTALL)
+       @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \
+       for p in $$list; do \
+         $(am__strip_dir) \
+         echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \
+         rm -f "$(DESTDIR)$(pdfdir)/$$f"; \
+       done
+
+uninstall-ps-am:
+       @$(NORMAL_UNINSTALL)
+       @list='$(PSS)'; test -n "$(psdir)" || list=; \
+       for p in $$list; do \
+         $(am__strip_dir) \
+         echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \
+         rm -f "$(DESTDIR)$(psdir)/$$f"; \
+       done
+
+dist-info: $(INFO_DEPS)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+       list='$(INFO_DEPS)'; \
+       for base in $$list; do \
+         case $$base in \
+           $(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \
+         esac; \
+         if test -f $$base; then d=.; else d=$(srcdir); fi; \
+         base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \
+         for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \
+           if test -f $$file; then \
+             relfile=`expr "$$file" : "$$d/\(.*\)"`; \
+             test -f "$(distdir)/$$relfile" || \
+               cp -p $$file "$(distdir)/$$relfile"; \
+           else :; fi; \
+         done; \
+       done
+
+mostlyclean-aminfo:
+       -rm -rf gprofng.t2d gprofng.t2p
+
+clean-aminfo:
+       -test -z "gprofng.dvi gprofng.pdf gprofng.ps gprofng.html" \
+       || rm -rf gprofng.dvi gprofng.pdf gprofng.ps gprofng.html
+
+maintainer-clean-aminfo:
+       @list='$(INFO_DEPS)'; for i in $$list; do \
+         i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \
+         echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \
+         rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \
+       done
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+       $(MAKE) $(AM_MAKEFLAGS) \
+         top_distdir="$(top_distdir)" distdir="$(distdir)" \
+         dist-info
+check-am: all-am
+check: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(INFO_DEPS)
+installdirs:
+       for dir in "$(DESTDIR)$(infodir)"; do \
+         test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+       done
+install: $(BUILT_SOURCES)
+       $(MAKE) $(AM_MAKEFLAGS) 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:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+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."
+       -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-aminfo clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am: $(DVIS)
+
+html: html-am
+
+html-am: $(HTMLS)
+
+info: info-am
+
+info-am: $(INFO_DEPS)
+
+install-data-am: install-info-am
+
+install-dvi: install-dvi-am
+
+install-dvi-am: $(DVIS)
+       @$(NORMAL_INSTALL)
+       @list='$(DVIS)'; test -n "$(dvidir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(dvidir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(dvidir)" || 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_DATA) $$files '$(DESTDIR)$(dvidir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(dvidir)" || exit $$?; \
+       done
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am: $(HTMLS)
+       @$(NORMAL_INSTALL)
+       @list='$(HTMLS)'; list2=; test -n "$(htmldir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(htmldir)" || exit 1; \
+       fi; \
+       for p in $$list; do \
+         if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         $(am__strip_dir) \
+         d2=$$d$$p; \
+         if test -d "$$d2"; then \
+           echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \
+           $(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
+           echo " $(INSTALL_DATA) '$$d2'/* '$(DESTDIR)$(htmldir)/$$f'"; \
+           $(INSTALL_DATA) "$$d2"/* "$(DESTDIR)$(htmldir)/$$f" || exit $$?; \
+         else \
+           list2="$$list2 $$d2"; \
+         fi; \
+       done; \
+       test -z "$$list2" || { echo "$$list2" | $(am__base_list) | \
+       while read files; do \
+         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(htmldir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(htmldir)" || exit $$?; \
+       done; }
+install-info: install-info-am
+
+install-info-am: $(INFO_DEPS)
+       @$(NORMAL_INSTALL)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+       list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(infodir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(infodir)" || exit 1; \
+       fi; \
+       for file in $$list; do \
+         case $$file in \
+           $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+         esac; \
+         if test -f $$file; then d=.; else d=$(srcdir); fi; \
+         file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \
+         for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \
+                      $$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \
+           if test -f $$ifile; then \
+             echo "$$ifile"; \
+           else : ; fi; \
+         done; \
+       done | $(am__base_list) | \
+       while read files; do \
+         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(infodir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(infodir)" || exit $$?; done
+       @$(POST_INSTALL)
+       @if $(am__can_run_installinfo); then \
+         list='$(INFO_DEPS)'; test -n "$(infodir)" || list=; \
+         for file in $$list; do \
+           relfile=`echo "$$file" | sed 's|^.*/||'`; \
+           echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\
+           install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\
+         done; \
+       else : ; fi
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am: $(PDFS)
+       @$(NORMAL_INSTALL)
+       @list='$(PDFS)'; test -n "$(pdfdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(pdfdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(pdfdir)" || 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_DATA) $$files '$(DESTDIR)$(pdfdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(pdfdir)" || exit $$?; done
+install-ps: install-ps-am
+
+install-ps-am: $(PSS)
+       @$(NORMAL_INSTALL)
+       @list='$(PSS)'; test -n "$(psdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(psdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(psdir)" || 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_DATA) $$files '$(DESTDIR)$(psdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(psdir)" || exit $$?; done
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-aminfo \
+       maintainer-clean-generic maintainer-clean-vti
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-aminfo mostlyclean-generic \
+       mostlyclean-libtool mostlyclean-vti
+
+pdf: pdf-am
+
+pdf-am: $(PDFS)
+
+ps: ps-am
+
+ps-am: $(PSS)
+
+uninstall-am: uninstall-dvi-am uninstall-html-am uninstall-info-am \
+       uninstall-pdf-am uninstall-ps-am
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-aminfo clean-generic \
+       clean-libtool cscopelist-am ctags-am dist-info distclean \
+       distclean-generic distclean-libtool distdir 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-man install-pdf install-pdf-am \
+       install-ps install-ps-am install-strip installcheck \
+       installcheck-am installdirs maintainer-clean \
+       maintainer-clean-aminfo maintainer-clean-generic \
+       maintainer-clean-vti mostlyclean mostlyclean-aminfo \
+       mostlyclean-generic mostlyclean-libtool mostlyclean-vti pdf \
+       pdf-am ps ps-am tags-am uninstall uninstall-am \
+       uninstall-dvi-am uninstall-html-am uninstall-info-am \
+       uninstall-pdf-am uninstall-ps-am
+
+.PRECIOUS: Makefile
+
+
+version.texi: 
+       @echo "@set EDITION 1.0"                    > $@
+       @echo "@set VERSION 1.0"                   >> $@
+       @echo "@set UPDATED 22 February 2022"      >> $@
+       @echo "@set UPDATED-MONTH February 2022"   >> $@
+
+# 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/doc/fdl.texi b/gprofng/doc/fdl.texi
new file mode 100644 (file)
index 0000000..8805f1a
--- /dev/null
@@ -0,0 +1,506 @@
+@c The GNU Free Documentation License.
+@center Version 1.3, 3 November 2008
+
+@c This file is intended to be included within another document,
+@c hence no sectioning command or @node.
+
+@display
+Copyright @copyright{} 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
+@uref{http://fsf.org/}
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@enumerate 0
+@item
+PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document @dfn{free} in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of ``copyleft'', which means that derivative
+works of the document must themselves be free in the same sense.  It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does.  But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book.  We recommend this License
+principally for works whose purpose is instruction or reference.
+
+@item
+APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License.  Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein.  The ``Document'', below,
+refers to any such manual or work.  Any member of the public is a
+licensee, and is addressed as ``you''.  You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A ``Modified Version'' of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A ``Secondary Section'' is a named appendix or a front-matter section
+of the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject.  (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.)  The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The ``Invariant Sections'' are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License.  If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant.  The Document may contain zero
+Invariant Sections.  If the Document does not identify any Invariant
+Sections then there are none.
+
+The ``Cover Texts'' are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License.  A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A ``Transparent'' copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters.  A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text.  A copy that is not ``Transparent'' is called ``Opaque''.
+
+Examples of suitable formats for Transparent copies include plain
+@sc{ascii} without markup, Texinfo input format, La@TeX{} input
+format, @acronym{SGML} or @acronym{XML} using a publicly available
+@acronym{DTD}, and standard-conforming simple @acronym{HTML},
+PostScript or @acronym{PDF} designed for human modification.  Examples
+of transparent image formats include @acronym{PNG}, @acronym{XCF} and
+@acronym{JPG}.  Opaque formats include proprietary formats that can be
+read and edited only by proprietary word processors, @acronym{SGML} or
+@acronym{XML} for which the @acronym{DTD} and/or processing tools are
+not generally available, and the machine-generated @acronym{HTML},
+PostScript or @acronym{PDF} produced by some word processors for
+output purposes only.
+
+The ``Title Page'' means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page.  For works in
+formats which do not have any title page as such, ``Title Page'' means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+The ``publisher'' means any person or entity that distributes copies
+of the Document to the public.
+
+A section ``Entitled XYZ'' means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language.  (Here XYZ stands for a
+specific section name mentioned below, such as ``Acknowledgements'',
+``Dedications'', ``Endorsements'', or ``History''.)  To ``Preserve the Title''
+of such a section when you modify the Document means that it remains a
+section ``Entitled XYZ'' according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document.  These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+@item
+VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License.  You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute.  However, you may accept
+compensation in exchange for copies.  If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+@item
+COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover.  Both covers must also clearly and legibly identify
+you as the publisher of these copies.  The front cover must present
+the full title with all words of the title equally prominent and
+visible.  You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+@item
+MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it.  In addition, you must do these things in the Modified Version:
+
+@enumerate A
+@item
+Use in the Title Page (and on the covers, if any) a title distinct
+from that of the Document, and from those of previous versions
+(which should, if there were any, be listed in the History section
+of the Document).  You may use the same title as a previous version
+if the original publisher of that version gives permission.
+
+@item
+List on the Title Page, as authors, one or more persons or entities
+responsible for authorship of the modifications in the Modified
+Version, together with at least five of the principal authors of the
+Document (all of its principal authors, if it has fewer than five),
+unless they release you from this requirement.
+
+@item
+State on the Title page the name of the publisher of the
+Modified Version, as the publisher.
+
+@item
+Preserve all the copyright notices of the Document.
+
+@item
+Add an appropriate copyright notice for your modifications
+adjacent to the other copyright notices.
+
+@item
+Include, immediately after the copyright notices, a license notice
+giving the public permission to use the Modified Version under the
+terms of this License, in the form shown in the Addendum below.
+
+@item
+Preserve in that license notice the full lists of Invariant Sections
+and required Cover Texts given in the Document's license notice.
+
+@item
+Include an unaltered copy of this License.
+
+@item
+Preserve the section Entitled ``History'', Preserve its Title, and add
+to it an item stating at least the title, year, new authors, and
+publisher of the Modified Version as given on the Title Page.  If
+there is no section Entitled ``History'' in the Document, create one
+stating the title, year, authors, and publisher of the Document as
+given on its Title Page, then add an item describing the Modified
+Version as stated in the previous sentence.
+
+@item
+Preserve the network location, if any, given in the Document for
+public access to a Transparent copy of the Document, and likewise
+the network locations given in the Document for previous versions
+it was based on.  These may be placed in the ``History'' section.
+You may omit a network location for a work that was published at
+least four years before the Document itself, or if the original
+publisher of the version it refers to gives permission.
+
+@item
+For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
+the Title of the section, and preserve in the section all the
+substance and tone of each of the contributor acknowledgements and/or
+dedications given therein.
+
+@item
+Preserve all the Invariant Sections of the Document,
+unaltered in their text and in their titles.  Section numbers
+or the equivalent are not considered part of the section titles.
+
+@item
+Delete any section Entitled ``Endorsements''.  Such a section
+may not be included in the Modified Version.
+
+@item
+Do not retitle any existing section to be Entitled ``Endorsements'' or
+to conflict in title with any Invariant Section.
+
+@item
+Preserve any Warranty Disclaimers.
+@end enumerate
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant.  To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled ``Endorsements'', provided it contains
+nothing but endorsements of your Modified Version by various
+parties---for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version.  Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity.  If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+@item
+COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy.  If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled ``History''
+in the various original documents, forming one section Entitled
+``History''; likewise combine any sections Entitled ``Acknowledgements'',
+and any sections Entitled ``Dedications''.  You must delete all
+sections Entitled ``Endorsements.''
+
+@item
+COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+@item
+AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an ``aggregate'' if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+@item
+TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections.  You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers.  In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled ``Acknowledgements'',
+``Dedications'', or ``History'', the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+@item
+TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense, or distribute it is void, and
+will automatically terminate your rights under this License.
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, receipt of a copy of some or all of the same material does
+not give you any rights to use it.
+
+@item
+FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time.  Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.  See
+@uref{http://www.gnu.org/copyleft/}.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License ``or any later version'' applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation.  If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.  If the Document
+specifies that a proxy can decide which future versions of this
+License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the
+Document.
+
+@item
+RELICENSING
+
+``Massive Multiauthor Collaboration Site'' (or ``MMC Site'') means any
+World Wide Web server that publishes copyrightable works and also
+provides prominent facilities for anybody to edit those works.  A
+public wiki that anybody can edit is an example of such a server.  A
+``Massive Multiauthor Collaboration'' (or ``MMC'') contained in the
+site means any set of copyrightable works thus published on the MMC
+site.
+
+``CC-BY-SA'' means the Creative Commons Attribution-Share Alike 3.0
+license published by Creative Commons Corporation, a not-for-profit
+corporation with a principal place of business in San Francisco,
+California, as well as future copyleft versions of that license
+published by that same organization.
+
+``Incorporate'' means to publish or republish a Document, in whole or
+in part, as part of another Document.
+
+An MMC is ``eligible for relicensing'' if it is licensed under this
+License, and if all works that were first published under this License
+somewhere other than this MMC, and subsequently incorporated in whole
+or in part into the MMC, (1) had no cover texts or invariant sections,
+and (2) were thus incorporated prior to November 1, 2008.
+
+The operator of an MMC Site may republish an MMC contained in the site
+under CC-BY-SA on the same site at any time before August 1, 2009,
+provided the MMC is eligible for relicensing.
+
+@end enumerate
+
+@page
+@heading ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+@smallexample
+@group
+  Copyright (C)  @var{year}  @var{your name}.
+  Permission is granted to copy, distribute and/or modify this document
+  under the terms of the GNU Free Documentation License, Version 1.3
+  or any later version published by the Free Software Foundation;
+  with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+  Texts.  A copy of the license is included in the section entitled ``GNU
+  Free Documentation License''.
+@end group
+@end smallexample
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the ``with@dots{}Texts.'' line with this:
+
+@smallexample
+@group
+    with the Invariant Sections being @var{list their titles}, with
+    the Front-Cover Texts being @var{list}, and with the Back-Cover Texts
+    being @var{list}.
+@end group
+@end smallexample
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
+
+@c Local Variables:
+@c ispell-local-pdict: "ispell-dict"
+@c End:
+
diff --git a/gprofng/doc/gprofng.texi b/gprofng/doc/gprofng.texi
new file mode 100644 (file)
index 0000000..3e75a6c
--- /dev/null
@@ -0,0 +1,3399 @@
+\input texinfo @c -*-texinfo-*-
+
+@c ----------------------------------------------------------------------------
+@c This is the Texinfo source file for the GPROFNG manual.
+@c
+@c Author: Ruud van der Pas
+@c ----------------------------------------------------------------------------
+
+@c %**start of header
+
+@setfilename gprofng.info
+@settitle GNU gprofng
+
+@c -- Set the indent for the @example command to 1 space, not 5 ---------------
+@exampleindent 1
+
+@c %**end of header
+
+@c -- Start a new chapter on a new, odd numbered, page ------------------------
+@setchapternewpage odd
+
+@c -- Merge all index entries into the Concepts Index -------------------------
+@syncodeindex fn cp
+@syncodeindex ky cp
+@syncodeindex pg cp
+@syncodeindex vr cp
+
+@c -- Macro definitions -------------------------------------------------------
+@c
+@c Since only letters can be used, we use capitalization to distinguish
+@c different words.
+@c ----------------------------------------------------------------------------
+@macro CollectApp{}
+@command{gprofng collect app}
+@end macro
+
+@macro DisplayHTML{}
+@command{gprofng display html}
+@end macro
+
+@macro DisplayText{}
+@command{gprofng display text}
+@end macro
+
+@macro Driver{}
+@command{gprofng}
+@end macro
+
+@macro ProductName{}
+gprofng
+@end macro
+
+@macro ToolName{}
+@command{gprofng}
+@end macro
+
+@macro IndexSubentry{label, string}
+@c -- @cindex \label\ @subentry \string\
+@cindex \label\, \string\
+@end macro
+
+@c -- Get the version information ---------------------------------------------
+@include version.texi
+
+@c -- Entry for the Info dir structure ----------------------------------------
+@ifnottex
+@dircategory Software development
+@direntry
+* gprofng: (gprofng).                    The next generation profiling tool for Linux
+@end direntry
+@end ifnottex
+
+@c -- Copyright stuff ---------------------------------------------------------
+@copying
+This document is the manual for @ProductName{}, last updated @value{UPDATED}.
+
+Copyright @copyright{} 2022 Free Software Foundation, Inc.
+
+@c -- @quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License,
+Version 1.3 or any later version published by the Free Software
+Foundation; with no Invariant Sections, with no Front-Cover texts,
+and with no Back-Cover Texts.  A copy of the license is included in the
+section entitled ``GNU Free Documentation License.''
+
+@c -- @end quotation
+@end copying
+
+@finalout
+@smallbook
+
+@c -- Define the title page ---------------------------------------------------
+@titlepage
+@title GNU gprofng
+@subtitle The next generation profiling tool for Linux
+@subtitle version @value{VERSION} (last updated @value{UPDATED})
+@author Ruud van der Pas
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@c -- Generate the Table of Contents ------------------------------------------
+@contents
+
+@c -- The Top node ------------------------------------------------------------
+@c Should contain a short summary, copying permissions and a master menu.
+@c ----------------------------------------------------------------------------
+@ifnottex
+@node Top
+@top  GNU Gprofng
+
+@insertcopying
+@end ifnottex
+
+@ifinfo
+@c -- The menu entries --------------------------------------------------------
+
+@menu
+* Introduction::           About this manual.
+* Overview::               A brief overview of @ProductName{}.
+* A Mini Tutorial::        A short tutorial covering the key features.
+* Terminology::            Various concepts and some terminology explained.
+* Other Document Formats:: How to create this document in other formats.
+* Index::                  The index.
+
+@detailmenu
+
+--- The Detailed Node Listing ---
+
+Introduction
+
+Overview
+
+* Main Features::                     A high level overview.
+* Sampling versus Tracing::           The pros and cons of sampling versus tracing.
+* Steps Needed to Create a Profile::  How to create a profile.
+
+A Mini Tutorial
+
+* Getting Started::                 The basics of profiling with @ProductName().
+* Support for Multithreading::      Commands specific to multithreaded applications.
+* Viewing Multiple Experiments::    Analyze multiple experiments.
+* Profile Hardware Event Counters:: How to use hardware event counters.
+* Java Profiling::                  How to profile a Java application.
+
+Terminology
+
+* The Program Counter::                    What is a Program Counter?
+* Inclusive and Exclusive Metrics::        An explanation of inclusive and exclusive metrics.
+* Metric Definitions::                     Definitions associated with metrics.
+* The Viewmode::                           Select the way call stacks are presented.
+* The Selection List::                     How to define a selection.
+* Load Objects and Functions::             The components in an application.
+* The Concept of a CPU in @ProductName{}:: The definition of a CPU.
+* Hardware Event Counters Explained::      What are event counters?
+* apath::                                  Our generic definition of a path.
+
+@c -- Index
+
+@end detailmenu
+@end menu
+@end ifinfo
+
+@c -- A new node --------------------------------------------------------------
+@node    Introduction
+@chapter Introduction
+@c ----------------------------------------------------------------------------
+The @ProductName{} tool is the next generation profiler for Linux. It consists 
+of various commands to generate and display profile information.
+
+This manual starts with a tutorial how to create and interpret a profile. This
+part is highly practical and has the goal to get users up to speed as quickly
+as possible. As soon as possible, we would like to show you how to get your
+first profile on your screen.
+
+This is followed by more examples, covering many of the features. At the
+end of this tutorial, you should feel confident enough to tackle the more
+complex tasks.
+
+In a future update a more formal reference manual will be included as well.
+Since even in this tutorial we use certain terminology, we have included a
+chapter with descriptions at the end. In case you encounter unfamiliar 
+wordings or terminology, please check this chapter.
+
+One word of caution. In several cases we had to somewhat tweak the screen
+output in order to make it fit. This is why the output may look somewhat
+different when you try things yourself.
+
+For now, we wish you a smooth profiling experience with @ProductName{} and 
+good luck tackling performance bottlenecks.
+
+@c -- A new node --------------------------------------------------------------
+@c cccccc @node    A Brief Overview of @ProductName{}
+@node    Overview
+@chapter A Brief Overview of @ProductName{}
+@c ----------------------------------------------------------------------------
+
+@menu
+* Main Features::                     A high level overview.
+* Sampling versus Tracing::           The pros and cons of sampling versus tracing.
+* Steps Needed to Create a Profile::  How to create a profile.
+@end menu
+
+Before we cover this tool in quite some detail, we start with a brief overview
+of what it is, and the main features. Since we know that many of you would 
+like to get started rightaway, already in this first chapter we explain the
+basics of profiling with @ToolName{}.
+
+@c ----------------------------------------------------------------------------
+@c TBD Review this text. Probably be more specific on the gcc releases and
+@c processor specifics.
+@c ----------------------------------------------------------------------------
+
+@c -- A new node --------------------------------------------------------------
+@node    Main Features
+@section Main Features
+@c ----------------------------------------------------------------------------
+
+@noindent
+These are the main features of the @ProductName{} tool:
+
+@itemize @bullet
+
+@item
+Profiling is supported for an application written in C, C++, Java, or Scala.
+
+@c TBD Java: up to 1.8 full support, support other than for modules 
+
+@item
+Shared libraries are supported. The information is presented at the instruction
+level.
+
+@item
+The following multithreading programming models are supported: Pthreads,
+OpenMP, and Java threads.
+
+@item
+This tool works with unmodified production level executables. There is no need to 
+recompile the code, but if the @code{-g} option has been used when building
+the application, source line level information is available.
+
+@item
+The focus is on support for code generated with the @code{gcc} compiler, but 
+there is some limited support for the @code{icc} compiler as well. Future
+improvements and enhancements will focus on @code{gcc} though.
+
+@item
+Processors from Intel, AMD, and Arm are supported, but the level of support
+depends on the architectural details. In particular, hardware event counters
+may not be supported.
+
+@item 
+Several views into the data are supported. For example, a function overview
+where the time is spent, but also a source line, disassembly, call tree and 
+a caller-callees overview are available.
+
+@item
+Through filters, the user can zoom in on an area of interest.
+
+@item
+Two or more profiles can be aggregated, or used in a comparison. This comparison 
+can be obtained at the function, source line, and disassembly level.
+
+@item
+Through a scripting language, and customization of the metrics shown,
+the generation and creation of a profile can be fully automated and provide 
+tailored output.
+
+@end itemize
+
+@c -- A new node --------------------------------------------------------------
+@node    Sampling versus Tracing
+@section Sampling versus Tracing
+@c ----------------------------------------------------------------------------
+
+A key difference with some other profiling tools is that the main data 
+collection command @CollectApp{} mostly uses 
+@cindex Program Counter sampling
+@cindex PC sampling
+Program Counter (PC) sampling
+under the hood. 
+
+With @emph{sampling}, the executable is stopped at regular intervals. Each time
+it is halted, key information is gathered and stored. This includes the Program
+Counter that keeps track of where the execution is. Hence the name.
+
+Together with operational
+data, this information is stored in the experiment directory and can be
+viewed in the second phase.
+
+For example, the PC information is used to derive where the program was when
+it was halted. Since the sampling interval is known, it is relatively easy to 
+derive how much time was spent in the various parts of the program.
+
+The opposite technique is generally referred to as @emph{tracing}. With
+tracing, the target is instrumented with specific calls that collect the
+requested information.
+
+These are some of the pros and cons of PC sampling verus tracing:
+
+@itemize
+
+@item
+Since there is no need to recompile, existing executables can be used
+and the profile measures the behaviour of exactly the same executable that is
+used in production runs.
+
+With sampling, one inherently profiles a different executable because
+the calls to the instrumentation library may affect the compiler optimizations 
+and run time behaviour. 
+
+@item
+With sampling, there are very few restrictions on what can be profiled and even without
+access to the source code, a basic profile can be made.
+
+@item
+A downside of sampling is that, depending on the sampling frequency, small 
+functions may be missed or not captured accurately. Although this is rare, 
+this may happen and is the reason why the user has control over the sampling rate.
+
+@item
+While tracing produces precise information, sampling is statistical in nature.
+As a result, small variations may occur across seemingly identical runs. We
+have not observed more than a few percent deviation though. Especially if 
+the target job executed for a sufficiently long time.
+
+@item
+With sampling, it is not possible to get an accurate count how often
+functions are called.
+
+@end itemize
+
+@c -- A new node --------------------------------------------------------------
+@node    Steps Needed to Create a Profile
+@section Steps Needed to Create a Profile
+@c ----------------------------------------------------------------------------
+
+Creating a profile takes two steps. First the profile data needs to be 
+generated. This is followed by a viewing step to create a report from the
+information that has been gathered.
+
+Every @ProductName{} command starts with @ToolName{}, the name of the driver. This is followed
+by a keyword to define the high level functionality. Depending on this
+keyword, a third qualifier may be needed to further narrow down the request. 
+This combination is then followed by options that are specific to the functionality
+desired.
+
+The command to gather, or ``collect'', the performance data is called 
+@CollectApp{}. Aside from numerous options, this command takes the name
+of the target executable as an input parameter.
+
+Upon completion of the run, the performance data can be
+found in the newly created 
+@cindex Experiment directory
+experiment directory.
+
+Unless explicitly specified otherwise, a default
+name for this directory is chosen. The name is @code{test.<n>.er} where
+@code{n} is the first integer number not in use yet for such a name.
+
+For example, the first time @CollectApp{} is invoked, an experiment
+directory with the name @code{test.1.er} is created.
+
+Upon a subsequent invocation of @CollectApp{} in the same directory,
+an experiment directory with the name @code{test.2.er} will be created, 
+and so forth.
+
+Note that @CollectApp{} supports an option to explicitly name the experiment directory.
+Outside of the restriction that the name of this directory has to end
+with @code{.er}, any valid directory name can be used for this.
+
+Now that we have the performance data, the next step is to display it.
+
+@pindex @DisplayText{}
+The most commonly used command to view the performance information is 
+@DisplayText{}. This is a very extensive and customizable tool that 
+produces the information in ASCII format. 
+
+@pindex @DisplayHTML{}
+Another option is to use @DisplayHTML{}. This tool generates a directory with 
+files in html format. These can be viewed in a browser, allowing for easy 
+navigation through the profile data.
+
+@c -- A new node --------------------------------------------------------------
+@node    A Mini Tutorial 
+@chapter A Mini Tutorial 
+@c ----------------------------------------------------------------------------
+
+In this chapter we present and discuss the main functionality of @ToolName{}.
+This will be a practical approach, using an example code to generate profile
+data and show how to get various performance reports. 
+
+@menu
+* Getting Started::                 The basics of profiling with @ProductName().
+* Support for Multithreading::      Commands specific to multithreaded applications.
+* Viewing Multiple Experiments::    Analyze multiple experiments.
+* Profile Hardware Event Counters:: How to use hardware event counters.
+* Java Profiling::                  How to profile a Java application.
+@end menu
+
+@c -- A new node --------------------------------------------------------------
+@node    Getting Started
+@section Getting Started
+@c ----------------------------------------------------------------------------
+
+The information presented here provides a good and common basis for many 
+profiling tasks, but there are more features that you may want to leverage.
+
+These are covered in subsequent sections in this chapter.
+
+@menu
+* The Example Program::                        A description of the example program used.
+* A First Profile::                            How to get the first profile.
+* The Source Code View::                       Display the metrics in the source code.
+* The Disassembly View::                       Display the metrics at the instruction level.
+* Display and Define the Metrics::             An example how to customize the metrics.
+* A First Customization of the Output::        An example how to customize the output.
+* Name the Experiment Directory::              Change the name of the experiment directory.
+* Control the Number of Lines in the Output::  Change the number of lines in the tables.
+* Sorting the Performance Data::               How to set the metric to sort by.
+* Scripting::                                  Use a script to execute the commands.
+* A More Elaborate Example::                   An example of customization.
+* The Call Tree::                              Display the dynamic call tree.
+* More Information on the Experiment::         How to get additional statistics.
+* Control the Sampling Frequency::             How to control the sampling granularity.
+* Information on Load Objects::                How to get more information on load objects.
+@end menu
+
+@c -- A new node --------------------------------------------------------------
+@node       The Example Program
+@subsection The Example Program
+@c ----------------------------------------------------------------------------
+
+Throughout this guide we use the same example C code that implements the 
+multiplication of a vector of length @math{n} by an @math{m} by @math{n}
+matrix. The result is stored in a vector of length @math{m}. 
+@cindex Pthreads
+@cindex Posix Threads
+The algorithm has been parallelized using Posix Threads, or Pthreads for short.
+
+The code was built using the @code{gcc} compiler and the name of the executable 
+is
+@cindex mxv-pthreads.exe
+mxv-pthreads.exe.
+
+The matrix sizes can be set through the @code{-m} and @code{-n} options. The
+number of threads is set with the @code{-t} option. To increase the duration
+of the run, the multiplication is executed repeatedly. 
+
+This is an example that multiplies a @math{3000} by @math{2000} matrix with
+a vector of length @math{2000} using @math{2} threads:
+
+@smallexample
+@verbatim
+$ ./mxv-pthreads.exe -m 3000 -n 2000 -t 2
+mxv: error check passed - rows = 3000 columns = 2000 threads = 2
+$
+@end verbatim
+@end smallexample
+
+The program performs an internal check to verify the results are correct.
+The result of this check is printed, followed by the matrix sizes and the 
+number of threads used.
+
+@c -- A new node --------------------------------------------------------------
+@node       A First Profile
+@subsection A First Profile
+@c ----------------------------------------------------------------------------
+
+The first step is to collect the performance data. It is important to remember
+that much more information is gathered than may be shown by default. Often a
+single data collection run is sufficient to get a lot of insight.
+
+The @CollectApp{} command is used for the data collection. Nothing needs to be
+changed in the way the application is executed. The only difference is that it
+is now run under control of the tool, as shown below:
+
+@cartouche
+@smallexample
+$ gprofng collect app ./mxv.pthreads.exe -m 3000 -n 2000 -t 1
+@end smallexample
+@end cartouche
+
+This command produces the following output:
+
+@smallexample
+@verbatim
+Creating experiment database test.1.er (Process ID: 2416504) ...
+mxv: error check passed - rows = 3000 columns = 2000 threads = 1
+@end verbatim
+@end smallexample
+
+We see the message that a directory with the name @code{test.1.er} 
+has been created. 
+The application then completes as usual and we have our first experiment 
+directory that can be analyzed.
+
+The tool we use for this is called @DisplayText{}. It takes the name of
+the experiment directory as an argument.
+
+@cindex Interpreter mode 
+If invoked this way, the tool starts in the interactive @emph{interpreter} mode.
+While in this environment, commands can be given and the tool responds. This is
+illustrated below:
+
+@smallexample
+@verbatim
+$ gprofng display text test.1.er
+Warning: History and command editing is not supported on this system.
+(gp-display-text) quit
+$
+@end verbatim
+@end smallexample
+
+@cindex Command line mode 
+While useful in certain cases, we prefer to use this tool in command line mode,
+by specifying the commands to be issued when invoking the tool. The way to do
+this is to prepend the command with a hyphen (@code{-}) if used on the command
+line.
+
+For example,
+@IndexSubentry{Commands, @code{functions}}
+with the @code{functions} command we request a list of the functions that 
+have been executed and their respective CPU times:
+
+@cartouche
+@smallexample
+$ gprofng display text -functions test.1.er
+@end smallexample
+@end cartouche
+
+@smallexample
+@verbatim
+$ gprofng display text -functions test.1.er
+Functions sorted by metric: Exclusive Total CPU Time
+
+Excl.     Incl.      Name
+Total     Total
+CPU sec.  CPU sec.
+2.272     2.272      <Total>
+2.160     2.160      mxv_core
+0.047     0.103      init_data
+0.030     0.043      erand48_r
+0.013     0.013      __drand48_iterate
+0.013     0.056      drand48
+0.008     0.010      _int_malloc
+0.001     0.001      brk
+0.001     0.002      sysmalloc
+0.        0.001      __default_morecore
+0.        0.113      __libc_start_main
+0.        0.010      allocate_data
+0.        2.160      collector_root
+0.        2.160      driver_mxv
+0.        0.113      main
+0.        0.010      malloc
+0.        0.001      sbrk
+@end verbatim
+@end smallexample
+
+As easy and simple as these steps are, we do have a first profile of our program!
+There are three columns. The first two contain the 
+@cindex Total CPU time
+@emph{Total CPU Time}, 
+which 
+is the sum of the user and system time. @xref{Inclusive and Exclusive Metrics}
+for an explanation of ``exclusive'' and ``inclusive'' times.
+
+The first line echoes the metric that is used to sort the output. By default, this
+is the exclusive CPU time, but the sort metric can be changed by the user.
+
+We then see three columns with the exclusive and inclusive CPU times, plus the
+name of the function.
+
+@IndexSubentry{Miscellaneous, @code{<Total>}}
+The function with the name @code{<Total>} is not a user function, but is introduced
+by @ToolName{} and is used to display the accumulated metric values. In this case,
+we see that the total CPU time of this job was @code{2.272} seconds.
+
+With @code{2.160} seconds, function @code{mxv_core} is the most time 
+consuming function. It is also a leaf function.
+
+The next function in the list is @code{init_data}. Although the CPU time spent in
+this part is negligible, this is an interesting entry because the inclusive CPU
+time of @code{0.103} seconds is higher than the exclusive CPU time of @code{0.047}
+seconds. Clearly it is calling another function,
+or even more than one function. 
+@xref{The Call Tree} for the details how to get more information on this.
+
+The function @code{collector_root} does not look familiar. It is one of the internal
+functions used by @CollectApp{} and can be ignored. While the inclusive time is high,
+the exclusive time is zero. This means it doesn't contribute to the performance.
+
+The question is how we know where this function originates from? There is a very useful
+command to get more details on a function. @xref{Information on Load Objects}.
+
+@c -- A new node --------------------------------------------------------------
+@node       The Source Code View
+@subsection The Source Code View
+@c ----------------------------------------------------------------------------
+
+In general, you would like to focus the tuning efforts on the most time
+consuming part(s) of the program. In this case that is easy, since 2.160
+seconds on a total of 2.272 seconds is spent in function @code{mxv_core}. 
+That is 95% of the total and it is time to dig deeper and look
+@cindex Source level timings
+at the time distribution at the source code level.
+
+@IndexSubentry{Commands, @code{source}}
+The @code{source} command is used to accomplish this. It takes the name of the
+function, not the source filename, as an argument. This is demonstrated
+below, where the @DisplayText{} command is used to show the annotated
+source listing of function @code{mxv_core}.
+
+Please note that the source code has to be compiled with the @code{-g}
+option in order for the source code feature to work. Otherwise the
+location can not be determined.
+
+@cartouche
+@smallexample
+$ gprofng display text -source mxv_core test.1.er
+@end smallexample
+@end cartouche
+
+The slightly modified output is as follows:
+
+@smallexample
+@verbatim
+Source file: <apath>/mxv.c
+Object file: mxv-pthreads.exe (found as test.1.er/archives/...)
+Load Object: mxv-pthreads.exe (found as test.1.er/archives/...)
+
+   Excl.     Incl.
+   Total     Total
+   CPU sec.  CPU sec.
+
+   <lines deleted>
+                               <Function: mxv_core>
+   0.        0.             32. void __attribute__ ((noinline)) 
+                                mxv_core (
+                                uint64_t row_index_start, 
+                                uint64_t row_index_end,
+                                uint64_t m, uint64_t n, 
+                                double **restrict A,
+                                double *restrict b, 
+                                double *restrict c)
+   0.        0.             33. {
+   0.        0.             34.    for (uint64_t i=row_index_start; 
+                                        i<=row_index_end; i++) {
+   0.        0.             35.       double row_sum = 0.0;
+## 1.687     1.687          36.       for (int64_t j=0; j<n; j++)
+   0.473     0.473          37.          row_sum += A[i][j]*b[j];
+   0.        0.             38.       c[i] = row_sum;
+                            39.    }
+   0.        0.             40. }
+@end verbatim
+@end smallexample
+
+The first three lines provide information on the location of the source file,
+the object file and the load object (@xref{Load Objects and Functions}).
+
+Function @code{mxv_core} is part of a source file that has other functions
+as well. These functions will be shown, but without timing information. They
+have been removed in the output shown above.
+
+This is followed by the annotated source code listing. The selected metrics 
+are shown first, followed by a source line number, and the source code.
+@IndexSubentry{Miscellaneous ,@code{##}}
+The most time consuming line(s) are marked with the @code{##} symbol. In
+this way they are easier to find.
+
+What we see is that all of the time is spent in lines 36-37. 
+
+@IndexSubentry{Commands, @code{lines}}
+A related command sometimes comes handy as well. It is called @code{lines}
+and displays a list of the source lines and their metrics, ordered according
+to the current sort metric (@xref{Sorting the Performance Data}).
+
+Below the command and the output. For lay-out reasons, only the top 10 is 
+shown here and the last part of the text on some lines has been replaced
+by dots.
+
+@cartouche
+@smallexample
+$ gprofng display text -lines test.1.er
+@end smallexample
+@end cartouche
+
+@smallexample
+@verbatim
+Lines sorted by metric: Exclusive Total CPU Time
+
+Excl.     Incl.  Name
+Total     Total
+CPU sec.  CPU sec.
+2.272     2.272  <Total>
+1.687     1.687  mxv_core, line 36 in "mxv.c"
+0.473     0.473  mxv_core, line 37 in "mxv.c"
+0.032     0.088  init_data, line 72 in "manage_data.c"
+0.030     0.043  <Function: erand48_r, instructions without line numbers>
+0.013     0.013  <Function: __drand48_iterate, instructions without ...>
+0.013     0.056  <Function: drand48, instructions without line numbers>
+0.012     0.012  init_data, line 77 in "manage_data.c"
+0.008     0.010  <Function: _int_malloc, instructions without ...>
+0.003     0.003  init_data, line 71 in "manage_data.c"
+@end verbatim
+@end smallexample
+
+What this overview immediately highlights is that the next most time consuming
+source line takes 0.032 seconds only. With an inclusive time of 0.088 seconds,
+it is also clear that this branch of the code does not impact the performance.
+
+@c -- A new node --------------------------------------------------------------
+@node       The Disassembly View
+@subsection The Disassembly View
+@c ----------------------------------------------------------------------------
+
+The source view is very useful to obtain more insight where the time is spent,
+but sometimes this is not sufficient. This is when the disassembly view comes
+in. It is activated with the 
+@IndexSubentry{Commands, @code{disasm}}
+@code{disasm} 
+command and as with the source view, it displays an annotated listing. In this
+@cindex Instruction level timings
+case it shows the instructions with the metrics, interleaved with the
+source lines. The
+instructions have a reference in square brackets (@code{[} and @code{]})
+to the source line they correspond to.
+
+@noindent
+This is what we get for our example:
+
+@cartouche
+@smallexample
+$ gprofng display text -disasm mxv_core test.1.er
+@end smallexample
+@end cartouche
+
+@smallexample
+@verbatim
+Source file: <apath>/mxv.c
+Object file: mxv-pthreads.exe (found as test.1.er/archives/...)
+Load Object: mxv-pthreads.exe (found as test.1.er/archives/...)
+
+   Excl.     Incl.
+   Total     Total
+   CPU sec.  CPU sec.
+
+   <lines deleted>
+                        32. void __attribute__ ((noinline)) 
+                            mxv_core (
+                            uint64_t row_index_start, 
+                            uint64_t row_index_end,
+                            uint64_t m, uint64_t n, 
+                            double **restrict A,
+                            double *restrict b, 
+                            double *restrict c)
+                        33. {
+                            <Function: mxv_core>
+   0.        0.             [33]   4021ba:  mov    0x8(%rsp),%r10
+                        34.    for (uint64_t i=row_index_start;
+                                    i<=row_index_end; i++) {
+   0.        0.             [34]   4021bf:  cmp    %rsi,%rdi
+   0.        0.             [34]   4021c2:  jbe    0x37
+   0.        0.             [34]   4021c4:  ret
+                        35.        double row_sum = 0.0;
+                        36.        for (int64_t j=0; j<n; j++)
+                        37.           row_sum += A[i][j]*b[j];
+   0.        0.             [37]   4021c5:  mov    (%r8,%rdi,8),%rdx
+   0.        0.             [36]   4021c9:  mov    $0x0,%eax
+   0.        0.             [35]   4021ce:  pxor   %xmm1,%xmm1
+   0.002     0.002          [37]   4021d2:  movsd  (%rdx,%rax,8),%xmm0
+   0.096     0.096          [37]   4021d7:  mulsd  (%r9,%rax,8),%xmm0
+   0.375     0.375          [37]   4021dd:  addsd  %xmm0,%xmm1
+## 1.683     1.683          [36]   4021e1:  add    $0x1,%rax
+   0.004     0.004          [36]   4021e5:  cmp    %rax,%rcx
+   0.        0.             [36]   4021e8:  jne    0xffffffffffffffea
+                        38.        c[i] = row_sum;
+   0.        0.             [38]   4021ea:  movsd  %xmm1,(%r10,%rdi,8)
+   0.        0.             [34]   4021f0:  add    $0x1,%rdi
+   0.        0.             [34]   4021f4:  cmp    %rdi,%rsi
+   0.        0.             [34]   4021f7:  jb     0xd
+   0.        0.             [35]   4021f9:  pxor   %xmm1,%xmm1
+   0.        0.             [36]   4021fd:  test   %rcx,%rcx
+   0.        0.             [36]   402200:  jne    0xffffffffffffffc5
+   0.        0.             [36]   402202:  jmp    0xffffffffffffffe8
+                        39.    }
+                        40. }
+   0.        0.             [40]   402204:  ret
+@end verbatim
+@end smallexample
+
+For each instruction, the timing values are given and we can exactly which ones
+are the most expensive. As with the source level view, the most expensive 
+instructions are market with the @code{##} symbol.
+
+As illustrated below and similar to the @code{lines} command, we can get 
+an overview of the instructions executed by using the 
+@IndexSubentry{Commands, @code{pcs}}
+@code{pcs} 
+command. 
+
+@noindent
+Below the command and the output, which again has been restricted
+to 10 lines:
+
+@cartouche
+@smallexample
+$ gprofng display text -pcs test.1.er
+@end smallexample
+@end cartouche
+
+@smallexample
+@verbatim
+PCs sorted by metric: Exclusive Total CPU Time
+
+Excl.     Incl.      Name
+Total     Total
+CPU sec.  CPU sec.
+2.272     2.272  <Total>
+1.683     1.683  mxv_core + 0x00000027, line 36 in "mxv.c"
+0.375     0.375  mxv_core + 0x00000023, line 37 in "mxv.c"
+0.096     0.096  mxv_core + 0x0000001D, line 37 in "mxv.c"
+0.027     0.027  init_data + 0x000000BD, line 72 in "manage_data.c"
+0.012     0.012  init_data + 0x00000117, line 77 in "manage_data.c"
+0.008     0.008  _int_malloc + 0x00000A45
+0.007     0.007  erand48_r + 0x00000062
+0.006     0.006  drand48 + 0x00000000
+0.005     0.005  __drand48_iterate + 0x00000005
+@end verbatim
+@end smallexample
+
+@c -- A new node --------------------------------------------------------------
+@node       Display and Define the Metrics
+@subsection Display and Define the Metrics
+@c ----------------------------------------------------------------------------
+
+The default metrics shown by @DisplayText{} are useful, but there is more
+recorded than displayed. We can customize the values shown by defining the 
+metrics ourselves.
+
+@IndexSubentry{Commands, @code{metric_list}}
+There are two commands related to changing the metrics shown: @code{metric_list}
+and 
+@IndexSubentry{Commands, @code{metrics}}
+@code{metrics}.
+
+The first command shows the metrics in use, plus all the metrics that have 
+been stored as part of the experiment. The second command may be used to
+define the metric list.
+
+In our example we get the following values for the metrics:
+
+@IndexSubentry{Commands, @code{metric_list}}
+@cartouche
+@smallexample
+$ gprofng display text -metric_list test.1.er
+@end smallexample
+@end cartouche
+
+@smallexample
+@verbatim
+Current metrics: e.totalcpu:i.totalcpu:name
+Current Sort Metric: Exclusive Total CPU Time ( e.totalcpu )
+Available metrics:
+   Exclusive Total CPU Time: e.%totalcpu
+   Inclusive Total CPU Time: i.%totalcpu
+                       Size: size
+                 PC Address: address
+                       Name: name
+@end verbatim
+@end smallexample
+
+This shows the metrics currently in use, the metric that is used to sort
+the data and all the metrics that have been recorded, but are not necessarily
+shown.
+
+@cindex Default metrics
+In this case, the default metrics are set to the exclusive and inclusive
+total CPU times, plus the name of the function, or load object.
+
+@IndexSubentry{Commands, @code{metrics}}
+The @code{metrics} command is used to define the metrics that need to be
+displayed. 
+
+For example, to display the exclusive total CPU time, both as a number and a
+percentage, use the following metric definition: @code{e.%totalcpu}
+
+Since the metrics can be tailored for different views, there is a way
+to reset them to the default. This is done through the special keyword
+@code{default}.
+
+@c -- A new node --------------------------------------------------------------
+@node    A First Customization of the Output
+@subsection A First Customization of the Output
+@c ----------------------------------------------------------------------------
+
+With the information just given, we can customize the function overview. 
+For sake of the example, we would like to display the name of the function
+first, followed by the exclusive CPU time, given as an absolute number and 
+a percentage.
+
+Note that the commands are parsed in order of appearance. This is why we
+need to define the metrics @emph{before} requesting the function overview:
+
+@cartouche
+@smallexample
+$ gprofng display text -metrics name:e.%totalcpu -functions test.1.er
+@end smallexample
+@end cartouche
+
+@smallexample
+@verbatim
+Current metrics: name:e.%totalcpu
+Current Sort Metric: Exclusive Total CPU Time ( e.%totalcpu )
+Functions sorted by metric: Exclusive Total CPU Time
+
+Name                Excl. Total
+                    CPU
+                     sec.      %
+ <Total>            2.272 100.00
+ mxv_core           2.160  95.04
+ init_data          0.047   2.06
+ erand48_r          0.030   1.32
+ __drand48_iterate  0.013   0.57
+ drand48            0.013   0.57
+ _int_malloc        0.008   0.35
+ brk                0.001   0.04
+ sysmalloc          0.001   0.04
+ __default_morecore 0.      0.
+ __libc_start_main  0.      0.
+ allocate_data      0.      0.
+ collector_root     0.      0.
+ driver_mxv         0.      0.
+ main               0.      0.
+ malloc             0.      0.
+ sbrk               0.      0.
+@end verbatim
+@end smallexample
+
+This was a first and simple example how to customize the output. Note that we
+did not rerun our profiling job and merely modified the display settings.
+Below we will show other and also more advanced examples of customization.
+
+
+@c -- A new node --------------------------------------------------------------
+@node    Name the Experiment Directory
+@subsection Name the Experiment Directory
+@c ----------------------------------------------------------------------------
+
+When using @CollectApp{}, the default names for experiments work fine, but
+they are quite generic. It is often more convenient to select a more 
+descriptive name. For example, one that reflects conditions for the experiment 
+conducted.
+
+For this, the mutually exclusive @code{-o} and @code{-O} options come in handy. 
+Both may be used to provide a name for the experiment directory, but the
+behaviour of @CollectApp{} is different.
+
+With the 
+@IndexSubentry{Options, @code{-o}}
+@code{-o} 
+option, an existing experiment directory is not overwritten. You either
+need to explicitly remove an existing directory first, or use a name that is not
+in use yet.
+
+This is in contrast with the behaviour for the
+ @IndexSubentry{Options, @code{-O}}
+@code{-O} 
+option. Any existing (experiment) directory with the same name is silently 
+overwritten.
+
+Be aware that the name of the experiment directory has to end with @code{.er}.
+
+@c -- A new node --------------------------------------------------------------
+@node    Control the Number of Lines in the Output
+@subsection Control the Number of Lines in the Output
+@c ----------------------------------------------------------------------------
+
+@IndexSubentry{Commands, @code{limit}}
+The @code{limit <n>} command can be used to control the number of lines printed
+in various overviews, including the function view, but it also takes effect
+for other display commands, like @code{lines}.
+
+The argument @code{<n>} should be a positive integer number. It sets the number
+of lines in the function view. A value of zero resets the limit to the default.
+
+Be aware that the pseudo-function @code{<Total>} counts as a regular function.
+For example @code{limit 10} displays nine user level functions.
+
+@c -- A new node --------------------------------------------------------------
+@node    Sorting the Performance Data
+@subsection Sorting the Performance Data
+@c ----------------------------------------------------------------------------
+
+@IndexSubentry{Commands, @code{sort}}
+The @code{sort <key>} command sets the key to be used when sorting the 
+performance data.
+
+The key is a valid metric definition, but the
+@cindex Visibility field
+visibility field 
+(@xref{Metric Definitions})
+in the metric
+definition is ignored since this does not affect the outcome of the sorting
+operation.
+For example if we set the sort key to @code{e.totalcpu}, the values
+will be sorted in descending order with respect to the exclusive total
+CPU time.
+
+The data can be sorted in reverse order by prepending the metric definition
+with a minus (@code{-}) sign. For example @code{sort -e.totalcpu}.
+
+A default metric for the sort operation has been defined and since this is 
+a persistent command, this default can be restored with @code{default} as 
+the key.
+
+@c -- A new node --------------------------------------------------------------
+@node    Scripting
+@subsection Scripting
+@c ----------------------------------------------------------------------------
+
+As is probably clear by now, the list with commands for @DisplayText{} can be
+very long. This is tedious and also error prone. Luckily, there is an easier and 
+more elegant way to control the behaviour of this tool.
+
+@IndexSubentry{Commands, @code{script}}
+Through the @code{script} command, the name of a file with commands can be
+passed in. These commands are parsed and executed as if they appeared on
+the command line in the same order as encountered in the file. The commands
+in this script file can actually be mixed with commands on the command line.
+
+The difference between the commands in the script file and those used on the
+command line is that the latter require a leading dash (@code{-}) symbol.
+
+Comment lines are supported. They need to start with the @code{#} symbol.
+
+@c -- A new node --------------------------------------------------------------
+@node       A More Elaborate Example
+@subsection A More Elaborate Example
+@c ----------------------------------------------------------------------------
+
+With the information presented so far, we can customize our data
+gathering and display commands.
+
+As an example, to reflect the name of the algorithm and the number of threads 
+that were used in the experiment, we select @code{mxv.1.thr.er} 
+as the name of the experiment directory.
+All we then need to 
+do is to add the 
+ @IndexSubentry{Options, @code{-O}}
+@code{-O} 
+option followed by this name on the command line when running @CollectApp{}:
+
+@cartouche
+@smallexample
+$ exe=mxv-pthreads.exe
+$ m=3000
+$ n=2000
+$ gprofng collect app -O mxv.1.thr.er ./$exe -m $m -n $n -t 1
+@end smallexample
+@end cartouche
+
+The commands to generate the profile are put into a file that we simply call
+@code{my-script}:
+
+@smallexample
+@verbatim
+$ cat my-script
+# This is my first gprofng script
+# Set the metrics
+metrics i.%totalcpu:e.%totalcpu:name
+# Use the exclusive time to sort
+sort e.totalcpu
+# Limit the function list to 5 lines
+limit 5
+# Show the function list
+functions
+@end verbatim
+@end smallexample
+
+This script file is then specified as input to the @DisplayText{} command 
+that is used to display the performance information stored in 
+@code{mxv.1.thr.er}:
+
+@cartouche
+@smallexample
+$ gprofng display text -script my-script mxv.1.thr.er
+@end smallexample
+@end cartouche
+
+The command above produces the following output:
+
+@smallexample
+@verbatim
+# This is my first gprofng script
+# Set the metrics
+Current metrics: i.%totalcpu:e.%totalcpu:name
+Current Sort Metric: Exclusive Total CPU Time ( e.%totalcpu )
+# Use the exclusive time to sort
+Current Sort Metric: Exclusive Total CPU Time ( e.%totalcpu )
+# Limit the function list to 5 lines
+Print limit set to 5
+# Show the function list
+Functions sorted by metric: Exclusive Total CPU Time
+
+Incl. Total   Excl. Total    Name
+CPU           CPU
+ sec.      %   sec.      %
+2.272 100.00  2.272 100.00   <Total>
+2.159  95.00  2.159  95.00   mxv_core
+0.102   4.48  0.054   2.37   init_data
+0.035   1.54  0.025   1.10   erand48_r
+0.048   2.11  0.013   0.57   drand48
+@end verbatim
+@end smallexample
+
+In the first part of the output, our comment lines in the script file are 
+shown. These are interleaved with an acknowledgement message for the commands.
+
+This is followed by a profile consisting of 5 lines only. For both metrics,
+the percentages plus the timings are given. The numbers are sorted with respect 
+to the exclusive total CPU time.
+
+It is now immediately clear that function @code{mxv_core} is responsbile for
+95% of the CPU time and @code{init_data} takes 4.5% only.
+
+This is also where we see sampling in action. Although this is exactly the
+same job we profiled before, the timings are somewhat different, but the
+differences are very small.
+
+@c -- A new node --------------------------------------------------------------
+@node       The Call Tree
+@subsection The Call Tree
+@c ----------------------------------------------------------------------------
+
+The call tree shows the dynamic hierarchy of the application by displaying the
+functions executed and their parent. It helps to find the most expensive path
+in the program.
+
+@IndexSubentry{Commands, @code{calltree}}
+This feature is enabled through the @code{calltree} command. This is how to get
+this tree for our current experiment:
+
+@cartouche
+@smallexample
+$ gprofng display text -calltree mxv.1.thr.er
+@end smallexample
+@end cartouche
+
+This displays the following structure:
+
+@smallexample
+@verbatim
+Functions Call Tree. Metric: Attributed Total CPU Time
+
+Attr.      Name
+Total
+CPU sec.
+2.272      +-<Total>
+2.159        +-collector_root
+2.159        |  +-driver_mxv
+2.159        |    +-mxv_core
+0.114        +-__libc_start_main
+0.114          +-main
+0.102            +-init_data
+0.048            |  +-drand48
+0.035            |    +-erand48_r
+0.010            |      +-__drand48_iterate
+0.011            +-allocate_data
+0.011            |  +-malloc
+0.011            |    +-_int_malloc
+0.001            |      +-sysmalloc
+0.001            +-check_results
+0.001              +-malloc
+0.001                +-_int_malloc
+@end verbatim
+@end smallexample
+
+At first sight this may not be what you expected and some explanation is in
+place.
+
+@c ----------------------------------------------------------------------------
+@c TBD: Revise this text when we have user and machine mode.
+@c ----------------------------------------------------------------------------
+First of all, function @code{collector_root} is internal to @ToolName{} and
+should be hidden to the user. This is part of a planned future enhancement.
+
+Recall that the @code{objects} and @code{fsingle} commands are very useful
+to find out more about load objects in general, but also to help identify
+an unknown entry in the function overview. @xref{Load Objects and Functions}.
+
+Another thing to note is that there are two main branches. The one under
+@code{collector_root} and the second one under @code{__libc_start_main}.
+This reflects the fact that we are executing a parallel program. Even though
+we only used one thread for this run, this is still executed in a separate
+path.
+
+The main, sequential part of the program is displayed under @code{main} and
+shows the functions called and the time they took.
+
+There are two things worth noting for the call tree feature:
+
+@itemize
+
+@item
+This is a dynamic tree and since sampling is used, it most likely looks
+slighlty different across seemingly identical profile runs. In case the
+run times are short, it is worth considering to use a high resolution
+through the 
+@IndexSubentry{Options, @code{-p}}
+@code{-p} 
+option. For example to use @code{-p hi} to increase the sampling rate.
+
+@item
+In case hardware event counters have been enabled 
+(@xref{Profile Hardware Event Counters}), these values are also displayed
+in the call tree view.
+
+@end itemize
+
+@c -- A new node --------------------------------------------------------------
+@node       More Information on the Experiment
+@subsection More Information on the Experiment
+@c ----------------------------------------------------------------------------
+
+The experiment directory not only contains performance related data. Several
+system characteristics, the actually command executed, and some global 
+performance statistics can be displayed.
+
+@IndexSubentry{Commands, @code{header}}
+The @code{header} command displays information about the experiment(s).
+For example, this is the command to extract this data from for our experiment 
+directory:
+
+@cartouche
+@smallexample
+$ gprofng display text -header mxv.1.thr.er
+@end smallexample
+@end cartouche
+
+The above command prints the following information. Note that some of the
+lay-out and the information has been modified. The textual changes are 
+marked with the @code{<} and @code{>} symbols.
+
+@smallexample
+@verbatim
+Experiment: mxv.1.thr.er
+No errors
+No warnings
+Archive command `gp-archive -n -a on 
+         --outfile <exp_dir>/archive.log <exp_dir>'
+
+Target command (64-bit): './mxv-pthreads.exe -m 3000 -n 2000 -t 1'
+Process pid 30591, ppid 30589, pgrp 30551, sid 30468
+Current working directory: <cwd>
+Collector version: `2.36.50'; experiment version 12.4 (64-bit)
+Host `<hostname>', OS `Linux <version>', page size 4096, 
+     architecture `x86_64'
+  16 CPUs, clock speed 1995 MHz.
+  Memory: 30871514 pages @  4096 = 120591 MB.
+Data collection parameters:
+  Clock-profiling, interval = 997 microsecs.
+  Periodic sampling, 1 secs.
+  Follow descendant processes from: fork|exec|combo
+
+Experiment started <date and time>
+
+Experiment Ended: 2.293162658
+Data Collection Duration: 2.293162658
+@end verbatim
+@end smallexample
+
+The output above may assist in troubleshooting, or to verify some of the
+operational conditions and we recommand to include this command when 
+generating a profile.
+
+@IndexSubentry{Options, @code{-C}}
+Related to this command there is a useful option to record your own comment(s) in 
+an experiment.
+To this end, use the @code{-C} option on the @CollectApp{} tool to
+specify a comment string. Up to ten comment lines can be included. 
+These comments are displayed with the @code{header} command on
+the @DisplayText{} tool.
+
+@IndexSubentry{Commands, @code{overview}}
+The @code{overview} command displays information on the experiment(s) and also
+shows a summary of the values for the metric(s) used. This is an example how to
+use it on our newly created experiment directory:
+
+@cartouche
+@smallexample
+$ gprofng display text -overview mxv.1.thr.er
+@end smallexample
+@end cartouche
+
+@smallexample
+@verbatim
+Experiment(s):
+
+Experiment      :mxv.1.thr.er
+  Target        : './mxv-pthreads.exe -m 3000 -n 2000 -t 1'
+  Host          : <hostname> (<ISA>, Linux <version>)
+  Start Time    : <date and time>
+  Duration      : 2.293 Seconds
+
+Metrics:
+
+  Experiment Duration (Seconds): [2.293]
+  Clock Profiling
+    [X]Total CPU Time - totalcpu (Seconds): [*2.272]
+
+Notes: '*' indicates hot metrics, '[X]' indicates currently enabled 
+       metrics.
+       The metrics command can be used to change selections. The 
+       metric_list command lists all available metrics.
+@end verbatim
+@end smallexample
+
+This command provides a dashboard overview that helps to easily identify
+where the time is spent and in case hardware event counters are used, it
+shows their total values.
+
+@c -- A new node --------------------------------------------------------------
+@node       Control the Sampling Frequency
+@subsection Control the Sampling Frequency
+@c ----------------------------------------------------------------------------
+
+So far we did not talk about the frequency of the sampling process, but in
+some cases it is useful to change the default of 10 milliseconds.
+
+The advantage of increasing the sampling frequency is that functions that
+do not take much time per invocation are more accurately captured. The
+downside is that more data is gathered. This has an impact on the overhead
+of the collection process and more disk space is required. 
+
+In general this is not an immediate concern, but with heavily threaded
+applications that run for an extended period of time, increasing the 
+frequency may have a more noticeable impact.
+
+@IndexSubentry{Options, @code{-p}}
+The @code{-p} option on the @CollectApp{} tool is used to enable or disable
+clock based profiling, or to explicitly set the sampling rate. 
+@cindex Sampling interval
+This option takes one of the following keywords:
+
+@table @code
+
+@item off
+Disable clock based profiling.
+
+@item on
+Enable clock based profiling with a per thread sampling interval of 10 ms. This is the default.
+
+@item lo
+Enable clock based profiling with a per thread sampling interval of 100 ms.
+
+@item hi
+Enable clock based profiling with a per thread sampling interval of 1 ms.
+
+@item <value>
+Enable clock based profiling with a per thread sampling interval of <value>. 
+
+@end table 
+
+One may wonder why there is an option to disable clock based profiling. This
+is because by default, it is enabled when conducting hardware event counter
+experiments (@xref{Profile Hardware Event Counters}).
+With the @code{-p off} option, this can be disabled.
+
+If an explicit value is set for the sampling, the number can be an integer or a 
+floating-point number.
+A  suffix of @code{u} for microseconds, or @code{m} for milliseconds is supported. 
+If no suffix is used, the value is assumed to be in milliseconds.
+
+If the value is smaller than the clock profiling minimum, a warning message is issued
+and it is set to the minimum.
+In case it is not a multiple of the clock profiling resolution, it is silently rounded 
+down to the nearest multiple of the clock resolution. 
+
+If the value exceeds the clock profiling maximum, is negative, or zero, an error is 
+reported.
+
+@IndexSubentry{Commands, @code{header}}
+Note that the @code{header} command echoes the sampling rate used.
+
+@c -- A new node --------------------------------------------------------------
+@node    Information on Load Objects
+@subsection Information on Load Objects
+@c ----------------------------------------------------------------------------
+
+It may happen that the function list contains a function that is not known to 
+the user. This can easily happen with library functions for example.
+Luckily there are three commands that come in handy then. 
+
+@IndexSubentry{Commands, @code{objects}}
+@IndexSubentry{Commands, @code{fsingle}}
+@IndexSubentry{Commands, @code{fsummary}}
+These commands are @code{objects}, @code{fsingle}, and @code{fsummary}. 
+They provide details on
+@cindex Load objects
+load objects (@xref{Load Objects and Functions}).
+
+The @code{objects} command lists all load objects that have been referenced 
+during the performance experiment.
+Below we show the command and the result for our profile job. Like before, 
+the (long) path names in the output have been shortened and replaced by the 
+@IndexSubentry{Miscellaneous, @code{<apath>}}
+@code{<apath>} symbol that represents an absolute directory path.
+
+@cartouche
+@smallexample
+$ gprofng display text -objects mxv.1.thr.er
+@end smallexample
+@end cartouche
+
+The output includes the name and path of the target executable:
+
+@smallexample
+@verbatim
+ <Unknown> (<Unknown>)
+ <mxv-pthreads.exe> (<apath>/mxv-pthreads.exe)
+ <librt-2.17.so> (/usr/lib64/librt-2.17.so)
+ <libdl-2.17.so> (/usr/lib64/libdl-2.17.so)
+ <libbfd-2.36.50.20210505.so> (<apath>/libbfd-2.36.50 <etc>)
+ <libopcodes-2.36.50.20210505.so> (<apath>/libopcodes-2. <etc>)
+ <libc-2.17.so> (/usr/lib64/libc-2.17.so)
+ <libpthread-2.17.so> (/usr/lib64/libpthread-2.17.so)
+ <libm-2.17.so> (/usr/lib64/libm-2.17.so)
+ <libgp-collector.so> (<apath>/libgp-collector.so)
+ <ld-2.17.so> (/usr/lib64/ld-2.17.so)
+ <DYNAMIC_FUNCTIONS> (DYNAMIC_FUNCTIONS)
+@end verbatim
+@end smallexample
+
+@IndexSubentry{Commands, @code{fsingle}}
+The @code{fsingle} command may be used to get more details on a specific entry 
+in the function view, say. For example, the command below provides additional
+information on the @code{collector_root} function shown in the function overview.
+
+@cartouche
+@smallexample
+$ gprofng display text -fsingle collector_root mxv.1.thr.er
+@end smallexample
+@end cartouche
+
+Below the output from this command. It has been somewhat modified to match the
+display requirements.
+
+@smallexample
+@verbatim
+collector_root
+  Exclusive Total CPU Time: 0.    (  0. %)
+  Inclusive Total CPU Time: 2.159 ( 95.0%)
+            Size:   401
+      PC Address: 10:0x0001db60
+     Source File: <apath>/dispatcher.c
+     Object File: mxv.1.thr.er/archives/libgp-collector.so_HpzZ6wMR-3b
+     Load Object: <apath>/libgp-collector.so
+    Mangled Name:
+         Aliases:
+@end verbatim
+@end smallexample
+
+In this table we not only see how much time was spent in this function, we
+also see where it originates from. In addition to this, the size and start
+address are given as well. If the source code location is known it is also 
+shown here.
+
+@IndexSubentry{Commands, @code{fsummary}}
+The related @code{fsummary} command displays the same information as 
+@code{fsingle}, but for all functions in the function overview, 
+including @code{<Total>}:
+
+@cartouche
+@smallexample
+$ gprofng display text -fsummary mxv.1.thr.er
+@end smallexample
+@end cartouche
+
+@smallexample
+@verbatim
+Functions sorted by metric: Exclusive Total CPU Time
+
+<Total>
+  Exclusive Total CPU Time: 2.272 (100.0%)
+  Inclusive Total CPU Time: 2.272 (100.0%)
+            Size:     0
+      PC Address: 1:0x00000000
+     Source File: (unknown)
+     Object File: (unknown)
+     Load Object: <Total>
+    Mangled Name:
+         Aliases:
+
+mxv_core
+  Exclusive Total CPU Time: 2.159 ( 95.0%)
+  Inclusive Total CPU Time: 2.159 ( 95.0%)
+            Size:    75
+      PC Address: 2:0x000021ba
+     Source File: <apath>/mxv.c
+     Object File: mxv.1.thr.er/archives/mxv-pthreads.exe_hRxWdccbJPc
+     Load Object: <apath>/mxv-pthreads.exe
+    Mangled Name:
+         Aliases:
+
+          ... etc ...
+@end verbatim
+@end smallexample
+
+@c -- A new node --------------------------------------------------------------
+@node    Support for Multithreading
+@section Support for Multithreading
+@c ----------------------------------------------------------------------------
+
+In this chapter we introduce and discuss the support for multithreading. As
+is shown below, nothing needs to be changed when collecting the performance 
+data.
+
+The difference is that additional commands are available to get more 
+information on the parallel environment, plus that several filters allow
+the user to zoom in on specific threads.
+
+@c -- A new node --------------------------------------------------------------
+@node       Creating a Multithreading Experiment
+@subsection Creating a Multithreading Experiment
+@c ----------------------------------------------------------------------------
+
+We demonstrate the support for multithreading using the same code and settings
+as before, but this time we use 2 threads:
+
+@cartouche
+@smallexample
+$ exe=mxv-pthreads.exe
+$ m=3000
+$ n=2000
+$ gprofng collect app -O mxv.2.thr.er ./$exe -m $m -n $n -t 2
+@end smallexample
+@end cartouche
+
+First of all, note that we did not change anything, other than setting the 
+number of threads to 2. Nothing special is needed to profile a multithreaded
+job when using @ToolName{}.
+
+The same is true when displaying the performance results. The same commands
+that we used before work unmodified. For example, this is all that is needed to 
+get a function overview:
+
+@cartouche
+@smallexample
+$ gpprofng display text -limit 10 -functions mxv.2.thr.er
+@end smallexample
+@end cartouche
+
+This produces the following familiar looking output:
+
+@smallexample
+@verbatim
+Print limit set to 10
+Functions sorted by metric: Exclusive Total CPU Time
+
+Excl.     Incl.      Name
+Total     Total
+CPU sec.  CPU sec.
+2.268     2.268      <Total>
+2.155     2.155      mxv_core
+0.044     0.103      init_data
+0.030     0.046      erand48_r
+0.016     0.016      __drand48_iterate
+0.013     0.059      drand48
+0.008     0.011      _int_malloc
+0.003     0.003      brk
+0.        0.003      __default_morecore
+0.        0.114      __libc_start_main
+@end verbatim
+@end smallexample
+
+@c -- A new node --------------------------------------------------------------
+@node       Commands Specific to Multithreading
+@subsection Commands Specific to Multithreading
+@c ----------------------------------------------------------------------------
+
+The function overview shown above shows the results aggregated over all the 
+threads. The interesting new element is that we can also look at the 
+performance data for the individual threads.
+
+@IndexSubentry{Commands, @code{thread_list}}
+The @code{thread_list} command displays how many threads have been used:
+
+@cartouche
+@smallexample
+$ gprofng display text -thread_list mxv.2.thr.er
+@end smallexample
+@end cartouche
+
+This produces the following output, showing that three threads have
+been used:
+
+@smallexample
+@verbatim
+Exp Sel Total
+=== === =====
+  1 all     3
+@end verbatim
+@end smallexample
+
+The output confirms there is one experiment and that by default all
+threads are selected.
+
+It may seem surprising to see three threads here, since we used the 
+@code{-t 2} option, but it is common for a Pthreads program to use one 
+additional thread. This is typically the thread that runs from start to 
+finish and handles the sequential portions of the code, as well as takes
+care of managing the threads. 
+
+It is no different in our example code. At some point, the main thread 
+creates and activates the two threads that perform the multiplication 
+of the matrix with the vector. Upon completion of this computation,
+the main thread continues.
+
+@IndexSubentry{Commands, @code{threads}}
+The @code{threads} command is simple, yet very powerful. It shows the
+total value of the metrics for each thread. To make it easier to 
+interpret the data, we modify the metrics to include percentages:
+
+@cartouche
+@smallexample
+$ gprofng display text -metrics e.%totalcpu -threads mxv.2.thr.er
+@end smallexample
+@end cartouche
+
+The command above produces the following overview:
+
+@smallexample
+@verbatim
+Current metrics: e.%totalcpu:name
+Current Sort Metric: Exclusive Total CPU Time ( e.%totalcpu )
+Objects sorted by metric: Exclusive Total CPU Time
+
+Excl. Total    Name
+CPU
+ sec.      %
+2.258 100.00   <Total>
+1.075  47.59   Process 1, Thread 3
+1.070  47.37   Process 1, Thread 2
+0.114   5.03   Process 1, Thread 1
+@end verbatim
+@end smallexample
+
+The first line gives the total CPU time accumulated over the threads
+selected. This is followed by the metric value(s) for each thread.
+
+From this it is clear that the main thread is responsible for 5% of
+the total CPU time, while the other two threads take 47% each.
+
+This view is ideally suited to verify if there any load balancing
+issues and also to find the most time consuming thread(s).
+
+@IndexSubentry{Filters, Thread selection}
+While useful, often more information than this is needed. This is
+@IndexSubentry{Commands, @code{thread_select}}
+where the thread selection filter comes in. Through the @code{thread_select}
+command, one or more threads may be selected 
+(@xref{The Selection List} how to define the selection list).
+
+Since it is most common to use this command in a script, we do so as
+well here. Below the script we are using:
+
+@cartouche
+@smallexample
+# Define the metrics
+metrics e.%totalcpu
+# Limit the output to 10 lines
+limit 10
+# Get the function overview for thread 1
+thread_select 1
+functions
+# Get the function overview for thread 2
+thread_select 2
+functions
+# Get the function overview for thread 3
+thread_select 3
+functions
+@end smallexample
+@end cartouche
+
+The definition of the metrics and the output limiter has been shown and
+explained before and will be ignored. The new command we focus on is 
+@IndexSubentry{Commands, @code{thread_select}}
+@code{thread_select}.
+
+This command takes a list (@xref{The Selection List}) to select specific
+threads. In this case we simply use the individual thread numbers that we
+obtained with the @code{thread_list} command earlier.
+
+This restricts the output of the @code{functions} command to the thread
+number(s) specified. This means that the script above shows which 
+function(s) each thread executes and how much CPU time they consumed.
+Both the timings and their percentages are given.
+
+This is the relevant part of the output for the first thread:
+
+@smallexample
+@verbatim
+# Get the function overview for thread 1
+Exp Sel Total
+=== === =====
+  1 1       3
+Functions sorted by metric: Exclusive Total CPU Time
+
+Excl. Total    Name
+CPU
+ sec.      %
+0.114 100.00   <Total>
+0.051  44.74   init_data
+0.028  24.56   erand48_r
+0.017  14.91   __drand48_iterate
+0.010   8.77   _int_malloc
+0.008   7.02   drand48
+0.      0.     __libc_start_main
+0.      0.     allocate_data
+0.      0.     main
+0.      0.     malloc
+@end verbatim
+@end smallexample
+
+As usual, the comment lines are echoed. This is followed by a confirmation
+of our selection. We see that indeed thread 1 has been selected. What is
+displayed next is the function overview for this particular thread. Due to
+the @code{limit 10} command, there are ten entries in this list.
+
+Below are the overviews for threads 2 and 3 respectively. We see that all
+of the CPU time is spent in function @code{mxv_core} and that this time
+is approximately the same for both threads.
+
+@smallexample
+@verbatim
+# Get the function overview for thread 2
+Exp Sel Total
+=== === =====
+  1 2       3
+Functions sorted by metric: Exclusive Total CPU Time
+
+Excl. Total    Name
+CPU
+ sec.      %
+1.072 100.00   <Total>
+1.072 100.00   mxv_core
+0.      0.     collector_root
+0.      0.     driver_mxv
+
+# Get the function overview for thread 3
+Exp Sel Total
+=== === =====
+  1 3       3
+Functions sorted by metric: Exclusive Total CPU Time
+
+Excl. Total    Name
+CPU
+ sec.      %
+1.076 100.00   <Total>
+1.076 100.00   mxv_core
+0.      0.     collector_root
+0.      0.     driver_mxv
+@end verbatim
+@end smallexample
+
+When analyzing the performance of a multithreaded application, it is sometimes
+useful to know whether threads have mostly executed on the same core, say, or
+if they have wandered across multiple cores. This sort of stickiness is usually 
+referred to as
+@cindex Thread affinity
+@emph{thread affinity}.
+
+Similar to the commands for the threads, there are several commands related 
+to the usage of the cores, or @emph{CPUs} as they are called in @ToolName{}
+(@xref{The Concept of a CPU in @ProductName{}}).
+
+In order to have some more interesting data to look at, we created a new
+experiment, this time using 8 threads:
+
+@cartouche
+@smallexample
+$ exe=mxv-pthreads.exe
+$ m=3000
+$ n=2000
+$ gprofng collect app -O mxv.8.thr.er ./$exe -m $m -n $n -t 8
+@end smallexample
+@end cartouche
+
+@IndexSubentry{Commands, @code{cpu_list}}
+Similar to the @code{thread_list} command, the @code{cpu_list} command 
+displays how many CPUs have been used. 
+@IndexSubentry{Commands, @code{cpus}}
+The equivalent of the @code{threads} threads command, is the @code{cpus} 
+command, which shows the CPU numbers that were used and how much time was 
+spent on each of them. Both are demonstrated below.
+
+@cartouche
+@smallexample
+$ gprofng display text -metrics e.%totalcpu -cpu_list -cpus mxv.8.thr.er
+@end smallexample
+@end cartouche
+
+This command produces the following output:
+
+@smallexample
+@verbatim
+Current metrics: e.%totalcpu:name
+Current Sort Metric: Exclusive Total CPU Time ( e.%totalcpu )
+Exp Sel Total
+=== === =====
+  1 all    10
+Objects sorted by metric: Exclusive Total CPU Time
+
+Excl. Total    Name
+CPU
+ sec.      %
+2.310 100.00   <Total>
+0.286  12.39   CPU 7
+0.284  12.30   CPU 13
+0.282  12.21   CPU 5
+0.280  12.13   CPU 14
+0.266  11.52   CPU 9
+0.265  11.48   CPU 2
+0.264  11.44   CPU 11
+0.194   8.42   CPU 0
+0.114   4.92   CPU 1
+0.074   3.19   CPU 15
+@end verbatim
+@end smallexample
+
+@c ----------------------------------------------------------------------------
+@c TBD - Ruud
+@c I'd like to improve this and have a way to see where a thread has executed.
+@c ----------------------------------------------------------------------------
+
+What we see in this table is that a total of 10 CPUs have been used. This is
+followed by a list with all the CPU numbers that have been used during the 
+run. For each CPU it is shown how much time was spent on it.
+
+While the table with thread times shown earlier may point at a load imbalance
+in the application, this overview has a different purpose.
+
+For example, we see that 10 CPUs have been used, but we know that the 
+application uses 9 threads only.
+This means that at least one thread has executed on more than one CPU. In 
+itself this is not something to worry about, but warrants a deeper 
+investigation.
+
+Honesty dictates that next we performed a pre-analysis to find out 
+which thread(s) have been running on more than one CPU. We found this 
+to be thread 7. It has executed on CPUs 0 and 15.
+
+With this knowledge, we wrote the script shown below. It zooms in on
+the behaviour of thread 7.
+
+@cartouche
+@smallexample
+# Define the metrics
+metrics e.%totalcpu
+# Limit the output to 10 lines
+limit 10
+functions
+# Get the function overview for CPU 0
+cpu_select 0
+functions
+# Get the function overview for CPU 15
+cpu_select 15
+functions
+@end smallexample
+@end cartouche
+
+From the earlier shown threads overview, we know that thread 7 has
+used @code{0.268} seconds of CPU time..
+
+By selecting CPUs 0 and 15, respectively, we get the following
+function overviews:
+
+@smallexample
+@verbatim
+# Get the function overview for CPU 0
+Exp Sel Total
+=== === =====
+  1 0      10
+Functions sorted by metric: Exclusive Total CPU Time
+
+Excl. Total    Name
+CPU
+ sec.      %
+0.194 100.00   <Total>
+0.194 100.00   mxv_core
+0.      0.     collector_root
+0.      0.     driver_mxv
+
+# Get the function overview for CPU 15
+Exp Sel Total
+=== === =====
+  1 15     10
+Functions sorted by metric: Exclusive Total CPU Time
+
+Excl. Total    Name
+CPU
+ sec.      %
+0.074 100.00   <Total>
+0.074 100.00   mxv_core
+0.      0.     collector_root
+0.      0.     driver_mxv
+@end verbatim
+@end smallexample
+
+This shows that thread 7 spent @code{0.194} seconds on CPU 0 and 
+@code{0.074} seconds on CPU 15.
+
+@c -- A new node --------------------------------------------------------------
+@node    Viewing Multiple Experiments
+@section Viewing Multiple Experiments
+@c ----------------------------------------------------------------------------
+
+One thing we did not cover sofar is that @ToolName{} fully supports the analysis
+of multiple experiments. The @DisplayText{} tool accepts a list of experiments.
+The data can either be aggregated across the experiments, or used in a 
+comparison.
+
+Mention @code{experiment_list}
+
+@c -- A new node --------------------------------------------------------------
+@node    Aggregation of Experiments
+@subsection Aggregation of Experiments
+@c ----------------------------------------------------------------------------
+
+By default, the data for multiple experiments is aggregrated and the display 
+commands shows these combined results.
+
+For example, we can aggregate the data for our single and dual thread
+experiments. Below is the script we used for this:
+
+@cartouche
+@smallexample
+# Define the metrics
+metrics e.%totalcpu
+# Limit the output to 10 lines
+limit 10
+# Get the list with experiments
+experiment_list
+# Get the function overview
+functions
+@end smallexample
+@end cartouche
+
+@IndexSubentry{Commands, @code{experiment_list}}
+With the exception of the @code{experiment_list} command, all commands
+used have been discussed earlier.
+
+The @code{experiment_list} command provides a list of the experiments
+that have been loaded. This is is used to verify we are looking at the
+experiments we intend to aggregate.
+
+@cartouche
+@smallexample
+$ gprofng display text -script my-script-agg mxv.1.thr.er mxv.2.thr.er
+@end smallexample
+@end cartouche
+
+With the command above, we get the following output:
+
+@smallexample
+@verbatim
+# Define the metrics
+Current metrics: e.%totalcpu:name
+Current Sort Metric: Exclusive Total CPU Time ( e.%totalcpu )
+# Limit the output to 10 lines
+Print limit set to 10
+# Get the list with experiments
+ID Sel   PID Experiment
+== === ===== ============
+ 1 yes 30591 mxv.1.thr.er
+ 2 yes 11629 mxv.2.thr.er
+# Get the function overview
+Functions sorted by metric: Exclusive Total CPU Time
+
+Excl. Total    Name
+CPU
+ sec.      %
+4.533 100.00   <Total>
+4.306  94.99   mxv_core
+0.105   2.31   init_data
+0.053   1.17   erand48_r
+0.027   0.59   __drand48_iterate
+0.021   0.46   _int_malloc
+0.021   0.46   drand48
+0.001   0.02   sysmalloc
+0.      0.     __libc_start_main
+0.      0.     allocate_data
+@end verbatim
+@end smallexample
+
+The first five lines should look familiar. The five lines following, echo
+the comment line in the script and show the overview of the experiments.
+This confirms two experiments have been loaded and that both are active.
+
+This is followed by the function overview. The timings have been summed
+up and the percentages are adjusted accordingly. For example, the total
+accumulated time is indeed 2.272 + 2.261 = 4.533 seconds.
+
+@c -- A new node --------------------------------------------------------------
+@node       Comparison of Experiments
+@subsection Comparison of Experiments
+@c ----------------------------------------------------------------------------
+
+The support for multiple experiments really shines in comparison mode. This
+feature is enabled through the command 
+@IndexSubentry{Commands, @code{compare on/off}}
+@code{compare on} 
+and is disabled
+by setting 
+@code{compare off}.
+
+@cindex Compare experiments
+In comparison mode, the data for the various experiments is shown side by
+side, as illustrated below where we compare the results for the multithreaded
+experiments using one and two threads respectively:
+
+@cartouche
+@smallexample
+$ gprofng display text -compare on -functions mxv.1.thr.er mxv.2.thr.er
+@end smallexample
+@end cartouche
+
+@noindent
+This produces the following output:
+
+@smallexample
+@verbatim
+Functions sorted by metric: Exclusive Total CPU Time
+
+mxv.1.thr.er  mxv.2.thr.er  mxv.1.thr.er  mxv.2.thr.er
+Excl. Total   Excl. Total   Incl. Total   Incl. Total    Name
+CPU           CPU           CPU           CPU
+ sec.          sec.          sec.          sec.
+2.272         2.261         2.272         2.261          <Total>
+2.159         2.148         2.159         2.148          mxv_core
+0.054         0.051         0.102         0.104          init_data
+0.025         0.028         0.035         0.045          erand48_r
+0.013         0.008         0.048         0.053          drand48
+0.011         0.010         0.012         0.010          _int_malloc
+0.010         0.017         0.010         0.017          __drand48_iterate
+0.001         0.            0.001         0.             sysmalloc
+0.            0.            0.114         0.114          __libc_start_main
+0.            0.            0.011         0.010          allocate_data
+0.            0.            0.001         0.             check_results
+0.            0.            2.159         2.148          collector_root
+0.            0.            2.159         2.148          driver_mxv
+0.            0.            0.114         0.114          main
+0.            0.            0.012         0.010          malloc
+@end verbatim
+@end smallexample
+
+This table is already helpful to more easily compare (two) profiles, but 
+there is more that we can do here. 
+
+By default, in comparison mode, all measured values are shown. Often 
+profiling is about comparing performance data. It is therefore
+more useful to look at differences, or ratios, using one experiment as 
+a reference. 
+
+The values shown are relative to this difference. For example if a ratio
+is below one, it means the reference value was higher. 
+
+@IndexSubentry{Commands, @code{compare on/off}}
+This feature is supported on the @code{compare} command. In addition to @code{on},
+or @code{off}, this command also supports 
+@IndexSubentry{Commands, @code{compare delta}}
+@code{delta}, or 
+@IndexSubentry{Commands, @code{compare ratio}}
+@code{ratio}.
+
+Usage of one of these two keywords enables the comparison feature and shows
+either the difference, or the ratio, relative to the reference data.
+
+In the example below, we use the same two experiments used in the comparison
+above, but as before, the number of lines is restricted to 10 and we focus on 
+the exclusive timings plus percentages. For the comparison part we are 
+interested in the differences.
+
+This is the script that produces such an overview:
+
+@cartouche
+@smallexample
+# Define the metrics
+metrics e.%totalcpu
+# Limit the output to 10 lines
+limit 10
+# Set the comparison mode to differences
+compare delta
+# Get the function overview
+functions
+@end smallexample
+@end cartouche
+
+Assuming this script file is called @code{my-script-comp}, this is how we
+get the table displayed on our screen:
+
+@cartouche
+@smallexample
+$ gprofng display text -script my-script-comp mxv.1.thr.er mxv.2.thr.er
+@end smallexample
+@end cartouche
+
+Leaving out some of the lines printed, but we have seen before, we get 
+the following table:
+
+@smallexample
+@verbatim
+mxv.1.thr.er  mxv.2.thr.er
+Excl. Total   Excl. Total     Name
+CPU           CPU
+ sec.      %   delta      %
+2.272 100.00  -0.011 100.00   <Total>
+2.159  95.00  -0.011  94.97   mxv_core
+0.054   2.37  -0.003   2.25   init_data
+0.025   1.10  +0.003   1.23   erand48_r
+0.013   0.57  -0.005   0.35   drand48
+0.011   0.48  -0.001   0.44   _int_malloc
+0.010   0.44  +0.007   0.75   __drand48_iterate
+0.001   0.04  -0.001   0.     sysmalloc
+0.      0.    +0.      0.     __libc_start_main
+0.      0.    +0.      0.     allocate_data
+@end verbatim
+@end smallexample
+
+It is now easy to see that the CPU times for the most time consuming
+functions in this code are practically the same. 
+
+While in this case we used the delta as a comparison,
+
+Note that the comparison feature is supported at the function, source, and 
+disassembly level. There is no practical limit on the number of experiments
+that can be used in a comparison.
+
+
+
+@c -- A new node --------------------------------------------------------------
+@node    Profile Hardware Event Counters
+@section Profile Hardware Event Counters
+@c ----------------------------------------------------------------------------
+
+Many processors provide a set of hardware event counters and @ToolName{}
+provides support for this feature.
+@xref{Hardware Event Counters Explained} for those readers that are not 
+familiar with such counters and like to learn more.
+
+In this section we explain how to get the details on the event counter
+support for the processor used in the experiment(s), and show several
+examples.
+
+@c -- A new node --------------------------------------------------------------
+@node       Getting Information on the Counters Supported
+@subsection Getting Information on the Counters Supported
+@c ----------------------------------------------------------------------------
+
+The first step is to check if the processor used for the experiments is 
+supported by @ToolName{}.
+
+@IndexSubentry{Options, @code{-h}}
+The @code{-h} option on @CollectApp{} will show the event counter
+information:
+
+@cartouche
+@smallexample
+$ gprofng collect app -h
+@end smallexample
+@end cartouche
+
+In case the counters are supported, a list with the events is printed. 
+Otherwise, a warning message will be issued. 
+
+For example, below we show this command and the output on an Intel Xeon 
+Platinum 8167M (aka ``Skylake'') processor. The output has been split
+into several sections and each section is commented upon separately.
+
+@smallexample
+@verbatim
+Run "gprofng collect app --help" for a usage message.
+
+Specifying HW counters on `Intel Arch PerfMon v2 on Family 6 Model 85' 
+(cpuver=2499):
+
+  -h {auto|lo|on|hi}
+       turn on default set of HW counters at the specified rate
+  -h <ctr_def> [-h <ctr_def>]...
+  -h <ctr_def>[,<ctr_def>]...
+       specify HW counter profiling for up to 4 HW counters
+@end verbatim
+@end smallexample
+
+The first line shows how to get a usage overview. This is followed by
+some information on the target processor.
+
+The next five lines explain in what ways the @code{-h} option can be 
+used to define the events to be monitored.
+
+The first version shown above enables a default set of counters. This
+default depends on the processor this command is executed on. The
+keyword following the @code{-h} option defines the sampling rate:
+
+@table @code
+
+@item auto
+Match the sample rate of used by clock profiling. If the latter is disabled,
+Use a per thread sampling rate of approximately 100 samples per second.
+This setting is the default and preferred.
+
+@item on
+Use a per thread sampling rate of approximately 100 samples per second.
+
+@item lo
+Use a per thread sampling rate of approximately 10 samples per second.
+
+@item hi
+Use a per thread sampling rate of approximately 1000 samples per second.
+
+@end table 
+
+The second and third variant define the events to be monitored. Note
+that the number of simultaneous events supported is printed. In this
+case we can monitor four events in a single profiling job.
+
+It is a matter of preference whether you like to use the @code{-h}
+option for each event, or use it once, followed by a comma separated
+list.
+
+There is one slight catch though. The counter definition below has 
+mandatory comma (@code{,}) between the event and the rate. While a 
+default can be used for the rate, the comma cannot be omitted. 
+This may result in a somewhat awkward counter definition in case
+the default sampling rate is used.
+
+For example, the following two commands are equivalent. Note
+the double comma in the second command. This is not a typo.
+
+@cartouche
+@smallexample
+$ gprofng collect app -h cycles -h insts ... 
+$ gprofng collect app -h cycles,,insts ... 
+@end smallexample
+@end cartouche
+
+In the first command this comma is not needed, because a 
+comma (``@code{,}'') immediately followed by white space may 
+be omitted.
+
+This is why we prefer the this syntax and in the remainder will 
+use the first version of this command.
+
+@IndexSubentry{Hardware event counters, counter definition}
+The counter definition takes an event name, plus optionally one or
+more attributes, followed by a comma, and optionally the sampling rate.
+The output section below shows the formal definition.
+
+@cartouche
+@smallexample
+  <ctr_def> == <ctr>[[~<attr>=<val>]...],[<rate>]
+@end smallexample
+@end cartouche
+
+The printed help then explains this syntax. Below we have summarized
+and expanded this output:
+
+@table @code
+
+@item <ctr>
+The counter name must be selected from the available counters listed
+as part of the output printed with the @code{-h} option.
+On most systems, if a counter is not listed, it may still be specified 
+by its numeric value.
+
+@item ~<attr>=<val>
+This is an optional attribute that depends on the processor. The list
+of supported attributes is printed in the output. Examples of 
+attributes are ``user'', or ``system''. The value can given in decimal
+or hexadecimal format.
+Multiple attributes may be specified, and each must be preceded 
+by a ~.
+
+@item <rate>
+
+The sampling rate is one of the following:
+
+@table @code
+
+@item auto
+This is the default and matches the rate used by clock profiling.
+If clock profiling is disabled, use @code{on}.
+
+@item on
+Set the per thread maximum sampling rate to ~100 samples/second
+
+@item lo
+Set the per thread maximum sampling rate to ~10 samples/second
+
+@item hi
+Set the per thread maximum sampling rate to ~1000 samples/second
+
+@item <interval>
+Define the sampling interval. 
+@xref{Control the Sampling Frequency} how to define this.
+
+@end table
+
+@end table
+
+After the section with the formal definition of events and counters, a
+processor specific list is displayed. This part starts with an overview
+of the default set of counters and the aliased names supported 
+@emph{on this specific processor}.
+
+@smallexample
+@verbatim
+Default set of HW counters:
+
+    -h cycles,,insts,,llm
+
+Aliases for most useful HW counters:
+
+ alias    raw name                   type units regs description
+
+ cycles   unhalted-core-cycles   CPU-cycles 0123 CPU Cycles
+ insts    instruction-retired        events 0123 Instructions Executed
+ llm      llc-misses                 events 0123 Last-Level Cache Misses
+ br_msp   branch-misses-retired      events 0123 Branch Mispredict
+ br_ins   branch-instruction-retired events 0123 Branch Instructions
+@end verbatim
+@end smallexample
+
+The definitions given above may or may not be available on other processors,
+but we try to maximize the overlap across alias sets.
+
+The table above shows the default set of counters defined for this processor,
+and the aliases. For each alias the full ``raw'' name is given, plus the
+unit of the number returned by the counter (CPU cycles, or a raw count), 
+the hardware counter the event is allowed to be mapped onto, and a short 
+description.
+
+The last part of the output contains all the events that can be monitored:
+
+@smallexample
+@verbatim
+Raw HW counters:
+
+    name                                type      units regs description
+
+    unhalted-core-cycles                     CPU-cycles 0123
+    unhalted-reference-cycles                    events 0123
+    instruction-retired                          events 0123
+    llc-reference                                events 0123
+    llc-misses                                   events 0123
+    branch-instruction-retired                   events 0123
+    branch-misses-retired                        events 0123
+    ld_blocks.store_forward                      events 0123
+    ld_blocks.no_sr                              events 0123
+    ld_blocks_partial.address_alias              events 0123
+    dtlb_load_misses.miss_causes_a_walk          events 0123
+    dtlb_load_misses.walk_completed_4k           events 0123
+
+    <many lines deleted>
+
+    l2_lines_out.silent                          events 0123
+    l2_lines_out.non_silent                      events 0123
+    l2_lines_out.useless_hwpf                    events 0123
+    sq_misc.split_lock                           events 0123
+
+See Chapter 19 of the "Intel 64 and IA-32 Architectures Software
+Developer's Manual Volume 3B: System Programming Guide"
+@end verbatim
+@end smallexample
+
+As can be seen, these names are not always easy to correlate to a specific
+event of interest. The processor manual should provide more clarity on this.
+
+@c -- A new node --------------------------------------------------------------
+@node       Examples Using Hardware Event Counters
+@subsection Examples Using Hardware Event Counters
+@c ----------------------------------------------------------------------------
+
+The previous section may give the impression that these counters are hard to
+use, but as we will show now, in practice it is quite simple.
+
+With the information from the @code{-h} option, we can easily set up our first 
+event counter experiment.
+
+We start by using the default set of counters defined for our processor and we
+use 2 threads:
+
+@cartouche
+@smallexample
+$ exe=mxv-pthreads.exe
+$ m=3000
+$ n=2000
+$ exp=mxv.hwc.def.2.thr.er
+$ gprofng collect app -O $exp -h auto ./$exe -m $m -n $n -t 2
+@end smallexample
+@end cartouche
+
+@IndexSubentry{Options, @code{-h}}
+@IndexSubentry{Hardware event counters, @code{auto} option}
+The new option here is @code{-h auto}. The @code{auto} keyword enables 
+hardware event counter profiling and selects the default set of counters 
+defined for this processor.
+
+As before, we can display the information, but there is one practical hurdle
+to take. Unless we like to view all metrics recorded, we would need to know
+the names of the events that have been enabled. This is tedious and also not
+portable in case we would like to repeat this experiment on another processor.
+
+@IndexSubentry{Hardware event counters, @code{hwc} metric}
+This is where the special @code{hwc} metric comes very handy. It 
+automatically expands to the active set of events used.
+
+With this, it is very easy to display the event counter values. Note that
+although the regular clock based profiling was enabled, we only want to see 
+the counter values. We also request to see the percentages and limit the
+output to the first 5 lines:
+
+@cartouche
+@smallexample
+$ exp=mxv.hwc.def.2.thr.er
+$ gprofng display text -metrics e.%hwc -limit 5 -functions $exp
+@end smallexample
+@end cartouche
+
+@smallexample
+@verbatim
+Current metrics: e.%cycles:e+%insts:e+%llm:name
+Current Sort Metric: Exclusive CPU Cycles ( e.%cycles )
+Print limit set to 5
+Functions sorted by metric: Exclusive CPU Cycles
+
+Excl. CPU     Excl. Instructions  Excl. Last-Level   Name
+Cycles        Executed            Cache Misses
+ sec.      %                  %                 %
+2.691 100.00  7906475309 100.00   122658983 100.00   <Total>
+2.598  96.54  7432724378  94.01   121745696  99.26   mxv_core
+0.035   1.31   188860269   2.39       70084   0.06   erand48_r
+0.026   0.95    73623396   0.93      763116   0.62   init_data
+0.018   0.66    76824434   0.97       40040   0.03   drand48
+@end verbatim
+@end smallexample
+
+As we have seen before, the first few lines echo the settings.
+This includes a list with the hardware event counters used by
+default.
+
+The table that follows makes it very easy to get an overview where the 
+time is spent and how many of the target events have occurred.
+
+As before, we can drill down deeper and see the same metrics at the source
+line and instruction level. Other than using @code{hwc} in the metrics
+definitions, nothing has changed compared to the previous examples:
+
+@cartouche
+@smallexample
+$ exp=mxv.hwc.def.2.thr.er
+$ gprofng display text -metrics e.hwc -source mxv_core $exp
+@end smallexample
+@end cartouche
+
+This is the relevant part of the output. Since the lines get very long,
+we have somewhat modified the lay-out:
+
+@smallexample
+@verbatim
+   Excl. CPU Excl.        Excl.
+   Cycles    Instructions Last-Level
+    sec.     Executed     Cache Misses
+                                         <Function: mxv_core>
+   0.                 0          0   32. void __attribute__ ((noinline)) 
+                                         mxv_core(...)
+   0.                 0          0   33. {
+   0.                 0          0   34.   for (uint64_t i=...) {
+   0.                 0          0   35.     double row_sum = 0.0;
+## 1.872     7291879319   88150571   36.     for (int64_t j=0; j<n; j++)
+   0.725      140845059   33595125   37.        row_sum += A[i][j]*b[j];
+   0.                 0          0   38.     c[i] = row_sum;
+                                     39.    }
+   0.                 0          0   40. }
+@end verbatim
+@end smallexample
+
+In a smiliar way we can display the event counter values at the instruction
+level. Again we have modified the lay-out due to page width limitations:
+
+@cartouche
+@smallexample
+$ exp=mxv.hwc.def.2.thr.er
+$ gprofng display text -metrics e.hwc -disasm mxv_core $exp
+@end smallexample
+@end cartouche
+
+@smallexample
+@verbatim
+   Excl. CPU Excl.        Excl.
+   Cycles    Instructions Last-Level
+    sec.     Executed     Cache Misses
+                                                <Function: mxv_core>
+   0.                 0          0  [33] 4021ba: mov   0x8(%rsp),%r10
+                                    34.   for (uint64_t i=...) {
+   0.                 0          0  [34] 4021bf: cmp   %rsi,%rdi
+   0.                 0          0  [34] 4021c2: jbe   0x37
+   0.                 0          0  [34] 4021c4: ret
+                                    35.       double row_sum = 0.0;
+                                    36.       for (int64_t j=0; j<n; j++)
+                                    37.         row_sum += A[i][j]*b[j];
+   0.                 0          0  [37] 4021c5: mov   (%r8,%rdi,8),%rdx
+   0.                 0          0  [36] 4021c9: mov   $0x0,%eax
+   0.                 0          0  [35] 4021ce: pxor  %xmm1,%xmm1
+   0.002       12804230     321394  [37] 4021d2: movsd (%rdx,%rax,8),%xmm0
+   0.141       60819025    3866677  [37] 4021d7: mulsd (%r9,%rax,8),%xmm0
+   0.582       67221804   29407054  [37] 4021dd: addsd %xmm0,%xmm1
+## 1.871     7279075109   87989870  [36] 4021e1: add   $0x1,%rax
+   0.002       12804210      80351  [36] 4021e5: cmp   %rax,%rcx
+   0.                 0          0  [36] 4021e8: jne   0xffffffffffffffea
+                                    38.       c[i] = row_sum;
+   0.                 0          0  [38] 4021ea: movsd %xmm1,(%r10,%rdi,8)
+   0.                 0          0  [34] 4021f0: add   $0x1,%rdi
+   0.                 0          0  [34] 4021f4: cmp   %rdi,%rsi
+   0.                 0          0  [34] 4021f7: jb    0xd
+   0.                 0          0  [35] 4021f9: pxor  %xmm1,%xmm1
+   0.                 0          0  [36] 4021fd: test  %rcx,%rcx
+   0.                 0      80350  [36] 402200: jne   0xffffffffffffffc5
+   0.                 0          0  [36] 402202: jmp   0xffffffffffffffe8
+                                    39.   }
+                                    40. }
+   0.                 0          0  [40]  402204:  ret
+@end verbatim
+@end smallexample
+
+So far we have used the default settings for the event counters. It is
+quite straightforward to select specific counters. For sake of the
+example, let's assume we would like to count how many branch instructions
+and retired memory load instructions that missed in the L1 cache have been
+executed. We also want to count these events with a high resolution.
+
+This is the command to do so:
+
+@cartouche
+@smallexample
+$ exe=mxv-pthreads.exe
+$ m=3000
+$ n=2000
+$ exp=mxv.hwc.sel.2.thr.er
+$ hwc1=br_ins,hi
+$ hwc2=mem_load_retired.l1_miss,hi
+$ gprofng collect app -O $exp -h $hwc1 -h $hwc2 $exe -m $m -n $n -t 2
+@end smallexample
+@end cartouche
+
+As before, we get a table with the event counts. Due to the very
+long name for the second counter, we have somewhat modified the
+output.
+
+@cartouche
+@smallexample
+$ gprofng display text -limit 10 -functions mxv.hwc.sel.2.thr.er
+@end smallexample
+@end cartouche
+
+@smallexample
+@verbatim
+Functions sorted by metric: Exclusive Total CPU Time
+Excl.     Incl.     Excl. Branch  Excl.                 Name
+Total     Total     Instructions  mem_load_retired.l1_miss
+CPU sec.  CPU sec.                Events
+2.597     2.597     1305305319    4021340               <Total>
+2.481     2.481     1233233242    3982327               mxv_core
+0.040     0.107       19019012       9003               init_data
+0.028     0.052       23023048      15006               erand48_r
+0.024     0.024       19019008       9004               __drand48_iterate
+0.015     0.067       11011009       2998               drand48
+0.008     0.010              0       3002               _int_malloc
+0.001     0.001              0          0               brk
+0.001     0.002              0          0               sysmalloc
+0.        0.001              0          0               __default_morecore
+@end verbatim
+@end smallexample
+
+@IndexSubentry{Commands, @code{compare ratio}}
+When using event counters, the values could be very large and it is not easy
+to compare the numbers. As we will show next, the @code{ratio} feature is
+very useful when comparing such profiles.
+
+To demonstrate this, we have set up another event counter experiment where
+we would like to compare the number of last level cache miss and the number
+of branch instructions executed when using a single thread, or two threads.
+
+These are the commands used to generate the experiment directories:
+
+@cartouche
+@smallexample
+$ exe=./mxv-pthreads.exe
+$ m=3000
+$ n=2000
+$ exp1=mxv.hwc.comp.1.thr.er
+$ exp2=mxv.hwc.comp.2.thr.er
+$ gprofng collect app -O $exp1 -h llm -h br_ins $exe -m $m -n $n -t 1
+$ gprofng collect app -O $exp2 -h llm -h br_ins $exe -m $m -n $n -t 2
+@end smallexample
+@end cartouche
+
+The following script has been used to get the tables. Due to lay-out
+restrictions, we have to create two tables, one for each counter.
+
+@cartouche
+@smallexample
+# Limit the output to 5 lines
+limit 5
+# Define the metrics
+metrics name:e.llm
+# Set the comparison to ratio
+compare ratio
+functions
+# Define the metrics
+metrics name:e.br_ins
+# Set the comparison to ratio
+compare ratio
+functions
+@end smallexample
+@end cartouche
+
+Note that we print the name of the function first, followed by the counter 
+data.
+The new element is that we set the comparison mode to @code{ratio}. This
+divides the data in a column by its counterpart in the reference experiment.
+
+This is the command using this script and the two experiment directories as 
+input:
+
+@cartouche
+@smallexample
+$ gprofng display text -script my-script-comp-counters \
+  mxv.hwc.comp.1.thr.er \
+  mxv.hwc.comp.2.thr.er
+@end smallexample
+@end cartouche
+
+By design, we get two tables, one for each counter:
+
+@smallexample
+@verbatim
+Functions sorted by metric: Exclusive Last-Level Cache Misses
+
+                              mxv.hwc.comp.1.thr.er  mxv.hwc.comp.2.thr.er
+Name                          Excl. Last-Level       Excl. Last-Level
+                              Cache Misses           Cache Misses
+                                                         ratio
+ <Total>                      122709276              x   0.788
+ mxv_core                     121796001              x   0.787
+ init_data                       723064              x   1.055
+ erand48_r                       100111              x   0.500
+ drand48                          60065              x   1.167
+
+Functions sorted by metric: Exclusive Branch Instructions
+
+                              mxv.hwc.comp.1.thr.er  mxv.hwc.comp.2.thr.er
+Name                          Excl. Branch           Excl. Branch
+                              Instructions           Instructions
+                                                       ratio
+ <Total>                      1307307316             x 0.997
+ mxv_core                     1235235239             x 0.997
+ erand48_r                      23023033             x 0.957
+ drand48                        20020009             x 0.600
+ __drand48_iterate              17017028             x 0.882
+@end verbatim
+@end smallexample
+
+A ratio less than one in the second column, means that this counter
+value was smaller than the value from the reference experiment shown
+in the first column.
+
+This kind of presentation of the results makes it much easier to 
+quickly interpret the data.
+
+We conclude this section with thread-level event counter overviews,
+but before we go into this, there is an important metric we need to
+mention.
+
+@IndexSubentry{Hardware event counters, IPC}
+In case it is known how many instructions and CPU cycles have been executed,
+the value for the IPC (``Instructions Per Clockycle'') can be computed. 
+@xref{Hardware Event Counters Explained}.
+This is a derived metric that gives an indication how well the processor
+is utilized. The inverse of the IPC is called CPI.
+
+The @DisplayText{} command automatically computes the IPC and CPI values
+if an experiment contains the event counter values for the instructions
+and CPU cycles executed. These are part of the metric list and can be
+displayed, just like any other metric.
+
+@IndexSubentry{Commands, @code{metric_list}}
+This can be verified through the @code{metric_list} command. If we go
+back to our earlier experiment with the default event counters, we get
+the following result.
+
+@cartouche
+@smallexample
+$ gprofng display text -metric_list mxv.hwc.def.2.thr.er
+@end smallexample
+@end cartouche
+
+@smallexample
+@verbatim
+Current metrics: e.totalcpu:i.totalcpu:e.cycles:e+insts:e+llm:name
+Current Sort Metric: Exclusive Total CPU Time ( e.totalcpu )
+Available metrics:
+         Exclusive Total CPU Time: e.%totalcpu
+         Inclusive Total CPU Time: i.%totalcpu
+             Exclusive CPU Cycles: e.+%cycles
+             Inclusive CPU Cycles: i.+%cycles
+  Exclusive Instructions Executed: e+%insts
+  Inclusive Instructions Executed: i+%insts
+Exclusive Last-Level Cache Misses: e+%llm
+Inclusive Last-Level Cache Misses: i+%llm
+ Exclusive Instructions Per Cycle: e+IPC
+ Inclusive Instructions Per Cycle: i+IPC
+ Exclusive Cycles Per Instruction: e+CPI
+ Inclusive Cycles Per Instruction: i+CPI
+                             Size: size
+                       PC Address: address
+                             Name: name
+@end verbatim
+@end smallexample
+
+Among the other metrics, we see the new metrics for the IPC and CPI 
+listed.
+
+In the script below, we use this information and add the IPC and CPI 
+to the metrics to be displayed. We also use a the thread filter to 
+display these values for the individual threads.
+
+This is the complete script we have used. Other than a different selection
+of the metrics, there are no new features.
+
+@cartouche
+@smallexample
+# Define the metrics
+metrics e.insts:e.%cycles:e.IPC:e.CPI
+# Sort with respect to cycles
+sort e.cycles
+# Limit the output to 5 lines
+limit 5
+# Get the function overview for all threads
+functions
+# Get the function overview for thread 1
+thread_select 1
+functions
+# Get the function overview for thread 2
+thread_select 2
+functions
+# Get the function overview for thread 3
+thread_select 3
+functions
+@end smallexample
+@end cartouche
+
+In the metrics definition on the second line, we explicitly request the 
+counter values for the instructions (@code{e.insts}) and CPU cycles 
+(@code{e.cycles}) executed. These names can be found in output from the
+@code{metric_list} commad above.
+In addition to these metrics, we also request the IPC and CPI to be shown.
+
+As before, we used the @code{limit} command to control the number of 
+functions displayed. We then request an overview for all the threads,
+followed by three sets of two commands to select a thread and display the 
+function overview.
+
+The script above is used as follows:
+
+@cartouche
+@smallexample
+$ gprofng display text -script my-script-ipc mxv.hwc.def.2.thr.er
+@end smallexample
+@end cartouche
+
+This script produces four tables. We list them separately below,
+and have left out the additional output.
+
+The first table shows the accumulated values across the three
+threads that have been active.
+
+@smallexample
+@verbatim
+Functions sorted by metric: Exclusive CPU Cycles
+
+Excl.         Excl. CPU     Excl.  Excl.   Name
+Instructions  Cycles        IPC    CPI
+Executed       sec.      %
+7906475309    2.691 100.00  1.473  0.679   <Total>
+7432724378    2.598  96.54  1.434  0.697   mxv_core
+ 188860269    0.035   1.31  2.682  0.373   erand48_r
+  73623396    0.026   0.95  1.438  0.696   init_data
+  76824434    0.018   0.66  2.182  0.458   drand48
+@end verbatim
+@end smallexample
+
+This shows that IPC of this program is completely dominated
+by function @code{mxv_core}. It has a fairly low IPC value
+of 1.43.
+
+The next table is for thread 1 and shows the values for the 
+main thread.
+
+@smallexample
+@verbatim
+Exp Sel Total
+=== === =====
+  1 1       3
+Functions sorted by metric: Exclusive CPU Cycles
+
+Excl.         Excl. CPU     Excl.  Excl.   Name
+Instructions  Cycles        IPC    CPI
+Executed       sec.      %
+473750931     0.093 100.00  2.552  0.392   <Total>
+188860269     0.035  37.93  2.682  0.373   erand48_r
+ 73623396     0.026  27.59  1.438  0.696   init_data
+ 76824434     0.018  18.97  2.182  0.458   drand48
+134442832     0.013  13.79  5.250  0.190   __drand48_iterate
+@end verbatim
+@end smallexample
+
+Although this thread hardly uses any CPU cycles, the overall IPC 
+of 2.55 is not all that bad.
+
+Last, we show the tables for threads 2 and 3:
+
+@smallexample
+@verbatim
+Exp Sel Total
+=== === =====
+  1 2       3
+Functions sorted by metric: Exclusive CPU Cycles
+
+Excl.         Excl. CPU     Excl.  Excl.   Name
+Instructions  Cycles        IPC    CPI
+Executed       sec.      %
+3716362189    1.298 100.00  1.435  0.697   <Total>
+3716362189    1.298 100.00  1.435  0.697   mxv_core
+         0    0.      0.    0.     0.      collector_root
+         0    0.      0.    0.     0.      driver_mxv
+
+Exp Sel Total
+=== === =====
+  1 3       3
+Functions sorted by metric: Exclusive CPU Cycles
+
+Excl.         Excl. CPU     Excl.  Excl.   Name
+Instructions  Cycles        IPC    CPI
+Executed       sec.      %
+3716362189    1.300 100.00  1.433  0.698   <Total>
+3716362189    1.300 100.00  1.433  0.698   mxv_core
+         0    0.      0.    0.     0.      collector_root
+         0    0.      0.    0.     0.      driver_mxv
+@end verbatim
+@end smallexample
+
+It is seen that both execute the same number of instructions and
+take about the same number of CPU cycles. As a result, the IPC is
+the same for both threads.
+
+@c -- A new node --------------------------------------------------------------
+@c TBD @node    Additional Features
+@c TBD @section Additional Features
+@c ----------------------------------------------------------------------------
+
+@c -- A new node --------------------------------------------------------------
+@c TBD @node    More Filtering Capabilities
+@c TBD @subsection More Filtering Capabilities
+@c ----------------------------------------------------------------------------
+
+@c TBD Cover @code{samples} and @code{seconds}
+
+@c -- A new node --------------------------------------------------------------
+@node    Java Profiling 
+@section Java Profiling
+@c ----------------------------------------------------------------------------
+
+@IndexSubentry{Java profiling, @code{-j on/off}}
+The @CollectApp{} command supports Java profiling. The @code{-j on} option
+can be used for this, but since this feature is enabled by default, there is 
+no need to set this explicitly. Java profiling may be disabled through the 
+@code{-j off} option.
+
+The program is compiled as usual and the experiment directory is created 
+similar to what we have seen before. The only difference with a C/C++
+application is that the program has to be explicitly executed by java.
+
+For example, this is how to generate the experiment data for a Java
+program that has the source code stored in file @code{Pi.java}:
+
+@cartouche
+@smallexample
+$ javac Pi.java
+$ gprofng collect app -j on -O pi.demo.er java Pi < pi.in
+@end smallexample
+@end cartouche
+
+Regarding which java is selected to generate the data, @ToolName{} 
+first looks for the JDK in the path set in either the 
+@IndexSubentry{Java profiling, @code{JDK_HOME}}
+@code{JDK_HOME} environment variable, or in the
+@IndexSubentry{Java profiling, @code{JAVA_PATH}}
+@code{JAVA_PATH} environment variable. If neither of these variables is 
+set, it checks for a JDK in the search path (set in the PATH
+environment variable). If there is no JDK in this path, it checks for 
+the java executable in @code{/usr/java/bin/java}.
+
+In case additional options need to be passed on to the JVM, the 
+@IndexSubentry{Java profiling, @code{-J <string>}}
+@code{-J <string>} option can be used. The string with the
+option(s) has to be delimited by quotation marks in case
+there is more than one argument.
+
+The @DisplayText{} command may be used to view the performance data. There is
+no need for any special options and the same commands as previously discussed
+are supported.
+
+@IndexSubentry{Commands, @code{viewmode}}
+@IndexSubentry{Java profiling, different view modes}
+The @code{viewmode} command 
+@xref{The Viewmode}
+is very useful to examine the call stacks. 
+
+For example, this is how one can see the native call stacks. For
+lay-out purposes we have restricted the list to the first five entries:
+
+@cartouche
+@smallexample
+$ gprofng display text -limit 5 -viewmode machine -calltree pi.demo.er 
+@end smallexample
+@end cartouche
+
+@smallexample
+@verbatim
+Print limit set to 5
+Viewmode set to machine
+Functions Call Tree. Metric: Attributed Total CPU Time
+
+Attr.      Name
+Total
+CPU sec.
+1.381      +-<Total>
+1.171        +-Pi.calculatePi(double)
+0.110        +-collector_root
+0.110        |  +-JavaMain
+0.070        |    +-jni_CallStaticVoidMethod
+@end verbatim
+@end smallexample
+
+@noindent
+Note that the selection of the viewmode is echoed in the output.
+
+@c -- A new node --------------------------------------------------------------
+@c TBD @node Summary of Options and Commands
+@c TBD @chapter Summary of Options and Commands
+@c ----------------------------------------------------------------------------
+
+@c -- A new node --------------------------------------------------------------
+@node    Terminology
+@chapter Terminology
+
+Throughout this manual, certain terminology specific to profiling tools, 
+or @ToolName{}, or even to this document only, is used. In this chapter we 
+explain this terminology in detail.
+
+@menu
+* The Program Counter::                    What is a Program Counter?
+* Inclusive and Exclusive Metrics::        An explanation of inclusive and exclusive metrics.
+* Metric Definitions::                     Definitions associated with metrics.
+* The Viewmode::                           Select the way call stacks are presented.
+* The Selection List::                     How to define a selection.
+* Load Objects and Functions::             The components in an application.
+* The Concept of a CPU in @ProductName{}:: The definition of a CPU.
+* Hardware Event Counters Explained::      What are event counters?
+* apath::                                  Our generic definition of a path.
+@end menu
+
+@c ----------------------------------------------------------------------------
+@node    The Program Counter
+@section The Program Counter
+@c ----------------------------------------------------------------------------
+
+@cindex PC
+@cindex Program Counter
+The @emph{Program Counter}, or PC for short, keeps track where program execution is.
+The address of the next instruction to be executed is stored in a special
+purpose register in the processor, or core.
+
+@cindex Instruction pointer
+The PC is sometimes also referred to as the @emph{instruction pointer}, but
+we will use Program Counter or PC throughout this document.
+
+@c ----------------------------------------------------------------------------
+@node    Inclusive and Exclusive Metrics
+@section Inclusive and Exclusive Metrics
+@c ----------------------------------------------------------------------------
+
+In the remainder, these two concepts occur quite often and for lack of a better
+place, they are explained here.
+
+@cindex Inclusive metric
+The @emph{inclusive} value for a metric includes all values that are part of
+the dynamic extent of the target function. For example if function @code{A}
+calls functions @code{B} and @code{C}, the inclusive CPU time for @code{A} 
+includes the CPU time spent in @code{B} and @code{C}.
+
+@cindex Exclusive metric
+In contrast with this, the @emph{exclusive} value for a metric is computed
+by excluding the metric values used by other functions called. In our imaginary
+example, the exclusive CPU time for function @code{A} is the time spent outside
+calling functions @code{B} and @code{C}.
+
+@cindex Leaf function
+In case of a @emph{leaf function}, the inclusive and exclusive values for the 
+metric are the same since by definition, it is not calling any other 
+function(s).
+
+Why do we use these two different values? The inclusive metric shows the most
+expensive path, in terms of this metric, in the application. For example, if
+the metric is cache misses, the function with the highest inclusive metric
+tells you where most of the cache misses come from.
+
+Within this branch of the application, the exclusive metric points to the
+functions that contribute and help to identify which part(s) to consider
+for further analysis.
+
+@c ----------------------------------------------------------------------------
+@node    Metric Definitions
+@section Metric Definitions
+@c ----------------------------------------------------------------------------
+The metrics to be shown are highly customizable. In this section we explain 
+the definitions associated with metrics.
+
+@IndexSubentry{Commands, @code{metrics}}
+The @code{metrics} command takes a colon (:) separated list with special
+keywords. This keyword consists of the following three fields: 
+@code{<flavor>}@code{<visibility>}@code{<metric_name>}.
+
+@cindex Flavor field
+@cindex Visibility field
+@cindex Metric name field
+The @emph{<flavor>} field is either an @code{e} for ``exclusive'', or @code{i}
+for ``inclusive''. The @code{<metric_name>} field is the name of the metric
+request. The @emph{<visibility>} field consists of one ore more characters
+from the following table:
+
+@table @code
+
+@item .
+Show the metric as time. This applies to timing metrics and hardware event counters
+that measure cycles. Interpret as @code{+} for other metrics.
+
+@item %
+Show the metric as a percentage of the total value for this metric.
+
+@item +
+Show the metric as an absolute value. For hardware event counters this is
+the event count. Interpret as @code{.} for timing metrics.
+
+@item |
+Do not show any metric value. Cannot be used with other visibility characters.
+
+@end table 
+
+@c ----------------------------------------------------------------------------
+@node    The Viewmode
+@section The Viewmode
+
+@cindex Viewmode
+@IndexSubentry{Commands, @code{viewmode}}
+
+There are different ways to view a call stack in Java. In @ToolName{}, this
+is called the @emph{viewmode} and the setting is controlled through a command
+with the same name.
+
+The @code{viewmode} command takes one of the following keywords:
+
+@table @code
+
+@item user
+This is the default and shows the Java call stacks for Java threads.
+No call stacks for any housekeeping threads are shown. The function 
+list contains a function 
+@IndexSubentry{Java profiling, @code{<JVM-System>}}
+@code{<JVM-System>} that represents the aggregated time from non-Java
+threads.
+When the JVM software does not report a Java call stack, time is reported
+against the function 
+@IndexSubentry{Java profiling, @code{<no Java callstack recorded>}}
+@code{<no Java callstack recorded>}.
+
+
+@item expert
+Show the Java call stacks for Java threads when the Java code from the
+user is executed and machine call stacks when JVM code is executed, or 
+when the JVM software does not report a Java call stack. 
+Show the machine call stacks for housekeeping threads.
+
+@item machine
+Show the actual native call stacks for all threads.
+
+@end table
+
+@c ----------------------------------------------------------------------------
+@c ----------------------------------------------------------------------------
+@node    The Selection List
+@section The Selection List
+@c ----------------------------------------------------------------------------
+
+@cindex Selection list
+@cindex List specification
+Several commands allow the user to specify a subset of a list. For example,
+to select specific threads from all the threads that have been used when 
+conducting the experiment(s). 
+
+Such a selection list (or ``list'' in the remainder of this section) can be a 
+single number, a contiguous range of numbers with the start and end numbers 
+separated by a hyphen (@code{-}), a comma-separated list of numbers and 
+ranges, or the @code{all} keyword. Lists must not contain spaces. 
+
+Each list can optionally be preceded by an experiment list with a similar 
+format, separated from the list by a colon (:). 
+If no experiment list is included, the list applies to all experiments.
+
+Multiple lists can be concatenated by separating the individual lists 
+by a plus sign.
+
+These are some examples of various filters using a list:
+
+@table @code
+
+@item thread_select 1
+Select thread 1 from all experiments.
+
+@item thread_select all:1
+Select thread 1 from all experiments.
+
+@item thread_select 1:1+2:2
+Select thread 1 from experiment 1 and thread 2 from experiment 2.
+
+@item cpu_select all:1,3,5
+Selects cores 1, 3, and 5 from all experiments.
+
+@item cpu_select 1,2:all
+Select all cores from experiments 1 and 2, as listed by the @code{by exp_list} command.
+
+@end table
+
+@c ----------------------------------------------------------------------------
+@node    Load Objects and Functions
+@section Load Objects and Functions
+@c ----------------------------------------------------------------------------
+
+An application consists of various components. The source code files are 
+compiled into object files. These are then glued together at link time to form
+the executable. 
+During execution, the program may also dynamically load objects.
+
+@cindex Load object 
+A @emph{load object} is defined to be an executable, or shared object. A shared
+library is an example of a load object in @ToolName{}.
+
+Each load object, contains a text section with the instructions generated by the 
+compiler, a data section for data, and various symbol tables.
+All load objects must contain an 
+@cindex ELF
+ELF 
+symbol table, which gives the names and addresses of all the globally known 
+functions in that object. 
+
+Load objects compiled with the -g option contain additional symbolic information 
+that can augment the ELF symbol table and provide information about functions that 
+are not global, additional information about object modules from which the functions 
+came, and line number information relating addresses to source lines.
+
+The term
+@cindex Function
+@emph{function}
+is used to describe a set of instructions that represent a high-level operation 
+described in the source code. The term also covers methods as used in C++ and in
+the Java programming language. 
+
+In the @ToolName{} context, functions are provided in source code format. 
+Normally their names appear in the symbol table representing a set of addresses. 
+@cindex Program Counter
+@cindex PC
+If the Program Counter (PC) is within that set, the program is executing within that function.
+
+In principle, any address within the text segment of a load object can be mapped to a 
+function. Exactly the same mapping is used for the leaf PC and all the other PCs on the 
+call stack. 
+
+Most of the functions correspond directly to the source model of the program, but 
+there are exceptions. This topic is however outside of the scope of this guide.
+
+@c ----------------------------------------------------------------------------
+@node    The Concept of a CPU in @ProductName{}
+@section The Concept of a CPU in @ProductName{}
+@c ----------------------------------------------------------------------------
+
+@cindex CPU
+In @ProductName{}, there is the concept of a CPU. Admittedly, this is not the
+best word to describe what is meant here and may be replaced in the future.
+
+The word CPU is used in many of the displays.
+In the context of @ProductName{}, it is meant to denote a part of the 
+processor that is capable of executing instructions and with its own state, 
+like the program counter.
+
+For example, on a contemporary processor, a CPU could be a core. In case
+hardware threads are supported within a core, it could be one of those
+hardware threads.
+
+@c ----------------------------------------------------------------------------
+@node    Hardware Event Counters Explained
+@section Hardware Event Counters Explained
+@c ----------------------------------------------------------------------------
+
+@IndexSubentry{Hardware event counters, description}
+For quite a number of years now, many microprocessors have supported hardware 
+event counters. 
+
+On the hardware side, this means that in the processor there are one or more 
+registers dedicated to count certain activities, or ``events''.
+Examples of such events are the number of instructions executed, or the number 
+of cache misses at level 2 in the memory hierarchy.
+
+While there is a limited set of such registers, the user can map events onto
+them. In case more than one register is available, this allows for the 
+simultaenous measurement of various events.
+
+A simple, yet powerful, example is to simultaneously count the number of CPU 
+cycles and the number of instructions excuted. These two numbers can then be
+used to compute the 
+@cindex IPC
+@emph{IPC} value. IPC stands for ``Instructions Per Clockcycle'' and each processor 
+has a maximum. For example, if this maximum number is 2, it means the 
+processor is capable of executing two instructions every clock cycle.
+
+Whether this is actually achieved, depends on several factors, including the
+instruction characteristics.
+However, in case the IPC value is well below this maximum in a time critical 
+part of the application and this cannot be easily explained, further 
+investigation is probably warranted.
+
+@cindex CPI
+A related metric is called @emph{CPI}, or ``Clockcycles Per Instruction''.
+It is the inverse of the CPI and can be compared against the theoretical
+value(s) of the target instruction(s). A significant difference may point
+at a bottleneck.
+
+One thing to keep in mind is that the value returned by a counter can either
+be the number of times the event occured, or a CPU cycle count. In case of 
+the latter it is possible to convert this number to time.
+
+@IndexSubentry{Hardware event counters, variable CPU frequency}
+This is often easier to interpret than a simple count, but there is one
+caveat to keep in mind. The CPU frequency may not have been constant while
+the experimen was recorded and this impacts the time reported.
+
+These event counters, or ``counters'' for short, provide great insight into
+what happens deep inside the processor. In case higher level information does
+not provide the insight needed, the counters provide the information to get 
+to the bottom of a performance problem.
+
+There are some things to consider though. 
+
+@itemize @bullet
+
+@item
+The event definitions and names vary across processors and it may even happen 
+that some events change with an update.
+Unfortunately and this is luckily rare, there are sometimes bugs causing the 
+wrong count to be returned.
+
+@IndexSubentry{Hardware event counters, alias name}
+In @ToolName{}, some of the processor specific event names have an alias 
+name. For example @code{insts} measures the instructions executed. 
+These aliases not only makes it easier to identify the functionality, but also 
+provide portability of certain events across processors.
+
+@item
+Another complexity is that there are typically many events one can monitor.
+There may up to hundreds of events available and it could require several
+experiments to zoom in on the root cause of a performance problem.
+
+@item
+There may be restrictions regarding the mapping of event(s) onto the 
+counters. For example, certain events may be restricted to specific 
+counters only. As a result, one may have to conduct additional experiments
+to cover all the events of interest.
+
+@item
+The names of the events may also not be easy to interpret. In such cases,
+the description can be found in the architecture manual for the processor.
+
+@end itemize
+
+Despite these drawbacks, hardware event counters are extremely useful and
+may even turn out to be indispensable.
+
+@c ----------------------------------------------------------------------------
+@node    apath
+@section What is <apath>?
+@c ----------------------------------------------------------------------------
+
+In most cases, @ToolName{} shows the absolute pathnames of directories. These
+tend to be rather long, causing display issues in this document. 
+
+Instead of wrapping these long pathnames over multiple lines, we decided to 
+represent them by the @code{<apath>} symbol, which stands for ``an absolute 
+pathname''.
+
+Note that different occurrences of @code{<apath>} may represent different
+absolute pathnames.
+
+@c -- A new node --------------------------------------------------------------
+@node    Other Document Formats
+@chapter Other Document Formats
+@c ----------------------------------------------------------------------------
+
+This document is written in Texinfo and the source text is made available as
+part of the binutils distribution. The file name is @code{gprofng.texi} and
+can be found in subdirectory @code{doc} under directory @code{gprofng} in the 
+top level directory.
+
+This file can be used to generate the document in the @code{info}, @code{html}, 
+and @code{pdf} formats.
+The default installation procedure creates a file in the @code{info} format and 
+stores it in the documentation section of binutils.
+
+The probably easiest way to generate a different format from this Texinfo 
+document is to go to the distribution directory that was created when the 
+tools were built.
+This is either the default distribution directory, or the one that has been set
+with the @code{--prefix} option as part of the @code{configure} command.
+In this example we symbolize this location with @code{<dist>}.
+
+The make file called @code{Makefile} in directory @code{<dist>/gprofng/doc}
+supports several commands to generate this document in different formats. 
+We recommend to use these commands.
+
+They create the file(s) and install it in the documentation directory of binutils,
+which is @code{<dist>/share/doc} in case @code{html} or @code{pdf} is selected and
+@code{<dist>/share/info} for the file in the @code{info} format.
+
+To generate this document in the requested format and install it in the documentation 
+directory, the commands below should be executed. In this notation, @code{<format>} 
+is one of @code{info}, @code{html}, or @code{pdf}:
+
+@smallexample
+@verbatim
+$ cd <dist>/gprofng/doc
+$ make install-<format>
+@end verbatim
+@end smallexample
+
+@noindent
+Some things to note:
+
+@itemize
+
+@item
+For the @code{pdf} file to be generated, the 
+@cindex TeX
+TeX document formatting software is required and the relevant commmands need
+to be included in the search path. An example of a popular TeX implementation 
+is @emph{TexLive}. It is beyond the scope of this document to go into the
+details of installing and using TeX, but it is well documented elsewhere.
+
+@item
+Instead of generating a single file in the @code{html} format, it is also 
+possible to create a directory with individual files for the various chapters. 
+To do so, remove the use of @code{--no-split} in variable @code{MAKEINFOHTML}
+in the make file in the @code{doc} directory.
+
+@item
+The make file also supports commands to only generate the file in the desired
+format and not move them to the documentation directory. This is
+accomplished through the @code{make <format>} command.
+
+@end itemize
+
+@ifnothtml
+@node       Index
+@unnumbered Index
+@printindex cp
+@end ifnothtml
+
+@bye
diff --git a/gprofng/doc/mdate-sh b/gprofng/doc/mdate-sh
new file mode 100755 (executable)
index 0000000..f80075c
--- /dev/null
@@ -0,0 +1,224 @@
+#!/bin/sh
+# Get modification time of a file or directory and pretty-print it.
+
+scriptversion=2016-01-11.22; # UTC
+
+# Copyright (C) 1995-2017 Free Software Foundation, Inc.
+# written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+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
+fi
+
+case $1 in
+  '')
+     echo "$0: No file.  Try '$0 --help' for more information." 1>&2
+     exit 1;
+     ;;
+  -h | --h*)
+    cat <<\EOF
+Usage: mdate-sh [--help] [--version] FILE
+
+Pretty-print the modification day of FILE, in the format:
+1 January 1970
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+    exit $?
+    ;;
+  -v | --v*)
+    echo "mdate-sh $scriptversion"
+    exit $?
+    ;;
+esac
+
+error ()
+{
+  echo "$0: $1" >&2
+  exit 1
+}
+
+
+# Prevent date giving response in another language.
+LANG=C
+export LANG
+LC_ALL=C
+export LC_ALL
+LC_TIME=C
+export LC_TIME
+
+# GNU ls changes its time format in response to the TIME_STYLE
+# variable.  Since we cannot assume 'unset' works, revert this
+# variable to its documented default.
+if test "${TIME_STYLE+set}" = set; then
+  TIME_STYLE=posix-long-iso
+  export TIME_STYLE
+fi
+
+save_arg1=$1
+
+# Find out how to get the extended ls output of a file or directory.
+if ls -L /dev/null 1>/dev/null 2>&1; then
+  ls_command='ls -L -l -d'
+else
+  ls_command='ls -l -d'
+fi
+# Avoid user/group names that might have spaces, when possible.
+if ls -n /dev/null 1>/dev/null 2>&1; then
+  ls_command="$ls_command -n"
+fi
+
+# A 'ls -l' line looks as follows on OS/2.
+#  drwxrwx---        0 Aug 11  2001 foo
+# This differs from Unix, which adds ownership information.
+#  drwxrwx---   2 root  root      4096 Aug 11  2001 foo
+#
+# To find the date, we split the line on spaces and iterate on words
+# until we find a month.  This cannot work with files whose owner is a
+# user named "Jan", or "Feb", etc.  However, it's unlikely that '/'
+# will be owned by a user whose name is a month.  So we first look at
+# the extended ls output of the root directory to decide how many
+# words should be skipped to get the date.
+
+# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below.
+set x`$ls_command /`
+
+# Find which argument is the month.
+month=
+command=
+until test $month
+do
+  test $# -gt 0 || error "failed parsing '$ls_command /' output"
+  shift
+  # Add another shift to the command.
+  command="$command shift;"
+  case $1 in
+    Jan) month=January; nummonth=1;;
+    Feb) month=February; nummonth=2;;
+    Mar) month=March; nummonth=3;;
+    Apr) month=April; nummonth=4;;
+    May) month=May; nummonth=5;;
+    Jun) month=June; nummonth=6;;
+    Jul) month=July; nummonth=7;;
+    Aug) month=August; nummonth=8;;
+    Sep) month=September; nummonth=9;;
+    Oct) month=October; nummonth=10;;
+    Nov) month=November; nummonth=11;;
+    Dec) month=December; nummonth=12;;
+  esac
+done
+
+test -n "$month" || error "failed parsing '$ls_command /' output"
+
+# Get the extended ls output of the file or directory.
+set dummy x`eval "$ls_command \"\\\$save_arg1\""`
+
+# Remove all preceding arguments
+eval $command
+
+# Because of the dummy argument above, month is in $2.
+#
+# On a POSIX system, we should have
+#
+# $# = 5
+# $1 = file size
+# $2 = month
+# $3 = day
+# $4 = year or time
+# $5 = filename
+#
+# On Darwin 7.7.0 and 7.6.0, we have
+#
+# $# = 4
+# $1 = day
+# $2 = month
+# $3 = year or time
+# $4 = filename
+
+# Get the month.
+case $2 in
+  Jan) month=January; nummonth=1;;
+  Feb) month=February; nummonth=2;;
+  Mar) month=March; nummonth=3;;
+  Apr) month=April; nummonth=4;;
+  May) month=May; nummonth=5;;
+  Jun) month=June; nummonth=6;;
+  Jul) month=July; nummonth=7;;
+  Aug) month=August; nummonth=8;;
+  Sep) month=September; nummonth=9;;
+  Oct) month=October; nummonth=10;;
+  Nov) month=November; nummonth=11;;
+  Dec) month=December; nummonth=12;;
+esac
+
+case $3 in
+  ???*) day=$1;;
+  *) day=$3; shift;;
+esac
+
+# Here we have to deal with the problem that the ls output gives either
+# the time of day or the year.
+case $3 in
+  *:*) set `date`; eval year=\$$#
+       case $2 in
+        Jan) nummonthtod=1;;
+        Feb) nummonthtod=2;;
+        Mar) nummonthtod=3;;
+        Apr) nummonthtod=4;;
+        May) nummonthtod=5;;
+        Jun) nummonthtod=6;;
+        Jul) nummonthtod=7;;
+        Aug) nummonthtod=8;;
+        Sep) nummonthtod=9;;
+        Oct) nummonthtod=10;;
+        Nov) nummonthtod=11;;
+        Dec) nummonthtod=12;;
+       esac
+       # For the first six month of the year the time notation can also
+       # be used for files modified in the last year.
+       if (expr $nummonth \> $nummonthtod) > /dev/null;
+       then
+        year=`expr $year - 1`
+       fi;;
+  *) year=$3;;
+esac
+
+# The result.
+echo $day $month $year
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC0"
+# time-stamp-end: "; # UTC"
+# End:
diff --git a/gprofng/doc/texinfo.tex b/gprofng/doc/texinfo.tex
new file mode 100644 (file)
index 0000000..2bab634
--- /dev/null
@@ -0,0 +1,11731 @@
+% texinfo.tex -- TeX macros to handle Texinfo files.
+%
+% Load plain if necessary, i.e., if running under initex.
+\expandafter\ifx\csname fmtname\endcsname\relax\input plain\fi
+%
+\def\texinfoversion{2021-02-20.11}
+%
+% Copyright 1985, 1986, 1988, 1990-2021 Free Software Foundation, Inc.
+%
+% This texinfo.tex 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 texinfo.tex file 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, see <https://www.gnu.org/licenses/>.
+%
+% As a special exception, when this file is read by TeX when processing
+% a Texinfo source document, you may use the result without
+% restriction. This Exception is an additional permission under section 7
+% of the GNU General Public License, version 3 ("GPLv3").
+%
+% Please try the latest version of texinfo.tex before submitting bug
+% reports; you can get the latest version from:
+%   https://ftp.gnu.org/gnu/texinfo/ (the Texinfo release area), or
+%   https://ftpmirror.gnu.org/texinfo/ (same, via a mirror), or
+%   https://www.gnu.org/software/texinfo/ (the Texinfo home page)
+% The texinfo.tex in any given distribution could well be out
+% of date, so if that's what you're using, please check.
+%
+% Send bug reports to bug-texinfo@gnu.org.  Please include a
+% complete document in each bug report with which we can reproduce the
+% problem.  Patches are, of course, greatly appreciated.
+%
+% To process a Texinfo manual with TeX, it's most reliable to use the
+% texi2dvi shell script that comes with the distribution.  For a simple
+% manual foo.texi, however, you can get away with this:
+%   tex foo.texi
+%   texindex foo.??
+%   tex foo.texi
+%   tex foo.texi
+%   dvips foo.dvi -o  # or whatever; this makes foo.ps.
+% The extra TeX runs get the cross-reference information correct.
+% Sometimes one run after texindex suffices, and sometimes you need more
+% than two; texi2dvi does it as many times as necessary.
+%
+% It is possible to adapt texinfo.tex for other languages, to some
+% extent.  You can get the existing language-specific files from the
+% full Texinfo distribution.
+%
+% The GNU Texinfo home page is https://www.gnu.org/software/texinfo.
+
+
+\message{Loading texinfo [version \texinfoversion]:}
+
+% If in a .fmt file, print the version number
+% and turn on active characters that we couldn't do earlier because
+% they might have appeared in the input file name.
+\everyjob{\message{[Texinfo version \texinfoversion]}%
+  \catcode`+=\active \catcode`\_=\active}
+
+% LaTeX's \typeout.  This ensures that the messages it is used for
+% are identical in format to the corresponding ones from latex/pdflatex.
+\def\typeout{\immediate\write17}%
+
+\chardef\other=12
+
+% We never want plain's \outer definition of \+ in Texinfo.
+% For @tex, we can use \tabalign.
+\let\+ = \relax
+
+% Save some plain tex macros whose names we will redefine.
+\let\ptexb=\b
+\let\ptexbullet=\bullet
+\let\ptexc=\c
+\let\ptexcomma=\,
+\let\ptexdot=\.
+\let\ptexdots=\dots
+\let\ptexend=\end
+\let\ptexequiv=\equiv
+\let\ptexexclam=\!
+\let\ptexfootnote=\footnote
+\let\ptexgtr=>
+\let\ptexhat=^
+\let\ptexi=\i
+\let\ptexindent=\indent
+\let\ptexinsert=\insert
+\let\ptexlbrace=\{
+\let\ptexless=<
+\let\ptexnewwrite\newwrite
+\let\ptexnoindent=\noindent
+\let\ptexplus=+
+\let\ptexraggedright=\raggedright
+\let\ptexrbrace=\}
+\let\ptexslash=\/
+\let\ptexsp=\sp
+\let\ptexstar=\*
+\let\ptexsup=\sup
+\let\ptext=\t
+\let\ptextop=\top
+{\catcode`\'=\active \global\let\ptexquoteright'}% active in plain's math mode
+
+% If this character appears in an error message or help string, it
+% starts a new line in the output.
+\newlinechar = `^^J
+
+% Use TeX 3.0's \inputlineno to get the line number, for better error
+% messages, but if we're using an old version of TeX, don't do anything.
+%
+\ifx\inputlineno\thisisundefined
+  \let\linenumber = \empty % Pre-3.0.
+\else
+  \def\linenumber{l.\the\inputlineno:\space}
+\fi
+
+% Set up fixed words for English if not already set.
+\ifx\putwordAppendix\undefined  \gdef\putwordAppendix{Appendix}\fi
+\ifx\putwordChapter\undefined   \gdef\putwordChapter{Chapter}\fi
+\ifx\putworderror\undefined     \gdef\putworderror{error}\fi
+\ifx\putwordfile\undefined      \gdef\putwordfile{file}\fi
+\ifx\putwordin\undefined        \gdef\putwordin{in}\fi
+\ifx\putwordIndexIsEmpty\undefined       \gdef\putwordIndexIsEmpty{(Index is empty)}\fi
+\ifx\putwordIndexNonexistent\undefined   \gdef\putwordIndexNonexistent{(Index is nonexistent)}\fi
+\ifx\putwordInfo\undefined      \gdef\putwordInfo{Info}\fi
+\ifx\putwordInstanceVariableof\undefined \gdef\putwordInstanceVariableof{Instance Variable of}\fi
+\ifx\putwordMethodon\undefined  \gdef\putwordMethodon{Method on}\fi
+\ifx\putwordNoTitle\undefined   \gdef\putwordNoTitle{No Title}\fi
+\ifx\putwordof\undefined        \gdef\putwordof{of}\fi
+\ifx\putwordon\undefined        \gdef\putwordon{on}\fi
+\ifx\putwordpage\undefined      \gdef\putwordpage{page}\fi
+\ifx\putwordsection\undefined   \gdef\putwordsection{section}\fi
+\ifx\putwordSection\undefined   \gdef\putwordSection{Section}\fi
+\ifx\putwordsee\undefined       \gdef\putwordsee{see}\fi
+\ifx\putwordSee\undefined       \gdef\putwordSee{See}\fi
+\ifx\putwordShortTOC\undefined  \gdef\putwordShortTOC{Short Contents}\fi
+\ifx\putwordTOC\undefined       \gdef\putwordTOC{Table of Contents}\fi
+%
+\ifx\putwordMJan\undefined \gdef\putwordMJan{January}\fi
+\ifx\putwordMFeb\undefined \gdef\putwordMFeb{February}\fi
+\ifx\putwordMMar\undefined \gdef\putwordMMar{March}\fi
+\ifx\putwordMApr\undefined \gdef\putwordMApr{April}\fi
+\ifx\putwordMMay\undefined \gdef\putwordMMay{May}\fi
+\ifx\putwordMJun\undefined \gdef\putwordMJun{June}\fi
+\ifx\putwordMJul\undefined \gdef\putwordMJul{July}\fi
+\ifx\putwordMAug\undefined \gdef\putwordMAug{August}\fi
+\ifx\putwordMSep\undefined \gdef\putwordMSep{September}\fi
+\ifx\putwordMOct\undefined \gdef\putwordMOct{October}\fi
+\ifx\putwordMNov\undefined \gdef\putwordMNov{November}\fi
+\ifx\putwordMDec\undefined \gdef\putwordMDec{December}\fi
+%
+\ifx\putwordDefmac\undefined    \gdef\putwordDefmac{Macro}\fi
+\ifx\putwordDefspec\undefined   \gdef\putwordDefspec{Special Form}\fi
+\ifx\putwordDefvar\undefined    \gdef\putwordDefvar{Variable}\fi
+\ifx\putwordDefopt\undefined    \gdef\putwordDefopt{User Option}\fi
+\ifx\putwordDeffunc\undefined   \gdef\putwordDeffunc{Function}\fi
+
+% Give the space character the catcode for a space.
+\def\spaceisspace{\catcode`\ =10\relax}
+
+% Likewise for ^^M, the end of line character.
+\def\endlineisspace{\catcode13=10\relax}
+
+\chardef\dashChar  = `\-
+\chardef\slashChar = `\/
+\chardef\underChar = `\_
+
+% Ignore a token.
+%
+\def\gobble#1{}
+
+% The following is used inside several \edef's.
+\def\makecsname#1{\expandafter\noexpand\csname#1\endcsname}
+
+% Hyphenation fixes.
+\hyphenation{
+  Flor-i-da Ghost-script Ghost-view Mac-OS Post-Script
+  ap-pen-dix bit-map bit-maps
+  data-base data-bases eshell fall-ing half-way long-est man-u-script
+  man-u-scripts mini-buf-fer mini-buf-fers over-view par-a-digm
+  par-a-digms rath-er rec-tan-gu-lar ro-bot-ics se-vere-ly set-up spa-ces
+  spell-ing spell-ings
+  stand-alone strong-est time-stamp time-stamps which-ever white-space
+  wide-spread wrap-around
+}
+
+% Sometimes it is convenient to have everything in the transcript file
+% and nothing on the terminal.  We don't just call \tracingall here,
+% since that produces some useless output on the terminal.  We also make
+% some effort to order the tracing commands to reduce output in the log
+% file; cf. trace.sty in LaTeX.
+%
+\def\gloggingall{\begingroup \globaldefs = 1 \loggingall \endgroup}%
+\def\loggingall{%
+  \tracingstats2
+  \tracingpages1
+  \tracinglostchars2  % 2 gives us more in etex
+  \tracingparagraphs1
+  \tracingoutput1
+  \tracingmacros2
+  \tracingrestores1
+  \showboxbreadth\maxdimen \showboxdepth\maxdimen
+  \ifx\eTeXversion\thisisundefined\else % etex gives us more logging
+    \tracingscantokens1
+    \tracingifs1
+    \tracinggroups1
+    \tracingnesting2
+    \tracingassigns1
+  \fi
+  \tracingcommands3  % 3 gives us more in etex
+  \errorcontextlines16
+}%
+
+% @errormsg{MSG}.  Do the index-like expansions on MSG, but if things
+% aren't perfect, it's not the end of the world, being an error message,
+% after all.
+%
+\def\errormsg{\begingroup \indexnofonts \doerrormsg}
+\def\doerrormsg#1{\errmessage{#1}}
+
+% add check for \lastpenalty to plain's definitions.  If the last thing
+% we did was a \nobreak, we don't want to insert more space.
+%
+\def\smallbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\smallskipamount
+  \removelastskip\penalty-50\smallskip\fi\fi}
+\def\medbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\medskipamount
+  \removelastskip\penalty-100\medskip\fi\fi}
+\def\bigbreak{\ifnum\lastpenalty<10000\par\ifdim\lastskip<\bigskipamount
+  \removelastskip\penalty-200\bigskip\fi\fi}
+
+%\f Output routine
+%
+
+% For a final copy, take out the rectangles
+% that mark overfull boxes (in case you have decided
+% that the text looks ok even though it passes the margin).
+%
+\def\finalout{\overfullrule=0pt }
+
+\newdimen\outerhsize \newdimen\outervsize % set by the paper size routines
+\newdimen\topandbottommargin \topandbottommargin=.75in
+
+% Output a mark which sets \thischapter, \thissection and \thiscolor.
+% We dump everything together because we only have one kind of mark.
+% This works because we only use \botmark / \topmark, not \firstmark.
+%
+% A mark contains a subexpression of the \ifcase ... \fi construct.
+% \get*marks macros below extract the needed part using \ifcase.
+%
+% Another complication is to let the user choose whether \thischapter
+% (\thissection) refers to the chapter (section) in effect at the top
+% of a page, or that at the bottom of a page.
+
+% \domark is called twice inside \chapmacro, to add one
+% mark before the section break, and one after.
+%   In the second call \prevchapterdefs is the same as \currentchapterdefs,
+% and \prevsectiondefs is the same as \currentsectiondefs.
+%   Then if the page is not broken at the mark, some of the previous
+% section appears on the page, and we can get the name of this section
+% from \firstmark for @everyheadingmarks top.
+%   @everyheadingmarks bottom uses \botmark.
+%
+% See page 260 of The TeXbook.
+\def\domark{%
+  \toks0=\expandafter{\currentchapterdefs}%
+  \toks2=\expandafter{\currentsectiondefs}%
+  \toks4=\expandafter{\prevchapterdefs}%
+  \toks6=\expandafter{\prevsectiondefs}%
+  \toks8=\expandafter{\currentcolordefs}%
+  \mark{%
+                   \the\toks0 \the\toks2  % 0: marks for @everyheadingmarks top
+      \noexpand\or \the\toks4 \the\toks6  % 1: for @everyheadingmarks bottom
+    \noexpand\else \the\toks8             % 2: color marks
+  }%
+}
+
+% \gettopheadingmarks, \getbottomheadingmarks,
+% \getcolormarks - extract needed part of mark.
+%
+% \topmark doesn't work for the very first chapter (after the title
+% page or the contents), so we use \firstmark there -- this gets us
+% the mark with the chapter defs, unless the user sneaks in, e.g.,
+% @setcolor (or @url, or @link, etc.) between @contents and the very
+% first @chapter.
+\def\gettopheadingmarks{%
+  \ifcase0\the\savedtopmark\fi
+  \ifx\thischapter\empty \ifcase0\firstmark\fi \fi
+}
+\def\getbottomheadingmarks{\ifcase1\botmark\fi}
+\def\getcolormarks{\ifcase2\the\savedtopmark\fi}
+
+% Avoid "undefined control sequence" errors.
+\def\currentchapterdefs{}
+\def\currentsectiondefs{}
+\def\currentsection{}
+\def\prevchapterdefs{}
+\def\prevsectiondefs{}
+\def\currentcolordefs{}
+
+% Margin to add to right of even pages, to left of odd pages.
+\newdimen\bindingoffset
+\newdimen\normaloffset
+\newdimen\txipagewidth \newdimen\txipageheight
+
+% Main output routine.
+%
+\chardef\PAGE = 255
+\newtoks\defaultoutput
+\defaultoutput = {\savetopmark\onepageout{\pagecontents\PAGE}}
+\output=\expandafter{\the\defaultoutput}
+
+\newbox\headlinebox
+\newbox\footlinebox
+
+% When outputting the double column layout for indices, an output routine
+% is run several times, which hides the original value of \topmark.  This
+% can lead to a page heading being output and duplicating the chapter heading
+% of the index.  Hence, save the contents of \topmark at the beginning of
+% the output routine.  The saved contents are valid until we actually
+% \shipout a page.
+%
+% (We used to run a short output routine to actually set \topmark and
+% \firstmark to the right values, but if this was called with an empty page
+% containing whatsits for writing index entries, the whatsits would be thrown
+% away and the index auxiliary file would remain empty.)
+%
+\newtoks\savedtopmark
+\newif\iftopmarksaved
+\topmarksavedtrue
+\def\savetopmark{%
+  \iftopmarksaved\else
+    \global\savedtopmark=\expandafter{\topmark}%
+    \global\topmarksavedtrue
+  \fi
+}
+
+% \onepageout takes a vbox as an argument.
+% \shipout a vbox for a single page, adding an optional header, footer
+% and footnote.  This also causes index entries for this page to be written
+% to the auxiliary files.
+%
+\def\onepageout#1{%
+  \hoffset=\normaloffset
+  %
+  \ifodd\pageno  \advance\hoffset by \bindingoffset
+  \else \advance\hoffset by -\bindingoffset\fi
+  %
+  \checkchapterpage
+  %
+  % Retrieve the information for the headings from the marks in the page,
+  % and call Plain TeX's \makeheadline and \makefootline, which use the
+  % values in \headline and \footline.
+  %
+  % Common context changes for both heading and footing.
+  % Do this outside of the \shipout so @code etc. will be expanded in
+  % the headline as they should be, not taken literally (outputting ''code).
+  \def\commonheadfootline{\let\hsize=\txipagewidth \texinfochars}
+  %
+  \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi
+  \global\setbox\headlinebox = \vbox{\commonheadfootline \makeheadline}%
+  \ifodd\pageno \getoddfootingmarks \else \getevenfootingmarks \fi
+  \global\setbox\footlinebox = \vbox{\commonheadfootline \makefootline}%
+  %
+  {%
+    % Set context for writing to auxiliary files like index files.
+    % Have to do this stuff outside the \shipout because we want it to
+    % take effect in \write's, yet the group defined by the \vbox ends
+    % before the \shipout runs.
+    %
+    \atdummies         % don't expand commands in the output.
+    \turnoffactive
+    \shipout\vbox{%
+      % Do this early so pdf references go to the beginning of the page.
+      \ifpdfmakepagedest \pdfdest name{\the\pageno} xyz\fi
+      %
+      \unvbox\headlinebox
+      \pagebody{#1}%
+      \ifdim\ht\footlinebox > 0pt
+        % Only leave this space if the footline is nonempty.
+        % (We lessened \vsize for it in \oddfootingyyy.)
+        % The \baselineskip=24pt in plain's \makefootline has no effect.
+        \vskip 24pt
+        \unvbox\footlinebox
+      \fi
+      %
+    }%
+  }%
+  \global\topmarksavedfalse
+  \advancepageno
+  \ifnum\outputpenalty>-20000 \else\dosupereject\fi
+}
+
+\newinsert\margin \dimen\margin=\maxdimen
+
+% Main part of page, including any footnotes
+\def\pagebody#1{\vbox to\txipageheight{\boxmaxdepth=\maxdepth #1}}
+{\catcode`\@ =11
+\gdef\pagecontents#1{\ifvoid\topins\else\unvbox\topins\fi
+% marginal hacks, juha@viisa.uucp (Juha Takala)
+\ifvoid\margin\else % marginal info is present
+  \rlap{\kern\hsize\vbox to\z@{\kern1pt\box\margin \vss}}\fi
+\dimen@=\dp#1\relax \unvbox#1\relax
+\ifvoid\footins\else\vskip\skip\footins\footnoterule \unvbox\footins\fi
+\ifr@ggedbottom \kern-\dimen@ \vfil \fi}
+}
+
+% Check if we are on the first page of a chapter.  Used for printing headings.
+\newif\ifchapterpage
+\def\checkchapterpage{%
+  % Get the chapter that was current at the end of the last page
+  \ifcase1\the\savedtopmark\fi
+  \let\prevchaptername\thischaptername
+  %
+  \ifodd\pageno \getoddheadingmarks \else \getevenheadingmarks \fi
+  \let\curchaptername\thischaptername
+  %
+  \ifx\curchaptername\prevchaptername
+    \chapterpagefalse
+  \else
+    \chapterpagetrue
+  \fi
+}
+
+% Argument parsing
+
+% Parse an argument, then pass it to #1.  The argument is the rest of
+% the input line (except we remove a trailing comment).  #1 should be a
+% macro which expects an ordinary undelimited TeX argument.
+% For example, \def\foo{\parsearg\fooxxx}.
+%
+\def\parsearg{\parseargusing{}}
+\def\parseargusing#1#2{%
+  \def\argtorun{#2}%
+  \begingroup
+    \obeylines
+    \spaceisspace
+    #1%
+    \parseargline\empty% Insert the \empty token, see \finishparsearg below.
+}
+
+{\obeylines %
+  \gdef\parseargline#1^^M{%
+    \endgroup % End of the group started in \parsearg.
+    \argremovecomment #1\comment\ArgTerm%
+  }%
+}
+
+% First remove any @comment, then any @c comment.  Pass the result on to
+% \argcheckspaces.
+\def\argremovecomment#1\comment#2\ArgTerm{\argremovec #1\c\ArgTerm}
+\def\argremovec#1\c#2\ArgTerm{\argcheckspaces#1\^^M\ArgTerm}
+
+% Each occurrence of `\^^M' or `<space>\^^M' is replaced by a single space.
+%
+% \argremovec might leave us with trailing space, e.g.,
+%    @end itemize  @c foo
+% This space token undergoes the same procedure and is eventually removed
+% by \finishparsearg.
+%
+\def\argcheckspaces#1\^^M{\argcheckspacesX#1\^^M \^^M}
+\def\argcheckspacesX#1 \^^M{\argcheckspacesY#1\^^M}
+\def\argcheckspacesY#1\^^M#2\^^M#3\ArgTerm{%
+  \def\temp{#3}%
+  \ifx\temp\empty
+    % Do not use \next, perhaps the caller of \parsearg uses it; reuse \temp:
+    \let\temp\finishparsearg
+  \else
+    \let\temp\argcheckspaces
+  \fi
+  % Put the space token in:
+  \temp#1 #3\ArgTerm
+}
+
+% If a _delimited_ argument is enclosed in braces, they get stripped; so
+% to get _exactly_ the rest of the line, we had to prevent such situation.
+% We prepended an \empty token at the very beginning and we expand it now,
+% just before passing the control to \argtorun.
+% (Similarly, we have to think about #3 of \argcheckspacesY above: it is
+% either the null string, or it ends with \^^M---thus there is no danger
+% that a pair of braces would be stripped.
+%
+% But first, we have to remove the trailing space token.
+%
+\def\finishparsearg#1 \ArgTerm{\expandafter\argtorun\expandafter{#1}}
+
+
+% \parseargdef - define a command taking an argument on the line
+%
+% \parseargdef\foo{...}
+%      is roughly equivalent to
+% \def\foo{\parsearg\Xfoo}
+% \def\Xfoo#1{...}
+\def\parseargdef#1{%
+  \expandafter \doparseargdef \csname\string#1\endcsname #1%
+}
+\def\doparseargdef#1#2{%
+  \def#2{\parsearg#1}%
+  \def#1##1%
+}
+
+% Several utility definitions with active space:
+{
+  \obeyspaces
+  \gdef\obeyedspace{ }
+
+  % Make each space character in the input produce a normal interword
+  % space in the output.  Don't allow a line break at this space, as this
+  % is used only in environments like @example, where each line of input
+  % should produce a line of output anyway.
+  %
+  \gdef\sepspaces{\obeyspaces\let =\tie}
+
+  % If an index command is used in an @example environment, any spaces
+  % therein should become regular spaces in the raw index file, not the
+  % expansion of \tie (\leavevmode \penalty \@M \ ).
+  \gdef\unsepspaces{\let =\space}
+}
+
+
+\def\flushcr{\ifx\par\lisppar \def\next##1{}\else \let\next=\relax \fi \next}
+
+% Define the framework for environments in texinfo.tex.  It's used like this:
+%
+%   \envdef\foo{...}
+%   \def\Efoo{...}
+%
+% It's the responsibility of \envdef to insert \begingroup before the
+% actual body; @end closes the group after calling \Efoo.  \envdef also
+% defines \thisenv, so the current environment is known; @end checks
+% whether the environment name matches.  The \checkenv macro can also be
+% used to check whether the current environment is the one expected.
+%
+% Non-false conditionals (@iftex, @ifset) don't fit into this, so they
+% are not treated as environments; they don't open a group.  (The
+% implementation of @end takes care not to call \endgroup in this
+% special case.)
+
+
+% At run-time, environments start with this:
+\def\startenvironment#1{\begingroup\def\thisenv{#1}}
+% initialize
+\let\thisenv\empty
+
+% ... but they get defined via ``\envdef\foo{...}'':
+\long\def\envdef#1#2{\def#1{\startenvironment#1#2}}
+\def\envparseargdef#1#2{\parseargdef#1{\startenvironment#1#2}}
+
+% Check whether we're in the right environment:
+\def\checkenv#1{%
+  \def\temp{#1}%
+  \ifx\thisenv\temp
+  \else
+    \badenverr
+  \fi
+}
+
+% Environment mismatch, #1 expected:
+\def\badenverr{%
+  \errhelp = \EMsimple
+  \errmessage{This command can appear only \inenvironment\temp,
+    not \inenvironment\thisenv}%
+}
+\def\inenvironment#1{%
+  \ifx#1\empty
+    outside of any environment%
+  \else
+    in environment \expandafter\string#1%
+  \fi
+}
+
+
+% @end foo calls \checkenv and executes the definition of \Efoo.
+\parseargdef\end{
+  \if 1\csname iscond.#1\endcsname
+  \else
+    % The general wording of \badenverr may not be ideal.
+    \expandafter\checkenv\csname#1\endcsname
+    \csname E#1\endcsname
+    \endgroup
+  \fi
+}
+
+\newhelp\EMsimple{Press RETURN to continue.}
+
+
+% Be sure we're in horizontal mode when doing a tie, since we make space
+% equivalent to this in @example-like environments. Otherwise, a space
+% at the beginning of a line will start with \penalty -- and
+% since \penalty is valid in vertical mode, we'd end up putting the
+% penalty on the vertical list instead of in the new paragraph.
+{\catcode`@ = 11
+ % Avoid using \@M directly, because that causes trouble
+ % if the definition is written into an index file.
+ \global\let\tiepenalty = \@M
+ \gdef\tie{\leavevmode\penalty\tiepenalty\ }
+}
+
+% @: forces normal size whitespace following.
+\def\:{\spacefactor=1000 }
+
+% @* forces a line break.
+\def\*{\unskip\hfil\break\hbox{}\ignorespaces}
+
+% @/ allows a line break.
+\let\/=\allowbreak
+
+% @. is an end-of-sentence period.
+\def\.{.\spacefactor=\endofsentencespacefactor\space}
+
+% @! is an end-of-sentence bang.
+\def\!{!\spacefactor=\endofsentencespacefactor\space}
+
+% @? is an end-of-sentence query.
+\def\?{?\spacefactor=\endofsentencespacefactor\space}
+
+% @frenchspacing on|off  says whether to put extra space after punctuation.
+%
+\def\onword{on}
+\def\offword{off}
+%
+\parseargdef\frenchspacing{%
+  \def\temp{#1}%
+  \ifx\temp\onword \plainfrenchspacing
+  \else\ifx\temp\offword \plainnonfrenchspacing
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @frenchspacing option `\temp', must be on|off}%
+  \fi\fi
+}
+
+% @w prevents a word break.  Without the \leavevmode, @w at the
+% beginning of a paragraph, when TeX is still in vertical mode, would
+% produce a whole line of output instead of starting the paragraph.
+\def\w#1{\leavevmode\hbox{#1}}
+
+% @group ... @end group forces ... to be all on one page, by enclosing
+% it in a TeX vbox.  We use \vtop instead of \vbox to construct the box
+% to keep its height that of a normal line.  According to the rules for
+% \topskip (p.114 of the TeXbook), the glue inserted is
+% max (\topskip - \ht (first item), 0).  If that height is large,
+% therefore, no glue is inserted, and the space between the headline and
+% the text is small, which looks bad.
+%
+% Another complication is that the group might be very large.  This can
+% cause the glue on the previous page to be unduly stretched, because it
+% does not have much material.  In this case, it's better to add an
+% explicit \vfill so that the extra space is at the bottom.  The
+% threshold for doing this is if the group is more than \vfilllimit
+% percent of a page (\vfilllimit can be changed inside of @tex).
+%
+\newbox\groupbox
+\def\vfilllimit{0.7}
+%
+\envdef\group{%
+  \ifnum\catcode`\^^M=\active \else
+    \errhelp = \groupinvalidhelp
+    \errmessage{@group invalid in context where filling is enabled}%
+  \fi
+  \startsavinginserts
+  %
+  \setbox\groupbox = \vtop\bgroup
+    % Do @comment since we are called inside an environment such as
+    % @example, where each end-of-line in the input causes an
+    % end-of-line in the output.  We don't want the end-of-line after
+    % the `@group' to put extra space in the output.  Since @group
+    % should appear on a line by itself (according to the Texinfo
+    % manual), we don't worry about eating any user text.
+    \comment
+}
+%
+% The \vtop produces a box with normal height and large depth; thus, TeX puts
+% \baselineskip glue before it, and (when the next line of text is done)
+% \lineskip glue after it.  Thus, space below is not quite equal to space
+% above.  But it's pretty close.
+\def\Egroup{%
+    % To get correct interline space between the last line of the group
+    % and the first line afterwards, we have to propagate \prevdepth.
+    \endgraf % Not \par, as it may have been set to \lisppar.
+    \global\dimen1 = \prevdepth
+  \egroup           % End the \vtop.
+  \addgroupbox
+  \prevdepth = \dimen1
+  \checkinserts
+}
+
+\def\addgroupbox{
+  % \dimen0 is the vertical size of the group's box.
+  \dimen0 = \ht\groupbox  \advance\dimen0 by \dp\groupbox
+  % \dimen2 is how much space is left on the page (more or less).
+  \dimen2 = \txipageheight   \advance\dimen2 by -\pagetotal
+  % if the group doesn't fit on the current page, and it's a big big
+  % group, force a page break.
+  \ifdim \dimen0 > \dimen2
+    \ifdim \pagetotal < \vfilllimit\txipageheight
+      \page
+    \fi
+  \fi
+  \box\groupbox
+}
+
+%
+% TeX puts in an \escapechar (i.e., `@') at the beginning of the help
+% message, so this ends up printing `@group can only ...'.
+%
+\newhelp\groupinvalidhelp{%
+group can only be used in environments such as @example,^^J%
+where each line of input produces a line of output.}
+
+% @need space-in-mils
+% forces a page break if there is not space-in-mils remaining.
+
+\newdimen\mil  \mil=0.001in
+
+\parseargdef\need{%
+  % Ensure vertical mode, so we don't make a big box in the middle of a
+  % paragraph.
+  \par
+  %
+  % If the @need value is less than one line space, it's useless.
+  \dimen0 = #1\mil
+  \dimen2 = \ht\strutbox
+  \advance\dimen2 by \dp\strutbox
+  \ifdim\dimen0 > \dimen2
+    %
+    % Do a \strut just to make the height of this box be normal, so the
+    % normal leading is inserted relative to the preceding line.
+    % And a page break here is fine.
+    \vtop to #1\mil{\strut\vfil}%
+    %
+    % TeX does not even consider page breaks if a penalty added to the
+    % main vertical list is 10000 or more.  But in order to see if the
+    % empty box we just added fits on the page, we must make it consider
+    % page breaks.  On the other hand, we don't want to actually break the
+    % page after the empty box.  So we use a penalty of 9999.
+    %
+    % There is an extremely small chance that TeX will actually break the
+    % page at this \penalty, if there are no other feasible breakpoints in
+    % sight.  (If the user is using lots of big @group commands, which
+    % almost-but-not-quite fill up a page, TeX will have a hard time doing
+    % good page breaking, for example.)  However, I could not construct an
+    % example where a page broke at this \penalty; if it happens in a real
+    % document, then we can reconsider our strategy.
+    \penalty9999
+    %
+    % Back up by the size of the box, whether we did a page break or not.
+    \kern -#1\mil
+    %
+    % Do not allow a page break right after this kern.
+    \nobreak
+  \fi
+}
+
+% @br   forces paragraph break (and is undocumented).
+
+\let\br = \par
+
+% @page forces the start of a new page.
+%
+\def\page{\par\vfill\supereject}
+
+% @exdent text....
+% outputs text on separate line in roman font, starting at standard page margin
+
+% This records the amount of indent in the innermost environment.
+% That's how much \exdent should take out.
+\newskip\exdentamount
+
+% This defn is used inside fill environments such as @defun.
+\parseargdef\exdent{\hfil\break\hbox{\kern -\exdentamount{\rm#1}}\hfil\break}
+
+% This defn is used inside nofill environments such as @example.
+\parseargdef\nofillexdent{{\advance \leftskip by -\exdentamount
+  \leftline{\hskip\leftskip{\rm#1}}}}
+
+% @inmargin{WHICH}{TEXT} puts TEXT in the WHICH margin next to the current
+% paragraph.  For more general purposes, use the \margin insertion
+% class.  WHICH is `l' or `r'.  Not documented, written for gawk manual.
+%
+\newskip\inmarginspacing \inmarginspacing=1cm
+\def\strutdepth{\dp\strutbox}
+%
+\def\doinmargin#1#2{\strut\vadjust{%
+  \nobreak
+  \kern-\strutdepth
+  \vtop to \strutdepth{%
+    \baselineskip=\strutdepth
+    \vss
+    % if you have multiple lines of stuff to put here, you'll need to
+    % make the vbox yourself of the appropriate size.
+    \ifx#1l%
+      \llap{\ignorespaces #2\hskip\inmarginspacing}%
+    \else
+      \rlap{\hskip\hsize \hskip\inmarginspacing \ignorespaces #2}%
+    \fi
+    \null
+  }%
+}}
+\def\inleftmargin{\doinmargin l}
+\def\inrightmargin{\doinmargin r}
+%
+% @inmargin{TEXT [, RIGHT-TEXT]}
+% (if RIGHT-TEXT is given, use TEXT for left page, RIGHT-TEXT for right;
+% else use TEXT for both).
+%
+\def\inmargin#1{\parseinmargin #1,,\finish}
+\def\parseinmargin#1,#2,#3\finish{% not perfect, but better than nothing.
+  \setbox0 = \hbox{\ignorespaces #2}%
+  \ifdim\wd0 > 0pt
+    \def\lefttext{#1}%  have both texts
+    \def\righttext{#2}%
+  \else
+    \def\lefttext{#1}%  have only one text
+    \def\righttext{#1}%
+  \fi
+  %
+  \ifodd\pageno
+    \def\temp{\inrightmargin\righttext}% odd page -> outside is right margin
+  \else
+    \def\temp{\inleftmargin\lefttext}%
+  \fi
+  \temp
+}
+
+% @include FILE -- \input text of FILE.
+%
+\def\include{\parseargusing\filenamecatcodes\includezzz}
+\def\includezzz#1{%
+  \pushthisfilestack
+  \def\thisfile{#1}%
+  {%
+    \makevalueexpandable  % we want to expand any @value in FILE.
+    \turnoffactive        % and allow special characters in the expansion
+    \indexnofonts         % Allow `@@' and other weird things in file names.
+    \wlog{texinfo.tex: doing @include of #1^^J}%
+    \edef\temp{\noexpand\input #1 }%
+    %
+    % This trickery is to read FILE outside of a group, in case it makes
+    % definitions, etc.
+    \expandafter
+  }\temp
+  \popthisfilestack
+}
+\def\filenamecatcodes{%
+  \catcode`\\=\other
+  \catcode`~=\other
+  \catcode`^=\other
+  \catcode`_=\other
+  \catcode`|=\other
+  \catcode`<=\other
+  \catcode`>=\other
+  \catcode`+=\other
+  \catcode`-=\other
+  \catcode`\`=\other
+  \catcode`\'=\other
+}
+
+\def\pushthisfilestack{%
+  \expandafter\pushthisfilestackX\popthisfilestack\StackTerm
+}
+\def\pushthisfilestackX{%
+  \expandafter\pushthisfilestackY\thisfile\StackTerm
+}
+\def\pushthisfilestackY #1\StackTerm #2\StackTerm {%
+  \gdef\popthisfilestack{\gdef\thisfile{#1}\gdef\popthisfilestack{#2}}%
+}
+
+\def\popthisfilestack{\errthisfilestackempty}
+\def\errthisfilestackempty{\errmessage{Internal error:
+  the stack of filenames is empty.}}
+%
+\def\thisfile{}
+
+% @center line
+% outputs that line, centered.
+%
+\parseargdef\center{%
+  \ifhmode
+    \let\centersub\centerH
+  \else
+    \let\centersub\centerV
+  \fi
+  \centersub{\hfil \ignorespaces#1\unskip \hfil}%
+  \let\centersub\relax % don't let the definition persist, just in case
+}
+\def\centerH#1{{%
+  \hfil\break
+  \advance\hsize by -\leftskip
+  \advance\hsize by -\rightskip
+  \line{#1}%
+  \break
+}}
+%
+\newcount\centerpenalty
+\def\centerV#1{%
+  % The idea here is the same as in \startdefun, \cartouche, etc.: if
+  % @center is the first thing after a section heading, we need to wipe
+  % out the negative parskip inserted by \sectionheading, but still
+  % prevent a page break here.
+  \centerpenalty = \lastpenalty
+  \ifnum\centerpenalty>10000 \vskip\parskip \fi
+  \ifnum\centerpenalty>9999 \penalty\centerpenalty \fi
+  \line{\kern\leftskip #1\kern\rightskip}%
+}
+
+% @sp n   outputs n lines of vertical space
+%
+\parseargdef\sp{\vskip #1\baselineskip}
+
+% @comment ...line which is ignored...
+% @c is the same as @comment
+% @ignore ... @end ignore  is another way to write a comment
+
+
+\def\c{\begingroup \catcode`\^^M=\active%
+\catcode`\@=\other \catcode`\{=\other \catcode`\}=\other%
+\cxxx}
+{\catcode`\^^M=\active \gdef\cxxx#1^^M{\endgroup}}
+%
+\let\comment\c
+
+% @paragraphindent NCHARS
+% We'll use ems for NCHARS, close enough.
+% NCHARS can also be the word `asis' or `none'.
+% We cannot feasibly implement @paragraphindent asis, though.
+%
+\def\asisword{asis} % no translation, these are keywords
+\def\noneword{none}
+%
+\parseargdef\paragraphindent{%
+  \def\temp{#1}%
+  \ifx\temp\asisword
+  \else
+    \ifx\temp\noneword
+      \defaultparindent = 0pt
+    \else
+      \defaultparindent = #1em
+    \fi
+  \fi
+  \parindent = \defaultparindent
+}
+
+% @exampleindent NCHARS
+% We'll use ems for NCHARS like @paragraphindent.
+% It seems @exampleindent asis isn't necessary, but
+% I preserve it to make it similar to @paragraphindent.
+\parseargdef\exampleindent{%
+  \def\temp{#1}%
+  \ifx\temp\asisword
+  \else
+    \ifx\temp\noneword
+      \lispnarrowing = 0pt
+    \else
+      \lispnarrowing = #1em
+    \fi
+  \fi
+}
+
+% @firstparagraphindent WORD
+% If WORD is `none', then suppress indentation of the first paragraph
+% after a section heading.  If WORD is `insert', then do indent at such
+% paragraphs.
+%
+% The paragraph indentation is suppressed or not by calling
+% \suppressfirstparagraphindent, which the sectioning commands do.
+% We switch the definition of this back and forth according to WORD.
+% By default, we suppress indentation.
+%
+\def\suppressfirstparagraphindent{\dosuppressfirstparagraphindent}
+\def\insertword{insert}
+%
+\parseargdef\firstparagraphindent{%
+  \def\temp{#1}%
+  \ifx\temp\noneword
+    \let\suppressfirstparagraphindent = \dosuppressfirstparagraphindent
+  \else\ifx\temp\insertword
+    \let\suppressfirstparagraphindent = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @firstparagraphindent option `\temp'}%
+  \fi\fi
+}
+
+% Here is how we actually suppress indentation.  Redefine \everypar to
+% \kern backwards by \parindent, and then reset itself to empty.
+%
+% We also make \indent itself not actually do anything until the next
+% paragraph.
+%
+\gdef\dosuppressfirstparagraphindent{%
+  \gdef\indent  {\restorefirstparagraphindent \indent}%
+  \gdef\noindent{\restorefirstparagraphindent \noindent}%
+  \global\everypar = {\kern -\parindent \restorefirstparagraphindent}%
+}
+%
+\gdef\restorefirstparagraphindent{%
+  \global\let\indent = \ptexindent
+  \global\let\noindent = \ptexnoindent
+  \global\everypar = {}%
+}
+
+
+% @refill is a no-op.
+\let\refill=\relax
+
+% @setfilename INFO-FILENAME - ignored
+\let\setfilename=\comment
+
+% @bye.
+\outer\def\bye{\chappager\pagelabels\tracingstats=1\ptexend}
+
+
+\message{pdf,}
+% adobe `portable' document format
+\newcount\tempnum
+\newcount\lnkcount
+\newtoks\filename
+\newcount\filenamelength
+\newcount\pgn
+\newtoks\toksA
+\newtoks\toksB
+\newtoks\toksC
+\newtoks\toksD
+\newbox\boxA
+\newbox\boxB
+\newcount\countA
+\newif\ifpdf
+\newif\ifpdfmakepagedest
+
+%
+% For LuaTeX
+%
+
+\newif\iftxiuseunicodedestname
+\txiuseunicodedestnamefalse % For pdfTeX etc.
+
+\ifx\luatexversion\thisisundefined
+\else
+  % Use Unicode destination names
+  \txiuseunicodedestnametrue
+  % Escape PDF strings with converting UTF-16 from UTF-8
+  \begingroup
+    \catcode`\%=12
+    \directlua{
+      function UTF16oct(str)
+        tex.sprint(string.char(0x5c) .. '376' .. string.char(0x5c) .. '377')
+        for c in string.utfvalues(str) do
+          if c < 0x10000 then
+            tex.sprint(
+              string.format(string.char(0x5c) .. string.char(0x25) .. '03o' ..
+                            string.char(0x5c) .. string.char(0x25) .. '03o',
+                            math.floor(c / 256), math.floor(c % 256)))
+          else
+            c = c - 0x10000
+            local c_hi = c / 1024 + 0xd800
+            local c_lo = c % 1024 + 0xdc00
+            tex.sprint(
+              string.format(string.char(0x5c) .. string.char(0x25) .. '03o' ..
+                            string.char(0x5c) .. string.char(0x25) .. '03o' ..
+                            string.char(0x5c) .. string.char(0x25) .. '03o' ..
+                            string.char(0x5c) .. string.char(0x25) .. '03o',
+                            math.floor(c_hi / 256), math.floor(c_hi % 256),
+                            math.floor(c_lo / 256), math.floor(c_lo % 256)))
+          end
+        end
+      end
+    }
+  \endgroup
+  \def\pdfescapestrutfsixteen#1{\directlua{UTF16oct('\luaescapestring{#1}')}}
+  % Escape PDF strings without converting
+  \begingroup
+    \directlua{
+      function PDFescstr(str)
+        for c in string.bytes(str) do
+          if c <= 0x20 or c >= 0x80 or c == 0x28 or c == 0x29 or c == 0x5c then
+            tex.sprint(-2,
+              string.format(string.char(0x5c) .. string.char(0x25) .. '03o',
+                            c))
+          else
+            tex.sprint(-2, string.char(c))
+          end
+        end
+      end
+    }
+    % The -2 in the arguments here gives all the input to TeX catcode 12
+    % (other) or 10 (space), preventing undefined control sequence errors. See
+    % https://lists.gnu.org/archive/html/bug-texinfo/2019-08/msg00031.html
+    %
+  \endgroup
+  \def\pdfescapestring#1{\directlua{PDFescstr('\luaescapestring{#1}')}}
+  \ifnum\luatexversion>84
+    % For LuaTeX >= 0.85
+    \def\pdfdest{\pdfextension dest}
+    \let\pdfoutput\outputmode
+    \def\pdfliteral{\pdfextension literal}
+    \def\pdfcatalog{\pdfextension catalog}
+    \def\pdftexversion{\numexpr\pdffeedback version\relax}
+    \let\pdfximage\saveimageresource
+    \let\pdfrefximage\useimageresource
+    \let\pdflastximage\lastsavedimageresourceindex
+    \def\pdfendlink{\pdfextension endlink\relax}
+    \def\pdfoutline{\pdfextension outline}
+    \def\pdfstartlink{\pdfextension startlink}
+    \def\pdffontattr{\pdfextension fontattr}
+    \def\pdfobj{\pdfextension obj}
+    \def\pdflastobj{\numexpr\pdffeedback lastobj\relax}
+    \let\pdfpagewidth\pagewidth
+    \let\pdfpageheight\pageheight
+    \edef\pdfhorigin{\pdfvariable horigin}
+    \edef\pdfvorigin{\pdfvariable vorigin}
+  \fi
+\fi
+
+% when pdftex is run in dvi mode, \pdfoutput is defined (so \pdfoutput=1
+% can be set).  So we test for \relax and 0 as well as being undefined.
+\ifx\pdfoutput\thisisundefined
+\else
+  \ifx\pdfoutput\relax
+  \else
+    \ifcase\pdfoutput
+    \else
+      \pdftrue
+    \fi
+  \fi
+\fi
+
+\newif\ifpdforxetex
+\pdforxetexfalse
+\ifpdf
+  \pdforxetextrue
+\fi
+\ifx\XeTeXrevision\thisisundefined\else
+  \pdforxetextrue
+\fi
+
+
+% Output page labels information.
+% See PDF reference v.1.7 p.594, section 8.3.1.
+\ifpdf
+\def\pagelabels{%
+  \def\title{0 << /P (T-) /S /D >>}%
+  \edef\roman{\the\romancount << /S /r >>}%
+  \edef\arabic{\the\arabiccount << /S /D >>}%
+  %
+  % Page label ranges must be increasing.  Remove any duplicates.
+  % (There is a slight chance of this being wrong if e.g. there is
+  % a @contents but no @titlepage, etc.)
+  %
+  \ifnum\romancount=0 \def\roman{}\fi
+  \ifnum\arabiccount=0 \def\title{}%
+  \else
+    \ifnum\romancount=\arabiccount \def\roman{}\fi
+  \fi
+  %
+  \ifnum\romancount<\arabiccount
+    \pdfcatalog{/PageLabels << /Nums [\title \roman \arabic ] >> }\relax
+  \else
+    \pdfcatalog{/PageLabels << /Nums [\title \arabic \roman ] >> }\relax
+  \fi
+}
+\else
+  \let\pagelabels\relax
+\fi
+
+\newcount\pagecount \pagecount=0
+\newcount\romancount \romancount=0
+\newcount\arabiccount \arabiccount=0
+\ifpdf
+  \let\ptxadvancepageno\advancepageno
+  \def\advancepageno{%
+    \ptxadvancepageno\global\advance\pagecount by 1
+  }
+\fi
+
+
+% PDF uses PostScript string constants for the names of xref targets,
+% for display in the outlines, and in other places.  Thus, we have to
+% double any backslashes.  Otherwise, a name like "\node" will be
+% interpreted as a newline (\n), followed by o, d, e.  Not good.
+%
+% See http://www.ntg.nl/pipermail/ntg-pdftex/2004-July/000654.html and
+% related messages.  The final outcome is that it is up to the TeX user
+% to double the backslashes and otherwise make the string valid, so
+% that's what we do.  pdftex 1.30.0 (ca.2005) introduced a primitive to
+% do this reliably, so we use it.
+
+% #1 is a control sequence in which to do the replacements,
+% which we \xdef.
+\def\txiescapepdf#1{%
+  \ifx\pdfescapestring\thisisundefined
+    % No primitive available; should we give a warning or log?
+    % Many times it won't matter.
+    \xdef#1{#1}%
+  \else
+    % The expandable \pdfescapestring primitive escapes parentheses,
+    % backslashes, and other special chars.
+    \xdef#1{\pdfescapestring{#1}}%
+  \fi
+}
+\def\txiescapepdfutfsixteen#1{%
+  \ifx\pdfescapestrutfsixteen\thisisundefined
+    % No UTF-16 converting macro available.
+    \txiescapepdf{#1}%
+  \else
+    \xdef#1{\pdfescapestrutfsixteen{#1}}%
+  \fi
+}
+
+\newhelp\nopdfimagehelp{Texinfo supports .png, .jpg, .jpeg, and .pdf images
+with PDF output, and none of those formats could be found.  (.eps cannot
+be supported due to the design of the PDF format; use regular TeX (DVI
+output) for that.)}
+
+\ifpdf
+  %
+  % Color manipulation macros using ideas from pdfcolor.tex,
+  % except using rgb instead of cmyk; the latter is said to render as a
+  % very dark gray on-screen and a very dark halftone in print, instead
+  % of actual black. The dark red here is dark enough to print on paper as
+  % nearly black, but still distinguishable for online viewing.  We use
+  % black by default, though.
+  \def\rgbDarkRed{0.50 0.09 0.12}
+  \def\rgbBlack{0 0 0}
+  %
+  % rg sets the color for filling (usual text, etc.);
+  % RG sets the color for stroking (thin rules, e.g., normal _'s).
+  \def\pdfsetcolor#1{\pdfliteral{#1 rg  #1 RG}}
+  %
+  % Set color, and create a mark which defines \thiscolor accordingly,
+  % so that \makeheadline knows which color to restore.
+  \def\setcolor#1{%
+    \xdef\currentcolordefs{\gdef\noexpand\thiscolor{#1}}%
+    \domark
+    \pdfsetcolor{#1}%
+  }
+  %
+  \def\maincolor{\rgbBlack}
+  \pdfsetcolor{\maincolor}
+  \edef\thiscolor{\maincolor}
+  \def\currentcolordefs{}
+  %
+  \def\makefootline{%
+    \baselineskip24pt
+    \line{\pdfsetcolor{\maincolor}\the\footline}%
+  }
+  %
+  \def\makeheadline{%
+    \vbox to 0pt{%
+      \vskip-22.5pt
+      \line{%
+        \vbox to8.5pt{}%
+        % Extract \thiscolor definition from the marks.
+        \getcolormarks
+        % Typeset the headline with \maincolor, then restore the color.
+        \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}%
+      }%
+      \vss
+    }%
+    \nointerlineskip
+  }
+  %
+  %
+  \pdfcatalog{/PageMode /UseOutlines}
+  %
+  % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto).
+  \def\dopdfimage#1#2#3{%
+    \def\pdfimagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}%
+    \def\pdfimageheight{#3}\setbox2 = \hbox{\ignorespaces #3}%
+    %
+    % pdftex (and the PDF format) support .pdf, .png, .jpg (among
+    % others).  Let's try in that order, PDF first since if
+    % someone has a scalable image, presumably better to use that than a
+    % bitmap.
+    \let\pdfimgext=\empty
+    \begingroup
+      \openin 1 #1.pdf \ifeof 1
+        \openin 1 #1.PDF \ifeof 1
+          \openin 1 #1.png \ifeof 1
+            \openin 1 #1.jpg \ifeof 1
+              \openin 1 #1.jpeg \ifeof 1
+                \openin 1 #1.JPG \ifeof 1
+                  \errhelp = \nopdfimagehelp
+                  \errmessage{Could not find image file #1 for pdf}%
+                \else \gdef\pdfimgext{JPG}%
+                \fi
+              \else \gdef\pdfimgext{jpeg}%
+              \fi
+            \else \gdef\pdfimgext{jpg}%
+            \fi
+          \else \gdef\pdfimgext{png}%
+          \fi
+        \else \gdef\pdfimgext{PDF}%
+        \fi
+      \else \gdef\pdfimgext{pdf}%
+      \fi
+      \closein 1
+    \endgroup
+    %
+    % without \immediate, ancient pdftex seg faults when the same image is
+    % included twice.  (Version 3.14159-pre-1.0-unofficial-20010704.)
+    \ifnum\pdftexversion < 14
+      \immediate\pdfimage
+    \else
+      \immediate\pdfximage
+    \fi
+      \ifdim \wd0 >0pt width \pdfimagewidth \fi
+      \ifdim \wd2 >0pt height \pdfimageheight \fi
+      \ifnum\pdftexversion<13
+         #1.\pdfimgext
+       \else
+         {#1.\pdfimgext}%
+       \fi
+    \ifnum\pdftexversion < 14 \else
+      \pdfrefximage \pdflastximage
+    \fi}
+  %
+  \def\setpdfdestname#1{{%
+    % We have to set dummies so commands such as @code, and characters
+    % such as \, aren't expanded when present in a section title.
+    \indexnofonts
+    \makevalueexpandable
+    \turnoffactive
+    \iftxiuseunicodedestname
+      \ifx \declaredencoding \latone
+        % Pass through Latin-1 characters.
+        % LuaTeX with byte wise I/O converts Latin-1 characters to Unicode.
+      \else
+        \ifx \declaredencoding \utfeight
+          % Pass through Unicode characters.
+        \else
+          % Use ASCII approximations in destination names.
+          \passthroughcharsfalse
+        \fi
+      \fi
+    \else
+      % Use ASCII approximations in destination names.
+      \passthroughcharsfalse
+    \fi
+    \def\pdfdestname{#1}%
+    \txiescapepdf\pdfdestname
+  }}
+  %
+  \def\setpdfoutlinetext#1{{%
+    \indexnofonts
+    \makevalueexpandable
+    \turnoffactive
+    \ifx \declaredencoding \latone
+      % The PDF format can use an extended form of Latin-1 in bookmark
+      % strings.  See Appendix D of the PDF Reference, Sixth Edition, for
+      % the "PDFDocEncoding".
+      \passthroughcharstrue
+      % Pass through Latin-1 characters.
+      %   LuaTeX: Convert to Unicode
+      %   pdfTeX: Use Latin-1 as PDFDocEncoding
+      \def\pdfoutlinetext{#1}%
+    \else
+      \ifx \declaredencoding \utfeight
+        \ifx\luatexversion\thisisundefined
+          % For pdfTeX  with UTF-8.
+          % TODO: the PDF format can use UTF-16 in bookmark strings,
+          % but the code for this isn't done yet.
+          % Use ASCII approximations.
+          \passthroughcharsfalse
+          \def\pdfoutlinetext{#1}%
+        \else
+          % For LuaTeX with UTF-8.
+          % Pass through Unicode characters for title texts.
+          \passthroughcharstrue
+          \def\pdfoutlinetext{#1}%
+        \fi
+      \else
+        % For non-Latin-1 or non-UTF-8 encodings.
+        % Use ASCII approximations.
+        \passthroughcharsfalse
+        \def\pdfoutlinetext{#1}%
+      \fi
+    \fi
+    % LuaTeX: Convert to UTF-16
+    % pdfTeX: Use Latin-1 as PDFDocEncoding
+    \txiescapepdfutfsixteen\pdfoutlinetext
+  }}
+  %
+  \def\pdfmkdest#1{%
+    \setpdfdestname{#1}%
+    \safewhatsit{\pdfdest name{\pdfdestname} xyz}%
+  }
+  %
+  % used to mark target names; must be expandable.
+  \def\pdfmkpgn#1{#1}
+  %
+  % by default, use black for everything.
+  \def\urlcolor{\rgbBlack}
+  \def\linkcolor{\rgbBlack}
+  \def\endlink{\setcolor{\maincolor}\pdfendlink}
+  %
+  % Adding outlines to PDF; macros for calculating structure of outlines
+  % come from Petr Olsak
+  \def\expnumber#1{\expandafter\ifx\csname#1\endcsname\relax 0%
+    \else \csname#1\endcsname \fi}
+  \def\advancenumber#1{\tempnum=\expnumber{#1}\relax
+    \advance\tempnum by 1
+    \expandafter\xdef\csname#1\endcsname{\the\tempnum}}
+  %
+  % #1 is the section text, which is what will be displayed in the
+  % outline by the pdf viewer.  #2 is the pdf expression for the number
+  % of subentries (or empty, for subsubsections).  #3 is the node text,
+  % which might be empty if this toc entry had no corresponding node.
+  % #4 is the page number
+  %
+  \def\dopdfoutline#1#2#3#4{%
+    % Generate a link to the node text if that exists; else, use the
+    % page number.  We could generate a destination for the section
+    % text in the case where a section has no node, but it doesn't
+    % seem worth the trouble, since most documents are normally structured.
+    \setpdfoutlinetext{#1}
+    \setpdfdestname{#3}
+    \ifx\pdfdestname\empty
+      \def\pdfdestname{#4}%
+    \fi
+    %
+    \pdfoutline goto name{\pdfmkpgn{\pdfdestname}}#2{\pdfoutlinetext}%
+  }
+  %
+  \def\pdfmakeoutlines{%
+    \begingroup
+      % Read toc silently, to get counts of subentries for \pdfoutline.
+      \def\partentry##1##2##3##4{}% ignore parts in the outlines
+      \def\numchapentry##1##2##3##4{%
+       \def\thischapnum{##2}%
+       \def\thissecnum{0}%
+       \def\thissubsecnum{0}%
+      }%
+      \def\numsecentry##1##2##3##4{%
+       \advancenumber{chap\thischapnum}%
+       \def\thissecnum{##2}%
+       \def\thissubsecnum{0}%
+      }%
+      \def\numsubsecentry##1##2##3##4{%
+       \advancenumber{sec\thissecnum}%
+       \def\thissubsecnum{##2}%
+      }%
+      \def\numsubsubsecentry##1##2##3##4{%
+       \advancenumber{subsec\thissubsecnum}%
+      }%
+      \def\thischapnum{0}%
+      \def\thissecnum{0}%
+      \def\thissubsecnum{0}%
+      %
+      % use \def rather than \let here because we redefine \chapentry et
+      % al. a second time, below.
+      \def\appentry{\numchapentry}%
+      \def\appsecentry{\numsecentry}%
+      \def\appsubsecentry{\numsubsecentry}%
+      \def\appsubsubsecentry{\numsubsubsecentry}%
+      \def\unnchapentry{\numchapentry}%
+      \def\unnsecentry{\numsecentry}%
+      \def\unnsubsecentry{\numsubsecentry}%
+      \def\unnsubsubsecentry{\numsubsubsecentry}%
+      \readdatafile{toc}%
+      %
+      % Read toc second time, this time actually producing the outlines.
+      % The `-' means take the \expnumber as the absolute number of
+      % subentries, which we calculated on our first read of the .toc above.
+      %
+      % We use the node names as the destinations.
+      %
+      % Currently we prefix the section name with the section number
+      % for chapter and appendix headings only in order to avoid too much
+      % horizontal space being required in the PDF viewer.
+      \def\numchapentry##1##2##3##4{%
+        \dopdfoutline{##2 ##1}{count-\expnumber{chap##2}}{##3}{##4}}%
+      \def\unnchapentry##1##2##3##4{%
+        \dopdfoutline{##1}{count-\expnumber{chap##2}}{##3}{##4}}%
+      \def\numsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{count-\expnumber{sec##2}}{##3}{##4}}%
+      \def\numsubsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{count-\expnumber{subsec##2}}{##3}{##4}}%
+      \def\numsubsubsecentry##1##2##3##4{% count is always zero
+        \dopdfoutline{##1}{}{##3}{##4}}%
+      %
+      % PDF outlines are displayed using system fonts, instead of
+      % document fonts.  Therefore we cannot use special characters,
+      % since the encoding is unknown.  For example, the eogonek from
+      % Latin 2 (0xea) gets translated to a | character.  Info from
+      % Staszek Wawrykiewicz, 19 Jan 2004 04:09:24 +0100.
+      %
+      % TODO this right, we have to translate 8-bit characters to
+      % their "best" equivalent, based on the @documentencoding.  Too
+      % much work for too little return.  Just use the ASCII equivalents
+      % we use for the index sort strings.
+      %
+      \indexnofonts
+      \setupdatafile
+      % We can have normal brace characters in the PDF outlines, unlike
+      % Texinfo index files.  So set that up.
+      \def\{{\lbracecharliteral}%
+      \def\}{\rbracecharliteral}%
+      \catcode`\\=\active \otherbackslash
+      \input \tocreadfilename
+    \endgroup
+  }
+  {\catcode`[=1 \catcode`]=2
+   \catcode`{=\other \catcode`}=\other
+   \gdef\lbracecharliteral[{]%
+   \gdef\rbracecharliteral[}]%
+  ]
+  %
+  \def\skipspaces#1{\def\PP{#1}\def\D{|}%
+    \ifx\PP\D\let\nextsp\relax
+    \else\let\nextsp\skipspaces
+      \addtokens{\filename}{\PP}%
+      \advance\filenamelength by 1
+    \fi
+    \nextsp}
+  \def\getfilename#1{%
+    \filenamelength=0
+    % If we don't expand the argument now, \skipspaces will get
+    % snagged on things like "@value{foo}".
+    \edef\temp{#1}%
+    \expandafter\skipspaces\temp|\relax
+  }
+  \ifnum\pdftexversion < 14
+    \let \startlink \pdfannotlink
+  \else
+    \let \startlink \pdfstartlink
+  \fi
+  % make a live url in pdf output.
+  \def\pdfurl#1{%
+    \begingroup
+      % it seems we really need yet another set of dummies; have not
+      % tried to figure out what each command should do in the context
+      % of @url.  for now, just make @/ a no-op, that's the only one
+      % people have actually reported a problem with.
+      %
+      \normalturnoffactive
+      \def\@{@}%
+      \let\/=\empty
+      \makevalueexpandable
+      % do we want to go so far as to use \indexnofonts instead of just
+      % special-casing \var here?
+      \def\var##1{##1}%
+      %
+      \leavevmode\setcolor{\urlcolor}%
+      \startlink attr{/Border [0 0 0]}%
+        user{/Subtype /Link /A << /S /URI /URI (#1) >>}%
+    \endgroup}
+  % \pdfgettoks - Surround page numbers in #1 with @pdflink.  #1 may
+  % be a simple number, or a list of numbers in the case of an index
+  % entry.
+  \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}}
+  \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks}
+  \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks}
+  \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}}
+  \def\maketoks{%
+    \expandafter\poptoks\the\toksA|ENDTOKS|\relax
+    \ifx\first0\adn0
+    \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3
+    \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6
+    \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9
+    \else
+      \ifnum0=\countA\else\makelink\fi
+      \ifx\first.\let\next=\done\else
+        \let\next=\maketoks
+        \addtokens{\toksB}{\the\toksD}
+        \ifx\first,\addtokens{\toksB}{\space}\fi
+      \fi
+    \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+    \next}
+  \def\makelink{\addtokens{\toksB}%
+    {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0}
+  \def\pdflink#1{%
+    \startlink attr{/Border [0 0 0]} goto name{\pdfmkpgn{#1}}
+    \setcolor{\linkcolor}#1\endlink}
+  \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st}
+\else
+  % non-pdf mode
+  \let\pdfmkdest = \gobble
+  \let\pdfurl = \gobble
+  \let\endlink = \relax
+  \let\setcolor = \gobble
+  \let\pdfsetcolor = \gobble
+  \let\pdfmakeoutlines = \relax
+\fi  % \ifx\pdfoutput
+
+%
+% For XeTeX
+%
+\ifx\XeTeXrevision\thisisundefined
+\else
+  %
+  % XeTeX version check
+  %
+  \ifnum\strcmp{\the\XeTeXversion\XeTeXrevision}{0.99996}>-1
+    % TeX Live 2016 contains XeTeX 0.99996 and xdvipdfmx 20160307.
+    % It can use the `dvipdfmx:config' special (from TeX Live SVN r40941).
+    % For avoiding PDF destination name replacement, we use this special
+    % instead of xdvipdfmx's command line option `-C 0x0010'.
+    \special{dvipdfmx:config C 0x0010}
+    % XeTeX 0.99995+ comes with xdvipdfmx 20160307+.
+    % It can handle Unicode destination names for PDF.
+    \txiuseunicodedestnametrue
+  \else
+    % XeTeX < 0.99996 (TeX Live < 2016) cannot use the
+    % `dvipdfmx:config' special.
+    % So for avoiding PDF destination name replacement,
+    % xdvipdfmx's command line option `-C 0x0010' is necessary.
+    %
+    % XeTeX < 0.99995 can not handle Unicode destination names for PDF
+    % because xdvipdfmx 20150315 has a UTF-16 conversion issue.
+    % It is fixed by xdvipdfmx 20160106 (TeX Live SVN r39753).
+    \txiuseunicodedestnamefalse
+  \fi
+  %
+  % Color support
+  %
+  \def\rgbDarkRed{0.50 0.09 0.12}
+  \def\rgbBlack{0 0 0}
+  %
+  \def\pdfsetcolor#1{\special{pdf:scolor [#1]}}
+  %
+  % Set color, and create a mark which defines \thiscolor accordingly,
+  % so that \makeheadline knows which color to restore.
+  \def\setcolor#1{%
+    \xdef\currentcolordefs{\gdef\noexpand\thiscolor{#1}}%
+    \domark
+    \pdfsetcolor{#1}%
+  }
+  %
+  \def\maincolor{\rgbBlack}
+  \pdfsetcolor{\maincolor}
+  \edef\thiscolor{\maincolor}
+  \def\currentcolordefs{}
+  %
+  \def\makefootline{%
+    \baselineskip24pt
+    \line{\pdfsetcolor{\maincolor}\the\footline}%
+  }
+  %
+  \def\makeheadline{%
+    \vbox to 0pt{%
+      \vskip-22.5pt
+      \line{%
+        \vbox to8.5pt{}%
+        % Extract \thiscolor definition from the marks.
+        \getcolormarks
+        % Typeset the headline with \maincolor, then restore the color.
+        \pdfsetcolor{\maincolor}\the\headline\pdfsetcolor{\thiscolor}%
+      }%
+      \vss
+    }%
+    \nointerlineskip
+  }
+  %
+  % PDF outline support
+  %
+  % Emulate pdfTeX primitive
+  \def\pdfdest name#1 xyz{%
+    \special{pdf:dest (#1) [@thispage /XYZ @xpos @ypos null]}%
+  }
+  %
+  \def\setpdfdestname#1{{%
+    % We have to set dummies so commands such as @code, and characters
+    % such as \, aren't expanded when present in a section title.
+    \indexnofonts
+    \makevalueexpandable
+    \turnoffactive
+    \iftxiuseunicodedestname
+      % Pass through Unicode characters.
+    \else
+      % Use ASCII approximations in destination names.
+      \passthroughcharsfalse
+    \fi
+    \def\pdfdestname{#1}%
+    \txiescapepdf\pdfdestname
+  }}
+  %
+  \def\setpdfoutlinetext#1{{%
+    \turnoffactive
+    % Always use Unicode characters in title texts.
+    \def\pdfoutlinetext{#1}%
+    % For XeTeX, xdvipdfmx converts to UTF-16.
+    % So we do not convert.
+    \txiescapepdf\pdfoutlinetext
+  }}
+  %
+  \def\pdfmkdest#1{%
+    \setpdfdestname{#1}%
+    \safewhatsit{\pdfdest name{\pdfdestname} xyz}%
+  }
+  %
+  % by default, use black for everything.
+  \def\urlcolor{\rgbBlack}
+  \def\linkcolor{\rgbBlack}
+  \def\endlink{\setcolor{\maincolor}\pdfendlink}
+  %
+  \def\dopdfoutline#1#2#3#4{%
+    \setpdfoutlinetext{#1}
+    \setpdfdestname{#3}
+    \ifx\pdfdestname\empty
+      \def\pdfdestname{#4}%
+    \fi
+    %
+    \special{pdf:out [-] #2 << /Title (\pdfoutlinetext) /A
+      << /S /GoTo /D (\pdfdestname) >> >> }%
+  }
+  %
+  \def\pdfmakeoutlines{%
+    \begingroup
+      %
+      % For XeTeX, counts of subentries are not necessary.
+      % Therefore, we read toc only once.
+      %
+      % We use node names as destinations.
+      %
+      % Currently we prefix the section name with the section number
+      % for chapter and appendix headings only in order to avoid too much
+      % horizontal space being required in the PDF viewer.
+      \def\partentry##1##2##3##4{}% ignore parts in the outlines
+      \def\numchapentry##1##2##3##4{%
+        \dopdfoutline{##2 ##1}{1}{##3}{##4}}%
+      \def\numsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{2}{##3}{##4}}%
+      \def\numsubsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{3}{##3}{##4}}%
+      \def\numsubsubsecentry##1##2##3##4{%
+        \dopdfoutline{##1}{4}{##3}{##4}}%
+      %
+      \let\appentry\numchapentry%
+      \let\appsecentry\numsecentry%
+      \let\appsubsecentry\numsubsecentry%
+      \let\appsubsubsecentry\numsubsubsecentry%
+      \def\unnchapentry##1##2##3##4{%
+        \dopdfoutline{##1}{1}{##3}{##4}}%
+      \let\unnsecentry\numsecentry%
+      \let\unnsubsecentry\numsubsecentry%
+      \let\unnsubsubsecentry\numsubsubsecentry%
+      %
+      % For XeTeX, xdvipdfmx converts strings to UTF-16.
+      % Therefore, the encoding and the language may not be considered.
+      %
+      \indexnofonts
+      \setupdatafile
+      % We can have normal brace characters in the PDF outlines, unlike
+      % Texinfo index files.  So set that up.
+      \def\{{\lbracecharliteral}%
+      \def\}{\rbracecharliteral}%
+      \catcode`\\=\active \otherbackslash
+      \input \tocreadfilename
+    \endgroup
+  }
+  {\catcode`[=1 \catcode`]=2
+   \catcode`{=\other \catcode`}=\other
+   \gdef\lbracecharliteral[{]%
+   \gdef\rbracecharliteral[}]%
+  ]
+
+  \special{pdf:docview << /PageMode /UseOutlines >> }
+  % ``\special{pdf:tounicode ...}'' is not necessary
+  % because xdvipdfmx converts strings from UTF-8 to UTF-16 without it.
+  % However, due to a UTF-16 conversion issue of xdvipdfmx 20150315,
+  % ``\special{pdf:dest ...}'' cannot handle non-ASCII strings.
+  % It is fixed by xdvipdfmx 20160106 (TeX Live SVN r39753).
+%
+  \def\skipspaces#1{\def\PP{#1}\def\D{|}%
+    \ifx\PP\D\let\nextsp\relax
+    \else\let\nextsp\skipspaces
+      \addtokens{\filename}{\PP}%
+      \advance\filenamelength by 1
+    \fi
+    \nextsp}
+  \def\getfilename#1{%
+    \filenamelength=0
+    % If we don't expand the argument now, \skipspaces will get
+    % snagged on things like "@value{foo}".
+    \edef\temp{#1}%
+    \expandafter\skipspaces\temp|\relax
+  }
+  % make a live url in pdf output.
+  \def\pdfurl#1{%
+    \begingroup
+      % it seems we really need yet another set of dummies; have not
+      % tried to figure out what each command should do in the context
+      % of @url.  for now, just make @/ a no-op, that's the only one
+      % people have actually reported a problem with.
+      %
+      \normalturnoffactive
+      \def\@{@}%
+      \let\/=\empty
+      \makevalueexpandable
+      % do we want to go so far as to use \indexnofonts instead of just
+      % special-casing \var here?
+      \def\var##1{##1}%
+      %
+      \leavevmode\setcolor{\urlcolor}%
+      \special{pdf:bann << /Border [0 0 0]
+        /Subtype /Link /A << /S /URI /URI (#1) >> >>}%
+    \endgroup}
+  \def\endlink{\setcolor{\maincolor}\special{pdf:eann}}
+  \def\pdfgettoks#1.{\setbox\boxA=\hbox{\toksA={#1.}\toksB={}\maketoks}}
+  \def\addtokens#1#2{\edef\addtoks{\noexpand#1={\the#1#2}}\addtoks}
+  \def\adn#1{\addtokens{\toksC}{#1}\global\countA=1\let\next=\maketoks}
+  \def\poptoks#1#2|ENDTOKS|{\let\first=#1\toksD={#1}\toksA={#2}}
+  \def\maketoks{%
+    \expandafter\poptoks\the\toksA|ENDTOKS|\relax
+    \ifx\first0\adn0
+    \else\ifx\first1\adn1 \else\ifx\first2\adn2 \else\ifx\first3\adn3
+    \else\ifx\first4\adn4 \else\ifx\first5\adn5 \else\ifx\first6\adn6
+    \else\ifx\first7\adn7 \else\ifx\first8\adn8 \else\ifx\first9\adn9
+    \else
+      \ifnum0=\countA\else\makelink\fi
+      \ifx\first.\let\next=\done\else
+        \let\next=\maketoks
+        \addtokens{\toksB}{\the\toksD}
+        \ifx\first,\addtokens{\toksB}{\space}\fi
+      \fi
+    \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+    \next}
+  \def\makelink{\addtokens{\toksB}%
+    {\noexpand\pdflink{\the\toksC}}\toksC={}\global\countA=0}
+  \def\pdflink#1{%
+    \special{pdf:bann << /Border [0 0 0]
+      /Type /Annot /Subtype /Link /A << /S /GoTo /D (#1) >> >>}%
+    \setcolor{\linkcolor}#1\endlink}
+  \def\done{\edef\st{\global\noexpand\toksA={\the\toksB}}\st}
+%
+  %
+  % @image support
+  %
+  % #1 is image name, #2 width (might be empty/whitespace), #3 height (ditto).
+  \def\doxeteximage#1#2#3{%
+    \def\xeteximagewidth{#2}\setbox0 = \hbox{\ignorespaces #2}%
+    \def\xeteximageheight{#3}\setbox2 = \hbox{\ignorespaces #3}%
+    %
+    % XeTeX (and the PDF format) supports .pdf, .png, .jpg (among
+    % others).  Let's try in that order, PDF first since if
+    % someone has a scalable image, presumably better to use that than a
+    % bitmap.
+    \let\xeteximgext=\empty
+    \begingroup
+      \openin 1 #1.pdf \ifeof 1
+        \openin 1 #1.PDF \ifeof 1
+          \openin 1 #1.png \ifeof 1
+            \openin 1 #1.jpg \ifeof 1
+              \openin 1 #1.jpeg \ifeof 1
+                \openin 1 #1.JPG \ifeof 1
+                  \errmessage{Could not find image file #1 for XeTeX}%
+                \else \gdef\xeteximgext{JPG}%
+                \fi
+              \else \gdef\xeteximgext{jpeg}%
+              \fi
+            \else \gdef\xeteximgext{jpg}%
+            \fi
+          \else \gdef\xeteximgext{png}%
+          \fi
+        \else \gdef\xeteximgext{PDF}%
+        \fi
+      \else \gdef\xeteximgext{pdf}%
+      \fi
+      \closein 1
+    \endgroup
+    %
+    \def\xetexpdfext{pdf}%
+    \ifx\xeteximgext\xetexpdfext
+      \XeTeXpdffile "#1".\xeteximgext ""
+    \else
+      \def\xetexpdfext{PDF}%
+      \ifx\xeteximgext\xetexpdfext
+        \XeTeXpdffile "#1".\xeteximgext ""
+      \else
+        \XeTeXpicfile "#1".\xeteximgext ""
+      \fi
+    \fi
+    \ifdim \wd0 >0pt width \xeteximagewidth \fi
+    \ifdim \wd2 >0pt height \xeteximageheight \fi \relax
+  }
+\fi
+
+
+%
+\message{fonts,}
+
+% Set the baselineskip to #1, and the lineskip and strut size
+% correspondingly.  There is no deep meaning behind these magic numbers
+% used as factors; they just match (closely enough) what Knuth defined.
+%
+\def\lineskipfactor{.08333}
+\def\strutheightpercent{.70833}
+\def\strutdepthpercent {.29167}
+%
+% can get a sort of poor man's double spacing by redefining this.
+\def\baselinefactor{1}
+%
+\newdimen\textleading
+\def\setleading#1{%
+  \dimen0 = #1\relax
+  \normalbaselineskip = \baselinefactor\dimen0
+  \normallineskip = \lineskipfactor\normalbaselineskip
+  \normalbaselines
+  \setbox\strutbox =\hbox{%
+    \vrule width0pt height\strutheightpercent\baselineskip
+                    depth \strutdepthpercent \baselineskip
+  }%
+}
+
+% PDF CMaps.  See also LaTeX's t1.cmap.
+%
+% do nothing with this by default.
+\expandafter\let\csname cmapOT1\endcsname\gobble
+\expandafter\let\csname cmapOT1IT\endcsname\gobble
+\expandafter\let\csname cmapOT1TT\endcsname\gobble
+
+% if we are producing pdf, and we have \pdffontattr, then define cmaps.
+% (\pdffontattr was introduced many years ago, but people still run
+% older pdftex's; it's easy to conditionalize, so we do.)
+\ifpdf \ifx\pdffontattr\thisisundefined \else
+  \begingroup
+    \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+    \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1-0)
+%%Title: (TeX-OT1-0 TeX OT1 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+8 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<23> <26> <0023>
+<28> <3B> <0028>
+<3F> <5B> <003F>
+<5D> <5E> <005D>
+<61> <7A> <0061>
+<7B> <7C> <2013>
+endbfrange
+40 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <00660066>
+<0C> <00660069>
+<0D> <0066006C>
+<0E> <006600660069>
+<0F> <00660066006C>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<21> <0021>
+<22> <201D>
+<27> <2019>
+<3C> <00A1>
+<3D> <003D>
+<3E> <00BF>
+<5C> <201C>
+<5F> <02D9>
+<60> <2018>
+<7D> <02DD>
+<7E> <007E>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+    }\endgroup
+  \expandafter\edef\csname cmapOT1\endcsname#1{%
+    \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+  }%
+%
+% \cmapOT1IT
+  \begingroup
+    \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+    \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1IT-0)
+%%Title: (TeX-OT1IT-0 TeX OT1IT 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1IT)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1IT-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+8 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<25> <26> <0025>
+<28> <3B> <0028>
+<3F> <5B> <003F>
+<5D> <5E> <005D>
+<61> <7A> <0061>
+<7B> <7C> <2013>
+endbfrange
+42 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <00660066>
+<0C> <00660069>
+<0D> <0066006C>
+<0E> <006600660069>
+<0F> <00660066006C>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<21> <0021>
+<22> <201D>
+<23> <0023>
+<24> <00A3>
+<27> <2019>
+<3C> <00A1>
+<3D> <003D>
+<3E> <00BF>
+<5C> <201C>
+<5F> <02D9>
+<60> <2018>
+<7D> <02DD>
+<7E> <007E>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+    }\endgroup
+  \expandafter\edef\csname cmapOT1IT\endcsname#1{%
+    \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+  }%
+%
+% \cmapOT1TT
+  \begingroup
+    \catcode`\^^M=\active \def^^M{^^J}% Output line endings as the ^^J char.
+    \catcode`\%=12 \immediate\pdfobj stream {%!PS-Adobe-3.0 Resource-CMap
+%%DocumentNeededResources: ProcSet (CIDInit)
+%%IncludeResource: ProcSet (CIDInit)
+%%BeginResource: CMap (TeX-OT1TT-0)
+%%Title: (TeX-OT1TT-0 TeX OT1TT 0)
+%%Version: 1.000
+%%EndComments
+/CIDInit /ProcSet findresource begin
+12 dict begin
+begincmap
+/CIDSystemInfo
+<< /Registry (TeX)
+/Ordering (OT1TT)
+/Supplement 0
+>> def
+/CMapName /TeX-OT1TT-0 def
+/CMapType 2 def
+1 begincodespacerange
+<00> <7F>
+endcodespacerange
+5 beginbfrange
+<00> <01> <0393>
+<09> <0A> <03A8>
+<21> <26> <0021>
+<28> <5F> <0028>
+<61> <7E> <0061>
+endbfrange
+32 beginbfchar
+<02> <0398>
+<03> <039B>
+<04> <039E>
+<05> <03A0>
+<06> <03A3>
+<07> <03D2>
+<08> <03A6>
+<0B> <2191>
+<0C> <2193>
+<0D> <0027>
+<0E> <00A1>
+<0F> <00BF>
+<10> <0131>
+<11> <0237>
+<12> <0060>
+<13> <00B4>
+<14> <02C7>
+<15> <02D8>
+<16> <00AF>
+<17> <02DA>
+<18> <00B8>
+<19> <00DF>
+<1A> <00E6>
+<1B> <0153>
+<1C> <00F8>
+<1D> <00C6>
+<1E> <0152>
+<1F> <00D8>
+<20> <2423>
+<27> <2019>
+<60> <2018>
+<7F> <00A8>
+endbfchar
+endcmap
+CMapName currentdict /CMap defineresource pop
+end
+end
+%%EndResource
+%%EOF
+    }\endgroup
+  \expandafter\edef\csname cmapOT1TT\endcsname#1{%
+    \pdffontattr#1{/ToUnicode \the\pdflastobj\space 0 R}%
+  }%
+\fi\fi
+
+
+% Set the font macro #1 to the font named \fontprefix#2.
+% #3 is the font's design size, #4 is a scale factor, #5 is the CMap
+% encoding (only OT1, OT1IT and OT1TT are allowed, or empty to omit).
+% Example:
+% #1 = \textrm
+% #2 = \rmshape
+% #3 = 10
+% #4 = \mainmagstep
+% #5 = OT1
+%
+\def\setfont#1#2#3#4#5{%
+  \font#1=\fontprefix#2#3 scaled #4
+  \csname cmap#5\endcsname#1%
+}
+% This is what gets called when #5 of \setfont is empty.
+\let\cmap\gobble
+%
+% (end of cmaps)
+
+% Use cm as the default font prefix.
+% To specify the font prefix, you must define \fontprefix
+% before you read in texinfo.tex.
+\ifx\fontprefix\thisisundefined
+\def\fontprefix{cm}
+\fi
+% Support font families that don't use the same naming scheme as CM.
+\def\rmshape{r}
+\def\rmbshape{bx}               % where the normal face is bold
+\def\bfshape{b}
+\def\bxshape{bx}
+\def\ttshape{tt}
+\def\ttbshape{tt}
+\def\ttslshape{sltt}
+\def\itshape{ti}
+\def\itbshape{bxti}
+\def\slshape{sl}
+\def\slbshape{bxsl}
+\def\sfshape{ss}
+\def\sfbshape{ss}
+\def\scshape{csc}
+\def\scbshape{csc}
+
+% Definitions for a main text size of 11pt.  (The default in Texinfo.)
+%
+\def\definetextfontsizexi{%
+% Text fonts (11.2pt, magstep1).
+\def\textnominalsize{11pt}
+\edef\mainmagstep{\magstephalf}
+\setfont\textrm\rmshape{10}{\mainmagstep}{OT1}
+\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT}
+\setfont\textbf\bfshape{10}{\mainmagstep}{OT1}
+\setfont\textit\itshape{10}{\mainmagstep}{OT1IT}
+\setfont\textsl\slshape{10}{\mainmagstep}{OT1}
+\setfont\textsf\sfshape{10}{\mainmagstep}{OT1}
+\setfont\textsc\scshape{10}{\mainmagstep}{OT1}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+\def\textecsize{1095}
+
+% A few fonts for @defun names and args.
+\setfont\defbf\bfshape{10}{\magstep1}{OT1}
+\setfont\deftt\ttshape{10}{\magstep1}{OT1TT}
+\setfont\defsl\slshape{10}{\magstep1}{OT1}
+\setfont\defttsl\ttslshape{10}{\magstep1}{OT1TT}
+\def\df{\let\ttfont=\deftt \let\bffont = \defbf
+\let\ttslfont=\defttsl \let\slfont=\defsl \bf}
+
+% Fonts for indices, footnotes, small examples (9pt).
+\def\smallnominalsize{9pt}
+\setfont\smallrm\rmshape{9}{1000}{OT1}
+\setfont\smalltt\ttshape{9}{1000}{OT1TT}
+\setfont\smallbf\bfshape{10}{900}{OT1}
+\setfont\smallit\itshape{9}{1000}{OT1IT}
+\setfont\smallsl\slshape{9}{1000}{OT1}
+\setfont\smallsf\sfshape{9}{1000}{OT1}
+\setfont\smallsc\scshape{10}{900}{OT1}
+\setfont\smallttsl\ttslshape{10}{900}{OT1TT}
+\font\smalli=cmmi9
+\font\smallsy=cmsy9
+\def\smallecsize{0900}
+
+% Fonts for small examples (8pt).
+\def\smallernominalsize{8pt}
+\setfont\smallerrm\rmshape{8}{1000}{OT1}
+\setfont\smallertt\ttshape{8}{1000}{OT1TT}
+\setfont\smallerbf\bfshape{10}{800}{OT1}
+\setfont\smallerit\itshape{8}{1000}{OT1IT}
+\setfont\smallersl\slshape{8}{1000}{OT1}
+\setfont\smallersf\sfshape{8}{1000}{OT1}
+\setfont\smallersc\scshape{10}{800}{OT1}
+\setfont\smallerttsl\ttslshape{10}{800}{OT1TT}
+\font\smalleri=cmmi8
+\font\smallersy=cmsy8
+\def\smallerecsize{0800}
+
+% Fonts for math mode superscripts (7pt).
+\def\sevennominalsize{7pt}
+\setfont\sevenrm\rmshape{7}{1000}{OT1}
+\setfont\seventt\ttshape{10}{700}{OT1TT}
+\setfont\sevenbf\bfshape{10}{700}{OT1}
+\setfont\sevenit\itshape{7}{1000}{OT1IT}
+\setfont\sevensl\slshape{10}{700}{OT1}
+\setfont\sevensf\sfshape{10}{700}{OT1}
+\setfont\sevensc\scshape{10}{700}{OT1}
+\setfont\seventtsl\ttslshape{10}{700}{OT1TT}
+\font\seveni=cmmi7
+\font\sevensy=cmsy7
+\def\sevenecsize{0700}
+
+% Fonts for title page (20.4pt):
+\def\titlenominalsize{20pt}
+\setfont\titlerm\rmbshape{12}{\magstep3}{OT1}
+\setfont\titleit\itbshape{10}{\magstep4}{OT1IT}
+\setfont\titlesl\slbshape{10}{\magstep4}{OT1}
+\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT}
+\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT}
+\setfont\titlesf\sfbshape{17}{\magstep1}{OT1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}{OT1}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\titleecsize{2074}
+
+% Chapter (and unnumbered) fonts (17.28pt).
+\def\chapnominalsize{17pt}
+\setfont\chaprm\rmbshape{12}{\magstep2}{OT1}
+\setfont\chapit\itbshape{10}{\magstep3}{OT1IT}
+\setfont\chapsl\slbshape{10}{\magstep3}{OT1}
+\setfont\chaptt\ttbshape{12}{\magstep2}{OT1TT}
+\setfont\chapttsl\ttslshape{10}{\magstep3}{OT1TT}
+\setfont\chapsf\sfbshape{17}{1000}{OT1}
+\let\chapbf=\chaprm
+\setfont\chapsc\scbshape{10}{\magstep3}{OT1}
+\font\chapi=cmmi12 scaled \magstep2
+\font\chapsy=cmsy10 scaled \magstep3
+\def\chapecsize{1728}
+
+% Section fonts (14.4pt).
+\def\secnominalsize{14pt}
+\setfont\secrm\rmbshape{12}{\magstep1}{OT1}
+\setfont\secrmnotbold\rmshape{12}{\magstep1}{OT1}
+\setfont\secit\itbshape{10}{\magstep2}{OT1IT}
+\setfont\secsl\slbshape{10}{\magstep2}{OT1}
+\setfont\sectt\ttbshape{12}{\magstep1}{OT1TT}
+\setfont\secttsl\ttslshape{10}{\magstep2}{OT1TT}
+\setfont\secsf\sfbshape{12}{\magstep1}{OT1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep2}{OT1}
+\font\seci=cmmi12 scaled \magstep1
+\font\secsy=cmsy10 scaled \magstep2
+\def\sececsize{1440}
+
+% Subsection fonts (13.15pt).
+\def\ssecnominalsize{13pt}
+\setfont\ssecrm\rmbshape{12}{\magstephalf}{OT1}
+\setfont\ssecit\itbshape{10}{1315}{OT1IT}
+\setfont\ssecsl\slbshape{10}{1315}{OT1}
+\setfont\ssectt\ttbshape{12}{\magstephalf}{OT1TT}
+\setfont\ssecttsl\ttslshape{10}{1315}{OT1TT}
+\setfont\ssecsf\sfbshape{12}{\magstephalf}{OT1}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{1315}{OT1}
+\font\sseci=cmmi12 scaled \magstephalf
+\font\ssecsy=cmsy10 scaled 1315
+\def\ssececsize{1200}
+
+% Reduced fonts for @acronym in text (10pt).
+\def\reducednominalsize{10pt}
+\setfont\reducedrm\rmshape{10}{1000}{OT1}
+\setfont\reducedtt\ttshape{10}{1000}{OT1TT}
+\setfont\reducedbf\bfshape{10}{1000}{OT1}
+\setfont\reducedit\itshape{10}{1000}{OT1IT}
+\setfont\reducedsl\slshape{10}{1000}{OT1}
+\setfont\reducedsf\sfshape{10}{1000}{OT1}
+\setfont\reducedsc\scshape{10}{1000}{OT1}
+\setfont\reducedttsl\ttslshape{10}{1000}{OT1TT}
+\font\reducedi=cmmi10
+\font\reducedsy=cmsy10
+\def\reducedecsize{1000}
+
+\textleading = 13.2pt % line spacing for 11pt CM
+\textfonts            % reset the current fonts
+\rm
+} % end of 11pt text font size definitions, \definetextfontsizexi
+
+
+% Definitions to make the main text be 10pt Computer Modern, with
+% section, chapter, etc., sizes following suit.  This is for the GNU
+% Press printing of the Emacs 22 manual.  Maybe other manuals in the
+% future.  Used with @smallbook, which sets the leading to 12pt.
+%
+\def\definetextfontsizex{%
+% Text fonts (10pt).
+\def\textnominalsize{10pt}
+\edef\mainmagstep{1000}
+\setfont\textrm\rmshape{10}{\mainmagstep}{OT1}
+\setfont\texttt\ttshape{10}{\mainmagstep}{OT1TT}
+\setfont\textbf\bfshape{10}{\mainmagstep}{OT1}
+\setfont\textit\itshape{10}{\mainmagstep}{OT1IT}
+\setfont\textsl\slshape{10}{\mainmagstep}{OT1}
+\setfont\textsf\sfshape{10}{\mainmagstep}{OT1}
+\setfont\textsc\scshape{10}{\mainmagstep}{OT1}
+\setfont\textttsl\ttslshape{10}{\mainmagstep}{OT1TT}
+\font\texti=cmmi10 scaled \mainmagstep
+\font\textsy=cmsy10 scaled \mainmagstep
+\def\textecsize{1000}
+
+% A few fonts for @defun names and args.
+\setfont\defbf\bfshape{10}{\magstephalf}{OT1}
+\setfont\deftt\ttshape{10}{\magstephalf}{OT1TT}
+\setfont\defsl\slshape{10}{\magstephalf}{OT1}
+\setfont\defttsl\ttslshape{10}{\magstephalf}{OT1TT}
+\def\df{\let\ttfont=\deftt \let\bffont = \defbf
+\let\slfont=\defsl \let\ttslfont=\defttsl \bf}
+
+% Fonts for indices, footnotes, small examples (9pt).
+\def\smallnominalsize{9pt}
+\setfont\smallrm\rmshape{9}{1000}{OT1}
+\setfont\smalltt\ttshape{9}{1000}{OT1TT}
+\setfont\smallbf\bfshape{10}{900}{OT1}
+\setfont\smallit\itshape{9}{1000}{OT1IT}
+\setfont\smallsl\slshape{9}{1000}{OT1}
+\setfont\smallsf\sfshape{9}{1000}{OT1}
+\setfont\smallsc\scshape{10}{900}{OT1}
+\setfont\smallttsl\ttslshape{10}{900}{OT1TT}
+\font\smalli=cmmi9
+\font\smallsy=cmsy9
+\def\smallecsize{0900}
+
+% Fonts for small examples (8pt).
+\def\smallernominalsize{8pt}
+\setfont\smallerrm\rmshape{8}{1000}{OT1}
+\setfont\smallertt\ttshape{8}{1000}{OT1TT}
+\setfont\smallerbf\bfshape{10}{800}{OT1}
+\setfont\smallerit\itshape{8}{1000}{OT1IT}
+\setfont\smallersl\slshape{8}{1000}{OT1}
+\setfont\smallersf\sfshape{8}{1000}{OT1}
+\setfont\smallersc\scshape{10}{800}{OT1}
+\setfont\smallerttsl\ttslshape{10}{800}{OT1TT}
+\font\smalleri=cmmi8
+\font\smallersy=cmsy8
+\def\smallerecsize{0800}
+
+% Fonts for math mode superscripts (7pt).
+\def\sevennominalsize{7pt}
+\setfont\sevenrm\rmshape{7}{1000}{OT1}
+\setfont\seventt\ttshape{10}{700}{OT1TT}
+\setfont\sevenbf\bfshape{10}{700}{OT1}
+\setfont\sevenit\itshape{7}{1000}{OT1IT}
+\setfont\sevensl\slshape{10}{700}{OT1}
+\setfont\sevensf\sfshape{10}{700}{OT1}
+\setfont\sevensc\scshape{10}{700}{OT1}
+\setfont\seventtsl\ttslshape{10}{700}{OT1TT}
+\font\seveni=cmmi7
+\font\sevensy=cmsy7
+\def\sevenecsize{0700}
+
+% Fonts for title page (20.4pt):
+\def\titlenominalsize{20pt}
+\setfont\titlerm\rmbshape{12}{\magstep3}{OT1}
+\setfont\titleit\itbshape{10}{\magstep4}{OT1IT}
+\setfont\titlesl\slbshape{10}{\magstep4}{OT1}
+\setfont\titlett\ttbshape{12}{\magstep3}{OT1TT}
+\setfont\titlettsl\ttslshape{10}{\magstep4}{OT1TT}
+\setfont\titlesf\sfbshape{17}{\magstep1}{OT1}
+\let\titlebf=\titlerm
+\setfont\titlesc\scbshape{10}{\magstep4}{OT1}
+\font\titlei=cmmi12 scaled \magstep3
+\font\titlesy=cmsy10 scaled \magstep4
+\def\titleecsize{2074}
+
+% Chapter fonts (14.4pt).
+\def\chapnominalsize{14pt}
+\setfont\chaprm\rmbshape{12}{\magstep1}{OT1}
+\setfont\chapit\itbshape{10}{\magstep2}{OT1IT}
+\setfont\chapsl\slbshape{10}{\magstep2}{OT1}
+\setfont\chaptt\ttbshape{12}{\magstep1}{OT1TT}
+\setfont\chapttsl\ttslshape{10}{\magstep2}{OT1TT}
+\setfont\chapsf\sfbshape{12}{\magstep1}{OT1}
+\let\chapbf\chaprm
+\setfont\chapsc\scbshape{10}{\magstep2}{OT1}
+\font\chapi=cmmi12 scaled \magstep1
+\font\chapsy=cmsy10 scaled \magstep2
+\def\chapecsize{1440}
+
+% Section fonts (12pt).
+\def\secnominalsize{12pt}
+\setfont\secrm\rmbshape{12}{1000}{OT1}
+\setfont\secit\itbshape{10}{\magstep1}{OT1IT}
+\setfont\secsl\slbshape{10}{\magstep1}{OT1}
+\setfont\sectt\ttbshape{12}{1000}{OT1TT}
+\setfont\secttsl\ttslshape{10}{\magstep1}{OT1TT}
+\setfont\secsf\sfbshape{12}{1000}{OT1}
+\let\secbf\secrm
+\setfont\secsc\scbshape{10}{\magstep1}{OT1}
+\font\seci=cmmi12
+\font\secsy=cmsy10 scaled \magstep1
+\def\sececsize{1200}
+
+% Subsection fonts (10pt).
+\def\ssecnominalsize{10pt}
+\setfont\ssecrm\rmbshape{10}{1000}{OT1}
+\setfont\ssecit\itbshape{10}{1000}{OT1IT}
+\setfont\ssecsl\slbshape{10}{1000}{OT1}
+\setfont\ssectt\ttbshape{10}{1000}{OT1TT}
+\setfont\ssecttsl\ttslshape{10}{1000}{OT1TT}
+\setfont\ssecsf\sfbshape{10}{1000}{OT1}
+\let\ssecbf\ssecrm
+\setfont\ssecsc\scbshape{10}{1000}{OT1}
+\font\sseci=cmmi10
+\font\ssecsy=cmsy10
+\def\ssececsize{1000}
+
+% Reduced fonts for @acronym in text (9pt).
+\def\reducednominalsize{9pt}
+\setfont\reducedrm\rmshape{9}{1000}{OT1}
+\setfont\reducedtt\ttshape{9}{1000}{OT1TT}
+\setfont\reducedbf\bfshape{10}{900}{OT1}
+\setfont\reducedit\itshape{9}{1000}{OT1IT}
+\setfont\reducedsl\slshape{9}{1000}{OT1}
+\setfont\reducedsf\sfshape{9}{1000}{OT1}
+\setfont\reducedsc\scshape{10}{900}{OT1}
+\setfont\reducedttsl\ttslshape{10}{900}{OT1TT}
+\font\reducedi=cmmi9
+\font\reducedsy=cmsy9
+\def\reducedecsize{0900}
+
+\divide\parskip by 2  % reduce space between paragraphs
+\textleading = 12pt   % line spacing for 10pt CM
+\textfonts            % reset the current fonts
+\rm
+} % end of 10pt text font size definitions, \definetextfontsizex
+
+% Fonts for short table of contents.
+\setfont\shortcontrm\rmshape{12}{1000}{OT1}
+\setfont\shortcontbf\bfshape{10}{\magstep1}{OT1}  % no cmb12
+\setfont\shortcontsl\slshape{12}{1000}{OT1}
+\setfont\shortconttt\ttshape{12}{1000}{OT1TT}
+
+
+% We provide the user-level command
+%   @fonttextsize 10
+% (or 11) to redefine the text font size.  pt is assumed.
+%
+\def\xiword{11}
+\def\xword{10}
+\def\xwordpt{10pt}
+%
+\parseargdef\fonttextsize{%
+  \def\textsizearg{#1}%
+  %\wlog{doing @fonttextsize \textsizearg}%
+  %
+  % Set \globaldefs so that documents can use this inside @tex, since
+  % makeinfo 4.8 does not support it, but we need it nonetheless.
+  %
+ \begingroup \globaldefs=1
+  \ifx\textsizearg\xword \definetextfontsizex
+  \else \ifx\textsizearg\xiword \definetextfontsizexi
+  \else
+    \errhelp=\EMsimple
+    \errmessage{@fonttextsize only supports `10' or `11', not `\textsizearg'}
+  \fi\fi
+ \endgroup
+}
+
+%
+% Change the current font style to #1, remembering it in \curfontstyle.
+% For now, we do not accumulate font styles: @b{@i{foo}} prints foo in
+% italics, not bold italics.
+%
+\def\setfontstyle#1{%
+  \def\curfontstyle{#1}% not as a control sequence, because we are \edef'd.
+  \csname #1font\endcsname  % change the current font
+}
+
+\def\rm{\fam=0 \setfontstyle{rm}}
+\def\it{\fam=\itfam \setfontstyle{it}}
+\def\sl{\fam=\slfam \setfontstyle{sl}}
+\def\bf{\fam=\bffam \setfontstyle{bf}}\def\bfstylename{bf}
+\def\tt{\fam=\ttfam \setfontstyle{tt}}\def\ttstylename{tt}
+
+% Texinfo sort of supports the sans serif font style, which plain TeX does not.
+% So we set up a \sf.
+\newfam\sffam
+\def\sf{\fam=\sffam \setfontstyle{sf}}
+
+% We don't need math for this font style.
+\def\ttsl{\setfontstyle{ttsl}}
+
+
+% In order for the font changes to affect most math symbols and letters,
+% we have to define the \textfont of the standard families.
+% We don't bother to reset \scriptscriptfont; awaiting user need.
+%
+\def\resetmathfonts{%
+  \textfont0=\rmfont \textfont1=\ifont \textfont2=\syfont
+  \textfont\itfam=\itfont \textfont\slfam=\slfont \textfont\bffam=\bffont
+  \textfont\ttfam=\ttfont \textfont\sffam=\sffont
+  %
+  % Fonts for superscript.  Note that the 7pt fonts are used regardless
+  % of the current font size.
+  \scriptfont0=\sevenrm \scriptfont1=\seveni \scriptfont2=\sevensy
+  \scriptfont\itfam=\sevenit \scriptfont\slfam=\sevensl
+  \scriptfont\bffam=\sevenbf \scriptfont\ttfam=\seventt
+  \scriptfont\sffam=\sevensf
+}
+
+%
+
+% The font-changing commands (all called \...fonts) redefine the meanings
+% of \STYLEfont, instead of just \STYLE.  We do this because \STYLE needs
+% to also set the current \fam for math mode.  Our \STYLE (e.g., \rm)
+% commands hardwire \STYLEfont to set the current font.
+%
+% The fonts used for \ifont are for "math italics"  (\itfont is for italics
+% in regular text).  \syfont is also used in math mode only.
+%
+% Each font-changing command also sets the names \lsize (one size lower)
+% and \lllsize (three sizes lower).  These relative commands are used
+% in, e.g., the LaTeX logo and acronyms.
+%
+% This all needs generalizing, badly.
+%
+
+\def\assignfonts#1{%
+  \expandafter\let\expandafter\rmfont\csname #1rm\endcsname
+  \expandafter\let\expandafter\itfont\csname #1it\endcsname
+  \expandafter\let\expandafter\slfont\csname #1sl\endcsname
+  \expandafter\let\expandafter\bffont\csname #1bf\endcsname
+  \expandafter\let\expandafter\ttfont\csname #1tt\endcsname
+  \expandafter\let\expandafter\smallcaps\csname #1sc\endcsname
+  \expandafter\let\expandafter\sffont  \csname #1sf\endcsname
+  \expandafter\let\expandafter\ifont   \csname #1i\endcsname
+  \expandafter\let\expandafter\syfont  \csname #1sy\endcsname
+  \expandafter\let\expandafter\ttslfont\csname #1ttsl\endcsname
+}
+
+\newif\ifrmisbold
+
+% Select smaller font size with the current style.  Used to change font size
+% in, e.g., the LaTeX logo and acronyms.  If we are using bold fonts for
+% normal roman text, also use bold fonts for roman text in the smaller size.
+\def\switchtolllsize{%
+   \expandafter\assignfonts\expandafter{\lllsize}%
+   \ifrmisbold
+     \let\rmfont\bffont
+   \fi
+   \csname\curfontstyle\endcsname
+}%
+
+\def\switchtolsize{%
+   \expandafter\assignfonts\expandafter{\lsize}%
+   \ifrmisbold
+     \let\rmfont\bffont
+   \fi
+   \csname\curfontstyle\endcsname
+}%
+
+\def\definefontsetatsize#1#2#3#4#5{%
+\expandafter\def\csname #1fonts\endcsname{%
+  \def\curfontsize{#1}%
+  \def\lsize{#2}\def\lllsize{#3}%
+  \csname rmisbold#5\endcsname
+  \assignfonts{#1}%
+  \resetmathfonts
+  \setleading{#4}%
+}}
+
+\definefontsetatsize{text}   {reduced}{smaller}{\textleading}{false}
+\definefontsetatsize{title}  {chap}   {subsec} {27pt}  {true}
+\definefontsetatsize{chap}   {sec}    {text}   {19pt}  {true}
+\definefontsetatsize{sec}    {subsec} {reduced}{17pt}  {true}
+\definefontsetatsize{ssec}   {text}   {small}  {15pt}  {true}
+\definefontsetatsize{reduced}{small}  {smaller}{10.5pt}{false}
+\definefontsetatsize{small}  {smaller}{smaller}{10.5pt}{false}
+\definefontsetatsize{smaller}{smaller}{smaller}{9.5pt} {false}
+
+\def\titlefont#1{{\titlefonts\rm #1}}
+\let\subsecfonts = \ssecfonts
+\let\subsubsecfonts = \ssecfonts
+
+% Define these just so they can be easily changed for other fonts.
+\def\angleleft{$\langle$}
+\def\angleright{$\rangle$}
+
+% Set the fonts to use with the @small... environments.
+\let\smallexamplefonts = \smallfonts
+
+% About \smallexamplefonts.  If we use \smallfonts (9pt), @smallexample
+% can fit this many characters:
+%   8.5x11=86   smallbook=72  a4=90  a5=69
+% If we use \scriptfonts (8pt), then we can fit this many characters:
+%   8.5x11=90+  smallbook=80  a4=90+  a5=77
+% For me, subjectively, the few extra characters that fit aren't worth
+% the additional smallness of 8pt.  So I'm making the default 9pt.
+%
+% By the way, for comparison, here's what fits with @example (10pt):
+%   8.5x11=71  smallbook=60  a4=75  a5=58
+% --karl, 24jan03.
+
+% Set up the default fonts, so we can use them for creating boxes.
+%
+\definetextfontsizexi
+
+
+% Check if we are currently using a typewriter font.  Since all the
+% Computer Modern typewriter fonts have zero interword stretch (and
+% shrink), and it is reasonable to expect all typewriter fonts to have
+% this property, we can check that font parameter.
+%
+\def\ifmonospace{\ifdim\fontdimen3\font=0pt }
+
+{
+\catcode`\'=\active
+\catcode`\`=\active
+
+\gdef\setcodequotes{\let`\codequoteleft \let'\codequoteright}
+\gdef\setregularquotes{\let`\lq \let'\rq}
+}
+
+% Allow an option to not use regular directed right quote/apostrophe
+% (char 0x27), but instead the undirected quote from cmtt (char 0x0d).
+% The undirected quote is ugly, so don't make it the default, but it
+% works for pasting with more pdf viewers (at least evince), the
+% lilypond developers report.  xpdf does work with the regular 0x27.
+%
+\def\codequoteright{%
+  \ifmonospace
+    \expandafter\ifx\csname SETtxicodequoteundirected\endcsname\relax
+      \expandafter\ifx\csname SETcodequoteundirected\endcsname\relax
+        '%
+      \else \char'15 \fi
+    \else \char'15 \fi
+   \else
+     '%
+   \fi
+}
+%
+% and a similar option for the left quote char vs. a grave accent.
+% Modern fonts display ASCII 0x60 as a grave accent, so some people like
+% the code environments to do likewise.
+%
+\def\codequoteleft{%
+  \ifmonospace
+    \expandafter\ifx\csname SETtxicodequotebacktick\endcsname\relax
+      \expandafter\ifx\csname SETcodequotebacktick\endcsname\relax
+        % [Knuth] pp. 380,381,391
+        % \relax disables Spanish ligatures ?` and !` of \tt font.
+        \relax`%
+      \else \char'22 \fi
+    \else \char'22 \fi
+   \else
+     \relax`%
+   \fi
+}
+
+% Commands to set the quote options.
+%
+\parseargdef\codequoteundirected{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETtxicodequoteundirected\endcsname
+      = t%
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETtxicodequoteundirected\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @codequoteundirected value `\temp', must be on|off}%
+  \fi\fi
+}
+%
+\parseargdef\codequotebacktick{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETtxicodequotebacktick\endcsname
+      = t%
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETtxicodequotebacktick\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @codequotebacktick value `\temp', must be on|off}%
+  \fi\fi
+}
+
+% [Knuth] pp. 380,381,391, disable Spanish ligatures ?` and !` of \tt font.
+\def\noligaturesquoteleft{\relax\lq}
+
+% Count depth in font-changes, for error checks
+\newcount\fontdepth \fontdepth=0
+
+% Font commands.
+
+% #1 is the font command (\sl or \it), #2 is the text to slant.
+% If we are in a monospaced environment, however, 1) always use \ttsl,
+% and 2) do not add an italic correction.
+\def\dosmartslant#1#2{%
+  \ifusingtt
+    {{\ttsl #2}\let\next=\relax}%
+    {\def\next{{#1#2}\futurelet\next\smartitaliccorrection}}%
+  \next
+}
+\def\smartslanted{\dosmartslant\sl}
+\def\smartitalic{\dosmartslant\it}
+
+% Output an italic correction unless \next (presumed to be the following
+% character) is such as not to need one.
+\def\smartitaliccorrection{%
+  \ifx\next,%
+  \else\ifx\next-%
+  \else\ifx\next.%
+  \else\ifx\next\.%
+  \else\ifx\next\comma%
+  \else\ptexslash
+  \fi\fi\fi\fi\fi
+  \aftersmartic
+}
+
+% Unconditional use \ttsl, and no ic.  @var is set to this for defuns.
+\def\ttslanted#1{{\ttsl #1}}
+
+% @cite is like \smartslanted except unconditionally use \sl.  We never want
+% ttsl for book titles, do we?
+\def\cite#1{{\sl #1}\futurelet\next\smartitaliccorrection}
+
+\def\aftersmartic{}
+\def\var#1{%
+  \let\saveaftersmartic = \aftersmartic
+  \def\aftersmartic{\null\let\aftersmartic=\saveaftersmartic}%
+  \smartslanted{#1}%
+}
+
+\let\i=\smartitalic
+\let\slanted=\smartslanted
+\let\dfn=\smartslanted
+\let\emph=\smartitalic
+
+% Explicit font changes: @r, @sc, undocumented @ii.
+\def\r#1{{\rm #1}}              % roman font
+\def\sc#1{{\smallcaps#1}}       % smallcaps font
+\def\ii#1{{\it #1}}             % italic font
+
+% @b, explicit bold.  Also @strong.
+\def\b#1{{\bf #1}}
+\let\strong=\b
+
+% @sansserif, explicit sans.
+\def\sansserif#1{{\sf #1}}
+
+% We can't just use \exhyphenpenalty, because that only has effect at
+% the end of a paragraph.  Restore normal hyphenation at the end of the
+% group within which \nohyphenation is presumably called.
+%
+\def\nohyphenation{\hyphenchar\font = -1  \aftergroup\restorehyphenation}
+\def\restorehyphenation{\hyphenchar\font = `- }
+
+% Set sfcode to normal for the chars that usually have another value.
+% Can't use plain's \frenchspacing because it uses the `\x notation, and
+% sometimes \x has an active definition that messes things up.
+%
+\catcode`@=11
+  \def\plainfrenchspacing{%
+    \sfcode`\.=\@m \sfcode`\?=\@m \sfcode`\!=\@m
+    \sfcode`\:=\@m \sfcode`\;=\@m \sfcode`\,=\@m
+    \def\endofsentencespacefactor{1000}% for @. and friends
+  }
+  \def\plainnonfrenchspacing{%
+    \sfcode`\.3000\sfcode`\?3000\sfcode`\!3000
+    \sfcode`\:2000\sfcode`\;1500\sfcode`\,1250
+    \def\endofsentencespacefactor{3000}% for @. and friends
+  }
+\catcode`@=\other
+\def\endofsentencespacefactor{3000}% default
+
+% @t, explicit typewriter.
+\def\t#1{%
+  {\tt \plainfrenchspacing #1}%
+  \null
+}
+
+% @samp.
+\def\samp#1{{\setcodequotes\lq\tclose{#1}\rq\null}}
+
+% @indicateurl is \samp, that is, with quotes.
+\let\indicateurl=\samp
+
+% @code (and similar) prints in typewriter, but with spaces the same
+% size as normal in the surrounding text, without hyphenation, etc.
+% This is a subroutine for that.
+\def\tclose#1{%
+  {%
+    % Change normal interword space to be same as for the current font.
+    \spaceskip = \fontdimen2\font
+    %
+    % Switch to typewriter.
+    \tt
+    %
+    % But `\ ' produces the large typewriter interword space.
+    \def\ {{\spaceskip = 0pt{} }}%
+    %
+    % Turn off hyphenation.
+    \nohyphenation
+    %
+    \plainfrenchspacing
+    #1%
+  }%
+  \null % reset spacefactor to 1000
+}
+
+% We *must* turn on hyphenation at `-' and `_' in @code.
+% (But see \codedashfinish below.)
+% Otherwise, it is too hard to avoid overfull hboxes
+% in the Emacs manual, the Library manual, etc.
+%
+% Unfortunately, TeX uses one parameter (\hyphenchar) to control
+% both hyphenation at - and hyphenation within words.
+% We must therefore turn them both off (\tclose does that)
+% and arrange explicitly to hyphenate at a dash. -- rms.
+{
+  \catcode`\-=\active \catcode`\_=\active
+  \catcode`\'=\active \catcode`\`=\active
+  \global\let'=\rq \global\let`=\lq  % default definitions
+  %
+  \global\def\code{\begingroup
+    \setcodequotes
+    \catcode\dashChar=\active  \catcode\underChar=\active
+    \ifallowcodebreaks
+     \let-\codedash
+     \let_\codeunder
+    \else
+     \let-\normaldash
+     \let_\realunder
+    \fi
+    % Given -foo (with a single dash), we do not want to allow a break
+    % after the hyphen.
+    \global\let\codedashprev=\codedash
+    %
+    \codex
+  }
+  %
+  \gdef\codedash{\futurelet\next\codedashfinish}
+  \gdef\codedashfinish{%
+    \normaldash % always output the dash character itself.
+    %
+    % Now, output a discretionary to allow a line break, unless
+    % (a) the next character is a -, or
+    % (b) the preceding character is a -.
+    % E.g., given --posix, we do not want to allow a break after either -.
+    % Given --foo-bar, we do want to allow a break between the - and the b.
+    \ifx\next\codedash \else
+      \ifx\codedashprev\codedash
+      \else \discretionary{}{}{}\fi
+    \fi
+    % we need the space after the = for the case when \next itself is a
+    % space token; it would get swallowed otherwise.  As in @code{- a}.
+    \global\let\codedashprev= \next
+  }
+}
+\def\normaldash{-}
+%
+\def\codex #1{\tclose{#1}\endgroup}
+
+\def\codeunder{%
+  % this is all so @math{@code{var_name}+1} can work.  In math mode, _
+  % is "active" (mathcode"8000) and \normalunderscore (or \char95, etc.)
+  % will therefore expand the active definition of _, which is us
+  % (inside @code that is), therefore an endless loop.
+  \ifusingtt{\ifmmode
+               \mathchar"075F % class 0=ordinary, family 7=ttfam, pos 0x5F=_.
+             \else\normalunderscore \fi
+             \discretionary{}{}{}}%
+            {\_}%
+}
+
+% An additional complication: the above will allow breaks after, e.g.,
+% each of the four underscores in __typeof__.  This is bad.
+% @allowcodebreaks provides a document-level way to turn breaking at -
+% and _ on and off.
+%
+\newif\ifallowcodebreaks  \allowcodebreakstrue
+
+\def\keywordtrue{true}
+\def\keywordfalse{false}
+
+\parseargdef\allowcodebreaks{%
+  \def\txiarg{#1}%
+  \ifx\txiarg\keywordtrue
+    \allowcodebreakstrue
+  \else\ifx\txiarg\keywordfalse
+    \allowcodebreaksfalse
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @allowcodebreaks option `\txiarg', must be true|false}%
+  \fi\fi
+}
+
+% For @command, @env, @file, @option quotes seem unnecessary,
+% so use \code rather than \samp.
+\let\command=\code
+\let\env=\code
+\let\file=\code
+\let\option=\code
+
+% @uref (abbreviation for `urlref') aka @url takes an optional
+% (comma-separated) second argument specifying the text to display and
+% an optional third arg as text to display instead of (rather than in
+% addition to) the url itself.  First (mandatory) arg is the url.
+
+% TeX-only option to allow changing PDF output to show only the second
+% arg (if given), and not the url (which is then just the link target).
+\newif\ifurefurlonlylink
+
+% The default \pretolerance setting stops the penalty inserted in
+% \urefallowbreak being a discouragement to line breaking.  Set it to
+% a negative value for this paragraph only.  Hopefully this does not
+% conflict with redefinitions of \par done elsewhere.
+\def\nopretolerance{%
+\pretolerance=-1
+\def\par{\endgraf\pretolerance=100 \let\par\endgraf}%
+}
+
+% The main macro is \urefbreak, which allows breaking at expected
+% places within the url.
+\def\urefbreak{\nopretolerance \begingroup \urefcatcodes \dourefbreak}
+\let\uref=\urefbreak
+%
+\def\dourefbreak#1{\urefbreakfinish #1,,,\finish}
+\def\urefbreakfinish#1,#2,#3,#4\finish{% doesn't work in @example
+  \unsepspaces
+  \pdfurl{#1}%
+  \setbox0 = \hbox{\ignorespaces #3}%
+  \ifdim\wd0 > 0pt
+    \unhbox0 % third arg given, show only that
+  \else
+    \setbox0 = \hbox{\ignorespaces #2}% look for second arg
+    \ifdim\wd0 > 0pt
+      \ifpdf
+        % For pdfTeX and LuaTeX
+        \ifurefurlonlylink
+          % PDF plus option to not display url, show just arg
+          \unhbox0
+        \else
+          % PDF, normally display both arg and url for consistency,
+          % visibility, if the pdf is eventually used to print, etc.
+          \unhbox0\ (\urefcode{#1})%
+        \fi
+      \else
+        \ifx\XeTeXrevision\thisisundefined
+          \unhbox0\ (\urefcode{#1})% DVI, always show arg and url
+        \else
+          % For XeTeX
+          \ifurefurlonlylink
+            % PDF plus option to not display url, show just arg
+            \unhbox0
+          \else
+            % PDF, normally display both arg and url for consistency,
+            % visibility, if the pdf is eventually used to print, etc.
+            \unhbox0\ (\urefcode{#1})%
+          \fi
+        \fi
+      \fi
+    \else
+      \urefcode{#1}% only url given, so show it
+    \fi
+  \fi
+  \endlink
+\endgroup}
+
+% Allow line breaks around only a few characters (only).
+\def\urefcatcodes{%
+  \catcode`\&=\active \catcode`\.=\active
+  \catcode`\#=\active \catcode`\?=\active
+  \catcode`\/=\active
+}
+{
+  \urefcatcodes
+  %
+  \global\def\urefcode{\begingroup
+    \setcodequotes
+    \urefcatcodes
+    \let&\urefcodeamp
+    \let.\urefcodedot
+    \let#\urefcodehash
+    \let?\urefcodequest
+    \let/\urefcodeslash
+    \codex
+  }
+  %
+  % By default, they are just regular characters.
+  \global\def&{\normalamp}
+  \global\def.{\normaldot}
+  \global\def#{\normalhash}
+  \global\def?{\normalquest}
+  \global\def/{\normalslash}
+}
+
+\def\urefcodeamp{\urefprebreak \&\urefpostbreak}
+\def\urefcodedot{\urefprebreak .\urefpostbreak}
+\def\urefcodehash{\urefprebreak \#\urefpostbreak}
+\def\urefcodequest{\urefprebreak ?\urefpostbreak}
+\def\urefcodeslash{\futurelet\next\urefcodeslashfinish}
+{
+  \catcode`\/=\active
+  \global\def\urefcodeslashfinish{%
+    \urefprebreak \slashChar
+    % Allow line break only after the final / in a sequence of
+    % slashes, to avoid line break between the slashes in http://.
+    \ifx\next/\else \urefpostbreak \fi
+  }
+}
+
+% By default we'll break after the special characters, but some people like to
+% break before the special chars, so allow that.  Also allow no breaking at
+% all, for manual control.
+%
+\parseargdef\urefbreakstyle{%
+  \def\txiarg{#1}%
+  \ifx\txiarg\wordnone
+    \def\urefprebreak{\nobreak}\def\urefpostbreak{\nobreak}
+  \else\ifx\txiarg\wordbefore
+    \def\urefprebreak{\urefallowbreak}\def\urefpostbreak{\nobreak}
+  \else\ifx\txiarg\wordafter
+    \def\urefprebreak{\nobreak}\def\urefpostbreak{\urefallowbreak}
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @urefbreakstyle setting `\txiarg'}%
+  \fi\fi\fi
+}
+\def\wordafter{after}
+\def\wordbefore{before}
+\def\wordnone{none}
+
+% Allow a ragged right output to aid breaking long URL's.  There can
+% be a break at the \allowbreak with no extra glue (if the existing stretch in
+% the line is sufficient), a break at the \penalty with extra glue added
+% at the end of the line, or no break at all here.
+%   Changing the value of the penalty and/or the amount of stretch affects how
+% preferable one choice is over the other.
+\def\urefallowbreak{%
+  \penalty0\relax
+  \hskip 0pt plus 2 em\relax
+  \penalty1000\relax
+  \hskip 0pt plus -2 em\relax
+}
+
+\urefbreakstyle after
+
+% @url synonym for @uref, since that's how everyone uses it.
+%
+\let\url=\uref
+
+% rms does not like angle brackets --karl, 17may97.
+% So now @email is just like @uref, unless we are pdf.
+%
+%\def\email#1{\angleleft{\tt #1}\angleright}
+\ifpdforxetex
+  \def\email#1{\doemail#1,,\finish}
+  \def\doemail#1,#2,#3\finish{\begingroup
+    \unsepspaces
+    \pdfurl{mailto:#1}%
+    \setbox0 = \hbox{\ignorespaces #2}%
+    \ifdim\wd0>0pt\unhbox0\else\code{#1}\fi
+    \endlink
+  \endgroup}
+\else
+  \let\email=\uref
+\fi
+
+% @kbdinputstyle -- arg is `distinct' (@kbd uses slanted tty font always),
+%   `example' (@kbd uses ttsl only inside of @example and friends),
+%   or `code' (@kbd uses normal tty font always).
+\parseargdef\kbdinputstyle{%
+  \def\txiarg{#1}%
+  \ifx\txiarg\worddistinct
+    \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\ttsl}%
+  \else\ifx\txiarg\wordexample
+    \gdef\kbdexamplefont{\ttsl}\gdef\kbdfont{\tt}%
+  \else\ifx\txiarg\wordcode
+    \gdef\kbdexamplefont{\tt}\gdef\kbdfont{\tt}%
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @kbdinputstyle setting `\txiarg'}%
+  \fi\fi\fi
+}
+\def\worddistinct{distinct}
+\def\wordexample{example}
+\def\wordcode{code}
+
+% Default is `distinct'.
+\kbdinputstyle distinct
+
+% @kbd is like @code, except that if the argument is just one @key command,
+% then @kbd has no effect.
+\def\kbd#1{{\def\look{#1}\expandafter\kbdsub\look??\par}}
+
+\def\xkey{\key}
+\def\kbdsub#1#2#3\par{%
+  \def\one{#1}\def\three{#3}\def\threex{??}%
+  \ifx\one\xkey\ifx\threex\three \key{#2}%
+  \else{\tclose{\kbdfont\setcodequotes\look}}\fi
+  \else{\tclose{\kbdfont\setcodequotes\look}}\fi
+}
+
+% definition of @key that produces a lozenge.  Doesn't adjust to text size.
+%\setfont\keyrm\rmshape{8}{1000}{OT1}
+%\font\keysy=cmsy9
+%\def\key#1{{\keyrm\textfont2=\keysy \leavevmode\hbox{%
+%  \raise0.4pt\hbox{\angleleft}\kern-.08em\vtop{%
+%    \vbox{\hrule\kern-0.4pt
+%     \hbox{\raise0.4pt\hbox{\vphantom{\angleleft}}#1}}%
+%    \kern-0.4pt\hrule}%
+%  \kern-.06em\raise0.4pt\hbox{\angleright}}}}
+
+% definition of @key with no lozenge.  If the current font is already
+% monospace, don't change it; that way, we respect @kbdinputstyle.  But
+% if it isn't monospace, then use \tt.
+%
+\def\key#1{{\setregularquotes
+  \nohyphenation
+  \ifmonospace\else\tt\fi
+  #1}\null}
+
+% @clicksequence{File @click{} Open ...}
+\def\clicksequence#1{\begingroup #1\endgroup}
+
+% @clickstyle @arrow   (by default)
+\parseargdef\clickstyle{\def\click{#1}}
+\def\click{\arrow}
+
+% Typeset a dimension, e.g., `in' or `pt'.  The only reason for the
+% argument is to make the input look right: @dmn{pt} instead of @dmn{}pt.
+%
+\def\dmn#1{\thinspace #1}
+
+% @acronym for "FBI", "NATO", and the like.
+% We print this one point size smaller, since it's intended for
+% all-uppercase.
+%
+\def\acronym#1{\doacronym #1,,\finish}
+\def\doacronym#1,#2,#3\finish{%
+  {\switchtolsize #1}%
+  \def\temp{#2}%
+  \ifx\temp\empty \else
+    \space ({\unsepspaces \ignorespaces \temp \unskip})%
+  \fi
+  \null % reset \spacefactor=1000
+}
+
+% @abbr for "Comput. J." and the like.
+% No font change, but don't do end-of-sentence spacing.
+%
+\def\abbr#1{\doabbr #1,,\finish}
+\def\doabbr#1,#2,#3\finish{%
+  {\plainfrenchspacing #1}%
+  \def\temp{#2}%
+  \ifx\temp\empty \else
+    \space ({\unsepspaces \ignorespaces \temp \unskip})%
+  \fi
+  \null % reset \spacefactor=1000
+}
+
+% @asis just yields its argument.  Used with @table, for example.
+%
+\def\asis#1{#1}
+
+% @math outputs its argument in math mode.
+%
+% One complication: _ usually means subscripts, but it could also mean
+% an actual _ character, as in @math{@var{some_variable} + 1}.  So make
+% _ active, and distinguish by seeing if the current family is \slfam,
+% which is what @var uses.
+{
+  \catcode`\_ = \active
+  \gdef\mathunderscore{%
+    \catcode`\_=\active
+    \def_{\ifnum\fam=\slfam \_\else\sb\fi}%
+  }
+}
+% Another complication: we want \\ (and @\) to output a math (or tt) \.
+% FYI, plain.tex uses \\ as a temporary control sequence (for no
+% particular reason), but this is not advertised and we don't care.
+%
+% The \mathchar is class=0=ordinary, family=7=ttfam, position=5C=\.
+\def\mathbackslash{\ifnum\fam=\ttfam \mathchar"075C \else\backslash \fi}
+%
+\def\math{%
+  \ifmmode\else % only go into math if not in math mode already
+    \tex
+    \mathunderscore
+    \let\\ = \mathbackslash
+    \mathactive
+    % make the texinfo accent commands work in math mode
+    \let\"=\ddot
+    \let\'=\acute
+    \let\==\bar
+    \let\^=\hat
+    \let\`=\grave
+    \let\u=\breve
+    \let\v=\check
+    \let\~=\tilde
+    \let\dotaccent=\dot
+    % have to provide another name for sup operator
+    \let\mathopsup=\sup
+  $\expandafter\finishmath\fi
+}
+\def\finishmath#1{#1$\endgroup}  % Close the group opened by \tex.
+
+% Some active characters (such as <) are spaced differently in math.
+% We have to reset their definitions in case the @math was an argument
+% to a command which sets the catcodes (such as @item or @section).
+%
+{
+  \catcode`^ = \active
+  \catcode`< = \active
+  \catcode`> = \active
+  \catcode`+ = \active
+  \catcode`' = \active
+  \gdef\mathactive{%
+    \let^ = \ptexhat
+    \let< = \ptexless
+    \let> = \ptexgtr
+    \let+ = \ptexplus
+    \let' = \ptexquoteright
+  }
+}
+
+% for @sub and @sup, if in math mode, just do a normal sub/superscript.
+% If in text, use math to place as sub/superscript, but switch
+% into text mode, with smaller fonts.  This is a different font than the
+% one used for real math sub/superscripts (8pt vs. 7pt), but let's not
+% fix it (significant additions to font machinery) until someone notices.
+%
+\def\sub{\ifmmode \expandafter\sb \else \expandafter\finishsub\fi}
+\def\finishsub#1{$\sb{\hbox{\switchtolllsize #1}}$}%
+%
+\def\sup{\ifmmode \expandafter\ptexsp \else \expandafter\finishsup\fi}
+\def\finishsup#1{$\ptexsp{\hbox{\switchtolllsize #1}}$}%
+
+% provide this command from LaTeX as it is very common
+\def\frac#1#2{{{#1}\over{#2}}}
+
+% @displaymath.
+% \globaldefs is needed to recognize the end lines in \tex and
+% \end tex.  Set \thisenv as @end displaymath is seen before @end tex.
+{\obeylines
+\globaldefs=1
+\envdef\displaymath{%
+\tex%
+\def\thisenv{\displaymath}%
+\begingroup\let\end\displaymathend%
+$$%
+}
+
+\def\displaymathend{$$\endgroup\end}%
+
+\def\Edisplaymath{%
+\def\thisenv{\tex}%
+\end tex
+}}
+
+
+% @inlinefmt{FMTNAME,PROCESSED-TEXT} and @inlineraw{FMTNAME,RAW-TEXT}.
+% Ignore unless FMTNAME == tex; then it is like @iftex and @tex,
+% except specified as a normal braced arg, so no newlines to worry about.
+%
+\def\outfmtnametex{tex}
+%
+\long\def\inlinefmt#1{\doinlinefmt #1,\finish}
+\long\def\doinlinefmt#1,#2,\finish{%
+  \def\inlinefmtname{#1}%
+  \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\fi
+}
+%
+% @inlinefmtifelse{FMTNAME,THEN-TEXT,ELSE-TEXT} expands THEN-TEXT if
+% FMTNAME is tex, else ELSE-TEXT.
+\long\def\inlinefmtifelse#1{\doinlinefmtifelse #1,,,\finish}
+\long\def\doinlinefmtifelse#1,#2,#3,#4,\finish{%
+  \def\inlinefmtname{#1}%
+  \ifx\inlinefmtname\outfmtnametex \ignorespaces #2\else \ignorespaces #3\fi
+}
+%
+% For raw, must switch into @tex before parsing the argument, to avoid
+% setting catcodes prematurely.  Doing it this way means that, for
+% example, @inlineraw{html, foo{bar} gets a parse error instead of being
+% ignored.  But this isn't important because if people want a literal
+% *right* brace they would have to use a command anyway, so they may as
+% well use a command to get a left brace too.  We could re-use the
+% delimiter character idea from \verb, but it seems like overkill.
+%
+\long\def\inlineraw{\tex \doinlineraw}
+\long\def\doinlineraw#1{\doinlinerawtwo #1,\finish}
+\def\doinlinerawtwo#1,#2,\finish{%
+  \def\inlinerawname{#1}%
+  \ifx\inlinerawname\outfmtnametex \ignorespaces #2\fi
+  \endgroup % close group opened by \tex.
+}
+
+% @inlineifset{VAR, TEXT} expands TEXT if VAR is @set.
+%
+\long\def\inlineifset#1{\doinlineifset #1,\finish}
+\long\def\doinlineifset#1,#2,\finish{%
+  \def\inlinevarname{#1}%
+  \expandafter\ifx\csname SET\inlinevarname\endcsname\relax
+  \else\ignorespaces#2\fi
+}
+
+% @inlineifclear{VAR, TEXT} expands TEXT if VAR is not @set.
+%
+\long\def\inlineifclear#1{\doinlineifclear #1,\finish}
+\long\def\doinlineifclear#1,#2,\finish{%
+  \def\inlinevarname{#1}%
+  \expandafter\ifx\csname SET\inlinevarname\endcsname\relax \ignorespaces#2\fi
+}
+
+
+\message{glyphs,}
+% and logos.
+
+% @@ prints an @, as does @atchar{}.
+\def\@{\char64 }
+\let\atchar=\@
+
+% @{ @} @lbracechar{} @rbracechar{} all generate brace characters.
+\def\lbracechar{{\ifmonospace\char123\else\ensuremath\lbrace\fi}}
+\def\rbracechar{{\ifmonospace\char125\else\ensuremath\rbrace\fi}}
+\let\{=\lbracechar
+\let\}=\rbracechar
+
+% @comma{} to avoid , parsing problems.
+\let\comma = ,
+
+% Accents: @, @dotaccent @ringaccent @ubaraccent @udotaccent
+% Others are defined by plain TeX: @` @' @" @^ @~ @= @u @v @H.
+\let\, = \ptexc
+\let\dotaccent = \ptexdot
+\def\ringaccent#1{{\accent23 #1}}
+\let\tieaccent = \ptext
+\let\ubaraccent = \ptexb
+\let\udotaccent = \d
+
+% Other special characters: @questiondown @exclamdown @ordf @ordm
+% Plain TeX defines: @AA @AE @O @OE @L (plus lowercase versions) @ss.
+\def\questiondown{?`}
+\def\exclamdown{!`}
+\def\ordf{\leavevmode\raise1ex\hbox{\switchtolllsize \underbar{a}}}
+\def\ordm{\leavevmode\raise1ex\hbox{\switchtolllsize \underbar{o}}}
+
+% Dotless i and dotless j, used for accents.
+\def\imacro{i}
+\def\jmacro{j}
+\def\dotless#1{%
+  \def\temp{#1}%
+  \ifx\temp\imacro \ifmmode\imath \else\ptexi \fi
+  \else\ifx\temp\jmacro \ifmmode\jmath \else\j \fi
+  \else \errmessage{@dotless can be used only with i or j}%
+  \fi\fi
+}
+
+% The \TeX{} logo, as in plain, but resetting the spacing so that a
+% period following counts as ending a sentence.  (Idea found in latex.)
+%
+\edef\TeX{\TeX \spacefactor=1000 }
+
+% @LaTeX{} logo.  Not quite the same results as the definition in
+% latex.ltx, since we use a different font for the raised A; it's most
+% convenient for us to use an explicitly smaller font, rather than using
+% the \scriptstyle font (since we don't reset \scriptstyle and
+% \scriptscriptstyle).
+%
+\def\LaTeX{%
+  L\kern-.36em
+  {\setbox0=\hbox{T}%
+   \vbox to \ht0{\hbox{%
+     \ifx\textnominalsize\xwordpt
+       % for 10pt running text, lllsize (8pt) is too small for the A in LaTeX.
+       % Revert to plain's \scriptsize, which is 7pt.
+       \count255=\the\fam $\fam\count255 \scriptstyle A$%
+     \else
+       % For 11pt, we can use our lllsize.
+       \switchtolllsize A%
+     \fi
+     }%
+     \vss
+  }}%
+  \kern-.15em
+  \TeX
+}
+
+% Some math mode symbols.  Define \ensuremath to switch into math mode
+% unless we are already there.  Expansion tricks may not be needed here,
+% but safer, and can't hurt.
+\def\ensuremath{\ifmmode \expandafter\asis \else\expandafter\ensuredmath \fi}
+\def\ensuredmath#1{$\relax#1$}
+%
+\def\bullet{\ensuremath\ptexbullet}
+\def\geq{\ensuremath\ge}
+\def\leq{\ensuremath\le}
+\def\minus{\ensuremath-}
+
+% @dots{} outputs an ellipsis using the current font.
+% We do .5em per period so that it has the same spacing in the cm
+% typewriter fonts as three actual period characters; on the other hand,
+% in other typewriter fonts three periods are wider than 1.5em.  So do
+% whichever is larger.
+%
+\def\dots{%
+  \leavevmode
+  \setbox0=\hbox{...}% get width of three periods
+  \ifdim\wd0 > 1.5em
+    \dimen0 = \wd0
+  \else
+    \dimen0 = 1.5em
+  \fi
+  \hbox to \dimen0{%
+    \hskip 0pt plus.25fil
+    .\hskip 0pt plus1fil
+    .\hskip 0pt plus1fil
+    .\hskip 0pt plus.5fil
+  }%
+}
+
+% @enddots{} is an end-of-sentence ellipsis.
+%
+\def\enddots{%
+  \dots
+  \spacefactor=\endofsentencespacefactor
+}
+
+% @point{}, @result{}, @expansion{}, @print{}, @equiv{}.
+%
+% Since these characters are used in examples, they should be an even number of
+% \tt widths. Each \tt character is 1en, so two makes it 1em.
+%
+\def\point{$\star$}
+\def\arrow{\leavevmode\raise.05ex\hbox to 1em{\hfil$\rightarrow$\hfil}}
+\def\result{\leavevmode\raise.05ex\hbox to 1em{\hfil$\Rightarrow$\hfil}}
+\def\expansion{\leavevmode\hbox to 1em{\hfil$\mapsto$\hfil}}
+\def\print{\leavevmode\lower.1ex\hbox to 1em{\hfil$\dashv$\hfil}}
+\def\equiv{\leavevmode\hbox to 1em{\hfil$\ptexequiv$\hfil}}
+
+% The @error{} command.
+% Adapted from the TeXbook's \boxit.
+%
+\newbox\errorbox
+%
+{\ttfont \global\dimen0 = 3em}% Width of the box.
+\dimen2 = .55pt % Thickness of rules
+% The text. (`r' is open on the right, `e' somewhat less so on the left.)
+\setbox0 = \hbox{\kern-.75pt \reducedsf \putworderror\kern-1.5pt}
+%
+\setbox\errorbox=\hbox to \dimen0{\hfil
+   \hsize = \dimen0 \advance\hsize by -5.8pt % Space to left+right.
+   \advance\hsize by -2\dimen2 % Rules.
+   \vbox{%
+      \hrule height\dimen2
+      \hbox{\vrule width\dimen2 \kern3pt          % Space to left of text.
+         \vtop{\kern2.4pt \box0 \kern2.4pt}% Space above/below.
+         \kern3pt\vrule width\dimen2}% Space to right.
+      \hrule height\dimen2}
+    \hfil}
+%
+\def\error{\leavevmode\lower.7ex\copy\errorbox}
+
+% @pounds{} is a sterling sign, which Knuth put in the CM italic font.
+%
+\def\pounds{\ifmonospace{\ecfont\char"BF}\else{\it\$}\fi}
+
+% @euro{} comes from a separate font, depending on the current style.
+% We use the free feym* fonts from the eurosym package by Henrik
+% Theiling, which support regular, slanted, bold and bold slanted (and
+% "outlined" (blackboard board, sort of) versions, which we don't need).
+% It is available from http://www.ctan.org/tex-archive/fonts/eurosym.
+%
+% Although only regular is the truly official Euro symbol, we ignore
+% that.  The Euro is designed to be slightly taller than the regular
+% font height.
+%
+% feymr - regular
+% feymo - slanted
+% feybr - bold
+% feybo - bold slanted
+%
+% There is no good (free) typewriter version, to my knowledge.
+% A feymr10 euro is ~7.3pt wide, while a normal cmtt10 char is ~5.25pt wide.
+% Hmm.
+%
+% Also doesn't work in math.  Do we need to do math with euro symbols?
+% Hope not.
+%
+%
+\def\euro{{\eurofont e}}
+\def\eurofont{%
+  % We set the font at each command, rather than predefining it in
+  % \textfonts and the other font-switching commands, so that
+  % installations which never need the symbol don't have to have the
+  % font installed.
+  %
+  % There is only one designed size (nominal 10pt), so we always scale
+  % that to the current nominal size.
+  %
+  % By the way, simply using "at 1em" works for cmr10 and the like, but
+  % does not work for cmbx10 and other extended/shrunken fonts.
+  %
+  \def\eurosize{\csname\curfontsize nominalsize\endcsname}%
+  %
+  \ifx\curfontstyle\bfstylename
+    % bold:
+    \font\thiseurofont = \ifusingit{feybo10}{feybr10} at \eurosize
+  \else
+    % regular:
+    \font\thiseurofont = \ifusingit{feymo10}{feymr10} at \eurosize
+  \fi
+  \thiseurofont
+}
+
+% Glyphs from the EC fonts.  We don't use \let for the aliases, because
+% sometimes we redefine the original macro, and the alias should reflect
+% the redefinition.
+%
+% Use LaTeX names for the Icelandic letters.
+\def\DH{{\ecfont \char"D0}} % Eth
+\def\dh{{\ecfont \char"F0}} % eth
+\def\TH{{\ecfont \char"DE}} % Thorn
+\def\th{{\ecfont \char"FE}} % thorn
+%
+\def\guillemetleft{{\ecfont \char"13}}
+\def\guillemotleft{\guillemetleft}
+\def\guillemetright{{\ecfont \char"14}}
+\def\guillemotright{\guillemetright}
+\def\guilsinglleft{{\ecfont \char"0E}}
+\def\guilsinglright{{\ecfont \char"0F}}
+\def\quotedblbase{{\ecfont \char"12}}
+\def\quotesinglbase{{\ecfont \char"0D}}
+%
+% This positioning is not perfect (see the ogonek LaTeX package), but
+% we have the precomposed glyphs for the most common cases.  We put the
+% tests to use those glyphs in the single \ogonek macro so we have fewer
+% dummy definitions to worry about for index entries, etc.
+%
+% ogonek is also used with other letters in Lithuanian (IOU), but using
+% the precomposed glyphs for those is not so easy since they aren't in
+% the same EC font.
+\def\ogonek#1{{%
+  \def\temp{#1}%
+  \ifx\temp\macrocharA\Aogonek
+  \else\ifx\temp\macrochara\aogonek
+  \else\ifx\temp\macrocharE\Eogonek
+  \else\ifx\temp\macrochare\eogonek
+  \else
+    \ecfont \setbox0=\hbox{#1}%
+    \ifdim\ht0=1ex\accent"0C #1%
+    \else\ooalign{\unhbox0\crcr\hidewidth\char"0C \hidewidth}%
+    \fi
+  \fi\fi\fi\fi
+  }%
+}
+\def\Aogonek{{\ecfont \char"81}}\def\macrocharA{A}
+\def\aogonek{{\ecfont \char"A1}}\def\macrochara{a}
+\def\Eogonek{{\ecfont \char"86}}\def\macrocharE{E}
+\def\eogonek{{\ecfont \char"A6}}\def\macrochare{e}
+%
+% Use the European Computer Modern fonts (cm-super in outline format)
+% for non-CM glyphs.  That is ec* for regular text and tc* for the text
+% companion symbols (LaTeX TS1 encoding).  Both are part of the ec
+% package and follow the same conventions.
+%
+\def\ecfont{\etcfont{e}}
+\def\tcfont{\etcfont{t}}
+%
+\def\etcfont#1{%
+  % We can't distinguish serif/sans and italic/slanted, but this
+  % is used for crude hacks anyway (like adding French and German
+  % quotes to documents typeset with CM, where we lose kerning), so
+  % hopefully nobody will notice/care.
+  \edef\ecsize{\csname\curfontsize ecsize\endcsname}%
+  \edef\nominalsize{\csname\curfontsize nominalsize\endcsname}%
+  \ifmonospace
+    % typewriter:
+    \font\thisecfont = #1ctt\ecsize \space at \nominalsize
+  \else
+    \ifx\curfontstyle\bfstylename
+      % bold:
+      \font\thisecfont = #1cb\ifusingit{i}{x}\ecsize \space at \nominalsize
+    \else
+      % regular:
+      \font\thisecfont = #1c\ifusingit{ti}{rm}\ecsize \space at \nominalsize
+    \fi
+  \fi
+  \thisecfont
+}
+
+% @registeredsymbol - R in a circle.  The font for the R should really
+% be smaller yet, but lllsize is the best we can do for now.
+% Adapted from the plain.tex definition of \copyright.
+%
+\def\registeredsymbol{%
+  $^{{\ooalign{\hfil\raise.07ex\hbox{\switchtolllsize R}%
+               \hfil\crcr\Orb}}%
+    }$%
+}
+
+% @textdegree - the normal degrees sign.
+%
+\def\textdegree{$^\circ$}
+
+% Laurent Siebenmann reports \Orb undefined with:
+%  Textures 1.7.7 (preloaded format=plain 93.10.14)  (68K)  16 APR 2004 02:38
+% so we'll define it if necessary.
+%
+\ifx\Orb\thisisundefined
+\def\Orb{\mathhexbox20D}
+\fi
+
+% Quotes.
+\chardef\quoteleft=`\`
+\chardef\quoteright=`\'
+
+% only change font for tt for correct kerning and to avoid using
+% \ecfont unless necessary.
+\def\quotedblleft{%
+  \ifmonospace{\ecfont\char"10}\else{\char"5C}\fi
+}
+
+\def\quotedblright{%
+  \ifmonospace{\ecfont\char"11}\else{\char`\"}\fi
+}
+
+
+\message{page headings,}
+
+\newskip\titlepagetopglue \titlepagetopglue = 1.5in
+\newskip\titlepagebottomglue \titlepagebottomglue = 2pc
+
+% First the title page.  Must do @settitle before @titlepage.
+\newif\ifseenauthor
+\newif\iffinishedtitlepage
+
+% @setcontentsaftertitlepage used to do an implicit @contents or
+% @shortcontents after @end titlepage, but it is now obsolete.
+\def\setcontentsaftertitlepage{%
+  \errmessage{@setcontentsaftertitlepage has been removed as a Texinfo
+              command; move your @contents command if you want the contents
+              after the title page.}}%
+\def\setshortcontentsaftertitlepage{%
+  \errmessage{@setshortcontentsaftertitlepage has been removed as a Texinfo
+              command; move your @shortcontents and @contents commands if you
+              want the contents after the title page.}}%
+
+\parseargdef\shorttitlepage{%
+  \begingroup \hbox{}\vskip 1.5in \chaprm \centerline{#1}%
+  \endgroup\page\hbox{}\page}
+
+\envdef\titlepage{%
+  % Open one extra group, as we want to close it in the middle of \Etitlepage.
+  \begingroup
+    \parindent=0pt \textfonts
+    % Leave some space at the very top of the page.
+    \vglue\titlepagetopglue
+    % No rule at page bottom unless we print one at the top with @title.
+    \finishedtitlepagetrue
+    %
+    % Most title ``pages'' are actually two pages long, with space
+    % at the top of the second.  We don't want the ragged left on the second.
+    \let\oldpage = \page
+    \def\page{%
+      \iffinishedtitlepage\else
+        \finishtitlepage
+      \fi
+      \let\page = \oldpage
+      \page
+      \null
+    }%
+}
+
+\def\Etitlepage{%
+    \iffinishedtitlepage\else
+       \finishtitlepage
+    \fi
+    % It is important to do the page break before ending the group,
+    % because the headline and footline are only empty inside the group.
+    % If we use the new definition of \page, we always get a blank page
+    % after the title page, which we certainly don't want.
+    \oldpage
+  \endgroup
+  %
+  % Need this before the \...aftertitlepage checks so that if they are
+  % in effect the toc pages will come out with page numbers.
+  \HEADINGSon
+}
+
+\def\finishtitlepage{%
+  \vskip4pt \hrule height 2pt width \hsize
+  \vskip\titlepagebottomglue
+  \finishedtitlepagetrue
+}
+
+% Settings used for typesetting titles: no hyphenation, no indentation,
+% don't worry much about spacing, ragged right.  This should be used
+% inside a \vbox, and fonts need to be set appropriately first. \par should
+% be specified before the end of the \vbox, since a vbox is a group.
+%
+\def\raggedtitlesettings{%
+  \rm
+  \hyphenpenalty=10000
+  \parindent=0pt
+  \tolerance=5000
+  \ptexraggedright
+}
+
+% Macros to be used within @titlepage:
+
+\let\subtitlerm=\rmfont
+\def\subtitlefont{\subtitlerm \normalbaselineskip = 13pt \normalbaselines}
+
+\parseargdef\title{%
+  \checkenv\titlepage
+  \vbox{\titlefonts \raggedtitlesettings #1\par}%
+  % print a rule at the page bottom also.
+  \finishedtitlepagefalse
+  \vskip4pt \hrule height 4pt width \hsize \vskip4pt
+}
+
+\parseargdef\subtitle{%
+  \checkenv\titlepage
+  {\subtitlefont \rightline{#1}}%
+}
+
+% @author should come last, but may come many times.
+% It can also be used inside @quotation.
+%
+\parseargdef\author{%
+  \def\temp{\quotation}%
+  \ifx\thisenv\temp
+    \def\quotationauthor{#1}% printed in \Equotation.
+  \else
+    \checkenv\titlepage
+    \ifseenauthor\else \vskip 0pt plus 1filll \seenauthortrue \fi
+    {\secfonts\rm \leftline{#1}}%
+  \fi
+}
+
+
+% Set up page headings and footings.
+
+\let\thispage=\folio
+
+\newtoks\evenheadline    % headline on even pages
+\newtoks\oddheadline     % headline on odd pages
+\newtoks\evenchapheadline% headline on even pages with a new chapter
+\newtoks\oddchapheadline % headline on odd pages with a new chapter
+\newtoks\evenfootline    % footline on even pages
+\newtoks\oddfootline     % footline on odd pages
+
+% Now make \makeheadline and \makefootline in Plain TeX use those variables
+\headline={{\textfonts\rm
+            \ifchapterpage
+              \ifodd\pageno\the\oddchapheadline\else\the\evenchapheadline\fi
+            \else
+              \ifodd\pageno\the\oddheadline\else\the\evenheadline\fi
+            \fi}}
+
+\footline={{\textfonts\rm \ifodd\pageno \the\oddfootline
+                            \else \the\evenfootline \fi}\HEADINGShook}
+\let\HEADINGShook=\relax
+
+% Commands to set those variables.
+% For example, this is what  @headings on  does
+% @evenheading @thistitle|@thispage|@thischapter
+% @oddheading @thischapter|@thispage|@thistitle
+% @evenfooting @thisfile||
+% @oddfooting ||@thisfile
+
+
+\def\evenheading{\parsearg\evenheadingxxx}
+\def\evenheadingxxx #1{\evenheadingyyy #1\|\|\|\|\finish}
+\def\evenheadingyyy #1\|#2\|#3\|#4\finish{%
+  \global\evenheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}
+  \global\evenchapheadline=\evenheadline}
+
+\def\oddheading{\parsearg\oddheadingxxx}
+\def\oddheadingxxx #1{\oddheadingyyy #1\|\|\|\|\finish}
+\def\oddheadingyyy #1\|#2\|#3\|#4\finish{%
+  \global\oddheadline={\rlap{\centerline{#2}}\line{#1\hfil#3}}%
+  \global\oddchapheadline=\oddheadline}
+
+\parseargdef\everyheading{\oddheadingxxx{#1}\evenheadingxxx{#1}}%
+
+\def\evenfooting{\parsearg\evenfootingxxx}
+\def\evenfootingxxx #1{\evenfootingyyy #1\|\|\|\|\finish}
+\def\evenfootingyyy #1\|#2\|#3\|#4\finish{%
+\global\evenfootline={\rlap{\centerline{#2}}\line{#1\hfil#3}}}
+
+\def\oddfooting{\parsearg\oddfootingxxx}
+\def\oddfootingxxx #1{\oddfootingyyy #1\|\|\|\|\finish}
+\def\oddfootingyyy #1\|#2\|#3\|#4\finish{%
+  \global\oddfootline = {\rlap{\centerline{#2}}\line{#1\hfil#3}}%
+  %
+  % Leave some space for the footline.  Hopefully ok to assume
+  % @evenfooting will not be used by itself.
+  \global\advance\txipageheight by -12pt
+  \global\advance\vsize by -12pt
+}
+
+\parseargdef\everyfooting{\oddfootingxxx{#1}\evenfootingxxx{#1}}
+
+% @evenheadingmarks top     \thischapter <- chapter at the top of a page
+% @evenheadingmarks bottom  \thischapter <- chapter at the bottom of a page
+%
+% The same set of arguments for:
+%
+% @oddheadingmarks
+% @evenfootingmarks
+% @oddfootingmarks
+% @everyheadingmarks
+% @everyfootingmarks
+
+% These define \getoddheadingmarks, \getevenheadingmarks,
+% \getoddfootingmarks, and \getevenfootingmarks, each to one of
+% \gettopheadingmarks, \getbottomheadingmarks.
+%
+\def\evenheadingmarks{\headingmarks{even}{heading}}
+\def\oddheadingmarks{\headingmarks{odd}{heading}}
+\def\evenfootingmarks{\headingmarks{even}{footing}}
+\def\oddfootingmarks{\headingmarks{odd}{footing}}
+\parseargdef\everyheadingmarks{\headingmarks{even}{heading}{#1}
+                          \headingmarks{odd}{heading}{#1} }
+\parseargdef\everyfootingmarks{\headingmarks{even}{footing}{#1}
+                          \headingmarks{odd}{footing}{#1} }
+% #1 = even/odd, #2 = heading/footing, #3 = top/bottom.
+\def\headingmarks#1#2#3 {%
+  \expandafter\let\expandafter\temp \csname get#3headingmarks\endcsname
+  \global\expandafter\let\csname get#1#2marks\endcsname \temp
+}
+
+\everyheadingmarks bottom
+\everyfootingmarks bottom
+
+% @headings double      turns headings on for double-sided printing.
+% @headings single      turns headings on for single-sided printing.
+% @headings off         turns them off.
+% @headings on          same as @headings double, retained for compatibility.
+% @headings after       turns on double-sided headings after this page.
+% @headings doubleafter turns on double-sided headings after this page.
+% @headings singleafter turns on single-sided headings after this page.
+% By default, they are off at the start of a document,
+% and turned `on' after @end titlepage.
+
+\parseargdef\headings{\csname HEADINGS#1\endcsname}
+
+\def\headingsoff{% non-global headings elimination
+  \evenheadline={\hfil}\evenfootline={\hfil}\evenchapheadline={\hfil}%
+   \oddheadline={\hfil}\oddfootline={\hfil}\oddchapheadline={\hfil}%
+}
+
+\def\HEADINGSoff{{\globaldefs=1 \headingsoff}} % global setting
+\HEADINGSoff  % it's the default
+
+% When we turn headings on, set the page number to 1.
+\def\pageone{
+  \global\pageno=1
+  \global\arabiccount = \pagecount
+}
+
+% For double-sided printing, put current file name in lower left corner,
+% chapter name on inside top of right hand pages, document
+% title on inside top of left hand pages, and page numbers on outside top
+% edge of all pages.
+\def\HEADINGSdouble{%
+\pageone
+\HEADINGSdoublex
+}
+\let\contentsalignmacro = \chappager
+
+% For single-sided printing, chapter title goes across top left of page,
+% page number on top right.
+\def\HEADINGSsingle{%
+\pageone
+\HEADINGSsinglex
+}
+\def\HEADINGSon{\HEADINGSdouble}
+
+\def\HEADINGSafter{\let\HEADINGShook=\HEADINGSdoublex}
+\let\HEADINGSdoubleafter=\HEADINGSafter
+\def\HEADINGSdoublex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\folio\hfil\thistitle}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\evenchapheadline={\line{\folio\hfil}}
+\global\oddchapheadline={\line{\hfil\folio}}
+\global\let\contentsalignmacro = \chapoddpage
+}
+
+\def\HEADINGSsingleafter{\let\HEADINGShook=\HEADINGSsinglex}
+\def\HEADINGSsinglex{%
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\evenchapheadline={\line{\hfil\folio}}
+\global\oddchapheadline={\line{\hfil\folio}}
+\global\let\contentsalignmacro = \chappager
+}
+
+% for @setchapternewpage off
+\def\HEADINGSsinglechapoff{%
+\pageone
+\global\evenfootline={\hfil}
+\global\oddfootline={\hfil}
+\global\evenheadline={\line{\thischapter\hfil\folio}}
+\global\oddheadline={\line{\thischapter\hfil\folio}}
+\global\evenchapheadline=\evenheadline
+\global\oddchapheadline=\oddheadline
+\global\let\contentsalignmacro = \chappager
+}
+
+% Subroutines used in generating headings
+% This produces Day Month Year style of output.
+% Only define if not already defined, in case a txi-??.tex file has set
+% up a different format (e.g., txi-cs.tex does this).
+\ifx\today\thisisundefined
+\def\today{%
+  \number\day\space
+  \ifcase\month
+  \or\putwordMJan\or\putwordMFeb\or\putwordMMar\or\putwordMApr
+  \or\putwordMMay\or\putwordMJun\or\putwordMJul\or\putwordMAug
+  \or\putwordMSep\or\putwordMOct\or\putwordMNov\or\putwordMDec
+  \fi
+  \space\number\year}
+\fi
+
+% @settitle line...  specifies the title of the document, for headings.
+% It generates no output of its own.
+\def\thistitle{\putwordNoTitle}
+\def\settitle{\parsearg{\gdef\thistitle}}
+
+
+\message{tables,}
+% Tables -- @table, @ftable, @vtable, @item(x).
+
+% default indentation of table text
+\newdimen\tableindent \tableindent=.8in
+% default indentation of @itemize and @enumerate text
+\newdimen\itemindent  \itemindent=.3in
+% margin between end of table item and start of table text.
+\newdimen\itemmargin  \itemmargin=.1in
+
+% used internally for \itemindent minus \itemmargin
+\newdimen\itemmax
+
+% Note @table, @ftable, and @vtable define @item, @itemx, etc., with
+% these defs.
+% They also define \itemindex
+% to index the item name in whatever manner is desired (perhaps none).
+
+\newif\ifitemxneedsnegativevskip
+
+\def\itemxpar{\par\ifitemxneedsnegativevskip\nobreak\vskip-\parskip\nobreak\fi}
+
+\def\internalBitem{\smallbreak \parsearg\itemzzz}
+\def\internalBitemx{\itemxpar \parsearg\itemzzz}
+
+\def\itemzzz #1{\begingroup %
+  \advance\hsize by -\rightskip
+  \advance\hsize by -\tableindent
+  \setbox0=\hbox{\itemindicate{#1}}%
+  \itemindex{#1}%
+  \nobreak % This prevents a break before @itemx.
+  %
+  % If the item text does not fit in the space we have, put it on a line
+  % by itself, and do not allow a page break either before or after that
+  % line.  We do not start a paragraph here because then if the next
+  % command is, e.g., @kindex, the whatsit would get put into the
+  % horizontal list on a line by itself, resulting in extra blank space.
+  \ifdim \wd0>\itemmax
+    %
+    % Make this a paragraph so we get the \parskip glue and wrapping,
+    % but leave it ragged-right.
+    \begingroup
+      \advance\leftskip by-\tableindent
+      \advance\hsize by\tableindent
+      \advance\rightskip by0pt plus1fil\relax
+      \leavevmode\unhbox0\par
+    \endgroup
+    %
+    % We're going to be starting a paragraph, but we don't want the
+    % \parskip glue -- logically it's part of the @item we just started.
+    \nobreak \vskip-\parskip
+    %
+    % Stop a page break at the \parskip glue coming up.  However, if
+    % what follows is an environment such as @example, there will be no
+    % \parskip glue; then the negative vskip we just inserted would
+    % cause the example and the item to crash together.  So we use this
+    % bizarre value of 10001 as a signal to \aboveenvbreak to insert
+    % \parskip glue after all.  Section titles are handled this way also.
+    %
+    \penalty 10001
+    \endgroup
+    \itemxneedsnegativevskipfalse
+  \else
+    % The item text fits into the space.  Start a paragraph, so that the
+    % following text (if any) will end up on the same line.
+    \noindent
+    % Do this with kerns and \unhbox so that if there is a footnote in
+    % the item text, it can migrate to the main vertical list and
+    % eventually be printed.
+    \nobreak\kern-\tableindent
+    \dimen0 = \itemmax  \advance\dimen0 by \itemmargin \advance\dimen0 by -\wd0
+    \unhbox0
+    \nobreak\kern\dimen0
+    \endgroup
+    \itemxneedsnegativevskiptrue
+  \fi
+}
+
+\def\item{\errmessage{@item while not in a list environment}}
+\def\itemx{\errmessage{@itemx while not in a list environment}}
+
+% @table, @ftable, @vtable.
+\envdef\table{%
+  \let\itemindex\gobble
+  \tablecheck{table}%
+}
+\envdef\ftable{%
+  \def\itemindex ##1{\doind {fn}{\code{##1}}}%
+  \tablecheck{ftable}%
+}
+\envdef\vtable{%
+  \def\itemindex ##1{\doind {vr}{\code{##1}}}%
+  \tablecheck{vtable}%
+}
+\def\tablecheck#1{%
+  \ifnum \the\catcode`\^^M=\active
+    \endgroup
+    \errmessage{This command won't work in this context; perhaps the problem is
+      that we are \inenvironment\thisenv}%
+    \def\next{\doignore{#1}}%
+  \else
+    \let\next\tablex
+  \fi
+  \next
+}
+\def\tablex#1{%
+  \def\itemindicate{#1}%
+  \parsearg\tabley
+}
+\def\tabley#1{%
+  {%
+    \makevalueexpandable
+    \edef\temp{\noexpand\tablez #1\space\space\space}%
+    \expandafter
+  }\temp \endtablez
+}
+\def\tablez #1 #2 #3 #4\endtablez{%
+  \aboveenvbreak
+  \ifnum 0#1>0 \advance \leftskip by #1\mil \fi
+  \ifnum 0#2>0 \tableindent=#2\mil \fi
+  \ifnum 0#3>0 \advance \rightskip by #3\mil \fi
+  \itemmax=\tableindent
+  \advance \itemmax by -\itemmargin
+  \advance \leftskip by \tableindent
+  \exdentamount=\tableindent
+  \parindent = 0pt
+  \parskip = \smallskipamount
+  \ifdim \parskip=0pt \parskip=2pt \fi
+  \let\item = \internalBitem
+  \let\itemx = \internalBitemx
+}
+\def\Etable{\endgraf\afterenvbreak}
+\let\Eftable\Etable
+\let\Evtable\Etable
+\let\Eitemize\Etable
+\let\Eenumerate\Etable
+
+% This is the counter used by @enumerate, which is really @itemize
+
+\newcount \itemno
+
+\envdef\itemize{\parsearg\doitemize}
+
+\def\doitemize#1{%
+  \aboveenvbreak
+  \itemmax=\itemindent
+  \advance\itemmax by -\itemmargin
+  \advance\leftskip by \itemindent
+  \exdentamount=\itemindent
+  \parindent=0pt
+  \parskip=\smallskipamount
+  \ifdim\parskip=0pt \parskip=2pt \fi
+  %
+  % Try typesetting the item mark so that if the document erroneously says
+  % something like @itemize @samp (intending @table), there's an error
+  % right away at the @itemize.  It's not the best error message in the
+  % world, but it's better than leaving it to the @item.  This means if
+  % the user wants an empty mark, they have to say @w{} not just @w.
+  \def\itemcontents{#1}%
+  \setbox0 = \hbox{\itemcontents}%
+  %
+  % @itemize with no arg is equivalent to @itemize @bullet.
+  \ifx\itemcontents\empty\def\itemcontents{\bullet}\fi
+  %
+  \let\item=\itemizeitem
+}
+
+% Definition of @item while inside @itemize and @enumerate.
+%
+\def\itemizeitem{%
+  \advance\itemno by 1  % for enumerations
+  {\let\par=\endgraf \smallbreak}% reasonable place to break
+  {%
+   % If the document has an @itemize directly after a section title, a
+   % \nobreak will be last on the list, and \sectionheading will have
+   % done a \vskip-\parskip.  In that case, we don't want to zero
+   % parskip, or the item text will crash with the heading.  On the
+   % other hand, when there is normal text preceding the item (as there
+   % usually is), we do want to zero parskip, or there would be too much
+   % space.  In that case, we won't have a \nobreak before.  At least
+   % that's the theory.
+   \ifnum\lastpenalty<10000 \parskip=0in \fi
+   \noindent
+   \hbox to 0pt{\hss \itemcontents \kern\itemmargin}%
+   %
+   \ifinner\else
+     \vadjust{\penalty 1200}% not good to break after first line of item.
+   \fi
+   % We can be in inner vertical mode in a footnote, although an
+   % @itemize looks awful there.
+  }%
+  \flushcr
+}
+
+% \splitoff TOKENS\endmark defines \first to be the first token in
+% TOKENS, and \rest to be the remainder.
+%
+\def\splitoff#1#2\endmark{\def\first{#1}\def\rest{#2}}%
+
+% Allow an optional argument of an uppercase letter, lowercase letter,
+% or number, to specify the first label in the enumerated list.  No
+% argument is the same as `1'.
+%
+\envparseargdef\enumerate{\enumeratey #1  \endenumeratey}
+\def\enumeratey #1 #2\endenumeratey{%
+  % If we were given no argument, pretend we were given `1'.
+  \def\thearg{#1}%
+  \ifx\thearg\empty \def\thearg{1}\fi
+  %
+  % Detect if the argument is a single token.  If so, it might be a
+  % letter.  Otherwise, the only valid thing it can be is a number.
+  % (We will always have one token, because of the test we just made.
+  % This is a good thing, since \splitoff doesn't work given nothing at
+  % all -- the first parameter is undelimited.)
+  \expandafter\splitoff\thearg\endmark
+  \ifx\rest\empty
+    % Only one token in the argument.  It could still be anything.
+    % A ``lowercase letter'' is one whose \lccode is nonzero.
+    % An ``uppercase letter'' is one whose \lccode is both nonzero, and
+    %   not equal to itself.
+    % Otherwise, we assume it's a number.
+    %
+    % We need the \relax at the end of the \ifnum lines to stop TeX from
+    % continuing to look for a <number>.
+    %
+    \ifnum\lccode\expandafter`\thearg=0\relax
+      \numericenumerate % a number (we hope)
+    \else
+      % It's a letter.
+      \ifnum\lccode\expandafter`\thearg=\expandafter`\thearg\relax
+        \lowercaseenumerate % lowercase letter
+      \else
+        \uppercaseenumerate % uppercase letter
+      \fi
+    \fi
+  \else
+    % Multiple tokens in the argument.  We hope it's a number.
+    \numericenumerate
+  \fi
+}
+
+% An @enumerate whose labels are integers.  The starting integer is
+% given in \thearg.
+%
+\def\numericenumerate{%
+  \itemno = \thearg
+  \startenumeration{\the\itemno}%
+}
+
+% The starting (lowercase) letter is in \thearg.
+\def\lowercaseenumerate{%
+  \itemno = \expandafter`\thearg
+  \startenumeration{%
+    % Be sure we're not beyond the end of the alphabet.
+    \ifnum\itemno=0
+      \errmessage{No more lowercase letters in @enumerate; get a bigger
+                  alphabet}%
+    \fi
+    \char\lccode\itemno
+  }%
+}
+
+% The starting (uppercase) letter is in \thearg.
+\def\uppercaseenumerate{%
+  \itemno = \expandafter`\thearg
+  \startenumeration{%
+    % Be sure we're not beyond the end of the alphabet.
+    \ifnum\itemno=0
+      \errmessage{No more uppercase letters in @enumerate; get a bigger
+                  alphabet}
+    \fi
+    \char\uccode\itemno
+  }%
+}
+
+% Call \doitemize, adding a period to the first argument and supplying the
+% common last two arguments.  Also subtract one from the initial value in
+% \itemno, since @item increments \itemno.
+%
+\def\startenumeration#1{%
+  \advance\itemno by -1
+  \doitemize{#1.}\flushcr
+}
+
+% @alphaenumerate and @capsenumerate are abbreviations for giving an arg
+% to @enumerate.
+%
+\def\alphaenumerate{\enumerate{a}}
+\def\capsenumerate{\enumerate{A}}
+\def\Ealphaenumerate{\Eenumerate}
+\def\Ecapsenumerate{\Eenumerate}
+
+
+% @multitable macros
+% Amy Hendrickson, 8/18/94, 3/6/96
+%
+% @multitable ... @end multitable will make as many columns as desired.
+% Contents of each column will wrap at width given in preamble.  Width
+% can be specified either with sample text given in a template line,
+% or in percent of \hsize, the current width of text on page.
+
+% Table can continue over pages but will only break between lines.
+
+% To make preamble:
+%
+% Either define widths of columns in terms of percent of \hsize:
+%   @multitable @columnfractions .25 .3 .45
+%   @item ...
+%
+%   Numbers following @columnfractions are the percent of the total
+%   current hsize to be used for each column. You may use as many
+%   columns as desired.
+
+
+% Or use a template:
+%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+%   @item ...
+%   using the widest term desired in each column.
+
+% Each new table line starts with @item, each subsequent new column
+% starts with @tab. Empty columns may be produced by supplying @tab's
+% with nothing between them for as many times as empty columns are needed,
+% ie, @tab@tab@tab will produce two empty columns.
+
+% @item, @tab do not need to be on their own lines, but it will not hurt
+% if they are.
+
+% Sample multitable:
+
+%   @multitable {Column 1 template} {Column 2 template} {Column 3 template}
+%   @item first col stuff @tab second col stuff @tab third col
+%   @item
+%   first col stuff
+%   @tab
+%   second col stuff
+%   @tab
+%   third col
+%   @item first col stuff @tab second col stuff
+%   @tab Many paragraphs of text may be used in any column.
+%
+%         They will wrap at the width determined by the template.
+%   @item@tab@tab This will be in third column.
+%   @end multitable
+
+% Default dimensions may be reset by user.
+% @multitableparskip is vertical space between paragraphs in table.
+% @multitableparindent is paragraph indent in table.
+% @multitablecolmargin is horizontal space to be left between columns.
+% @multitablelinespace is space to leave between table items, baseline
+%                                                            to baseline.
+%   0pt means it depends on current normal line spacing.
+%
+\newskip\multitableparskip
+\newskip\multitableparindent
+\newdimen\multitablecolspace
+\newskip\multitablelinespace
+\multitableparskip=0pt
+\multitableparindent=6pt
+\multitablecolspace=12pt
+\multitablelinespace=0pt
+
+% Macros used to set up halign preamble:
+%
+\let\endsetuptable\relax
+\def\xendsetuptable{\endsetuptable}
+\let\columnfractions\relax
+\def\xcolumnfractions{\columnfractions}
+\newif\ifsetpercent
+
+% #1 is the @columnfraction, usually a decimal number like .5, but might
+% be just 1.  We just use it, whatever it is.
+%
+\def\pickupwholefraction#1 {%
+  \global\advance\colcount by 1
+  \expandafter\xdef\csname col\the\colcount\endcsname{#1\hsize}%
+  \setuptable
+}
+
+\newcount\colcount
+\def\setuptable#1{%
+  \def\firstarg{#1}%
+  \ifx\firstarg\xendsetuptable
+    \let\go = \relax
+  \else
+    \ifx\firstarg\xcolumnfractions
+      \global\setpercenttrue
+    \else
+      \ifsetpercent
+         \let\go\pickupwholefraction
+      \else
+         \global\advance\colcount by 1
+         \setbox0=\hbox{#1\unskip\space}% Add a normal word space as a
+                   % separator; typically that is always in the input, anyway.
+         \expandafter\xdef\csname col\the\colcount\endcsname{\the\wd0}%
+      \fi
+    \fi
+    \ifx\go\pickupwholefraction
+      % Put the argument back for the \pickupwholefraction call, so
+      % we'll always have a period there to be parsed.
+      \def\go{\pickupwholefraction#1}%
+    \else
+      \let\go = \setuptable
+    \fi%
+  \fi
+  \go
+}
+
+% multitable-only commands.
+%
+% @headitem starts a heading row, which we typeset in bold.  Assignments
+% have to be global since we are inside the implicit group of an
+% alignment entry.  \everycr below resets \everytab so we don't have to
+% undo it ourselves.
+\def\headitemfont{\b}% for people to use in the template row; not changeable
+\def\headitem{%
+  \checkenv\multitable
+  \crcr
+  \gdef\headitemcrhook{\nobreak}% attempt to avoid page break after headings
+  \global\everytab={\bf}% can't use \headitemfont since the parsing differs
+  \the\everytab % for the first item
+}%
+%
+% default for tables with no headings.
+\let\headitemcrhook=\relax
+%
+% A \tab used to include \hskip1sp.  But then the space in a template
+% line is not enough.  That is bad.  So let's go back to just `&' until
+% we again encounter the problem the 1sp was intended to solve.
+%                                      --karl, nathan@acm.org, 20apr99.
+\def\tab{\checkenv\multitable &\the\everytab}%
+
+% @multitable ... @end multitable definitions:
+%
+\newtoks\everytab  % insert after every tab.
+%
+\envdef\multitable{%
+  \vskip\parskip
+  \startsavinginserts
+  %
+  % @item within a multitable starts a normal row.
+  % We use \def instead of \let so that if one of the multitable entries
+  % contains an @itemize, we don't choke on the \item (seen as \crcr aka
+  % \endtemplate) expanding \doitemize.
+  \def\item{\crcr}%
+  %
+  \tolerance=9500
+  \hbadness=9500
+  \setmultitablespacing
+  \parskip=\multitableparskip
+  \parindent=\multitableparindent
+  \overfullrule=0pt
+  \global\colcount=0
+  %
+  \everycr = {%
+    \noalign{%
+      \global\everytab={}% Reset from possible headitem.
+      \global\colcount=0 % Reset the column counter.
+      %
+      % Check for saved footnotes, etc.:
+      \checkinserts
+      %
+      % Perhaps a \nobreak, then reset:
+      \headitemcrhook
+      \global\let\headitemcrhook=\relax
+    }%
+  }%
+  %
+  \parsearg\domultitable
+}
+\def\domultitable#1{%
+  % To parse everything between @multitable and @item:
+  \setuptable#1 \endsetuptable
+  %
+  % This preamble sets up a generic column definition, which will
+  % be used as many times as user calls for columns.
+  % \vtop will set a single line and will also let text wrap and
+  % continue for many paragraphs if desired.
+  \halign\bgroup &%
+    \global\advance\colcount by 1
+    \multistrut
+    \vtop{%
+      % Use the current \colcount to find the correct column width:
+      \hsize=\expandafter\csname col\the\colcount\endcsname
+      %
+      % In order to keep entries from bumping into each other
+      % we will add a \leftskip of \multitablecolspace to all columns after
+      % the first one.
+      %
+      % If a template has been used, we will add \multitablecolspace
+      % to the width of each template entry.
+      %
+      % If the user has set preamble in terms of percent of \hsize we will
+      % use that dimension as the width of the column, and the \leftskip
+      % will keep entries from bumping into each other.  Table will start at
+      % left margin and final column will justify at right margin.
+      %
+      % Make sure we don't inherit \rightskip from the outer environment.
+      \rightskip=0pt
+      \ifnum\colcount=1
+       % The first column will be indented with the surrounding text.
+       \advance\hsize by\leftskip
+      \else
+       \ifsetpercent \else
+         % If user has not set preamble in terms of percent of \hsize
+         % we will advance \hsize by \multitablecolspace.
+         \advance\hsize by \multitablecolspace
+       \fi
+       % In either case we will make \leftskip=\multitablecolspace:
+      \leftskip=\multitablecolspace
+      \fi
+      % Ignoring space at the beginning and end avoids an occasional spurious
+      % blank line, when TeX decides to break the line at the space before the
+      % box from the multistrut, so the strut ends up on a line by itself.
+      % For example:
+      % @multitable @columnfractions .11 .89
+      % @item @code{#}
+      % @tab Legal holiday which is valid in major parts of the whole country.
+      % Is automatically provided with highlighting sequences respectively
+      % marking characters.
+      \noindent\ignorespaces##\unskip\multistrut
+    }\cr
+}
+\def\Emultitable{%
+  \crcr
+  \egroup % end the \halign
+  \global\setpercentfalse
+}
+
+\def\setmultitablespacing{%
+  \def\multistrut{\strut}% just use the standard line spacing
+  %
+  % Compute \multitablelinespace (if not defined by user) for use in
+  % \multitableparskip calculation.  We used define \multistrut based on
+  % this, but (ironically) that caused the spacing to be off.
+  % See bug-texinfo report from Werner Lemberg, 31 Oct 2004 12:52:20 +0100.
+\ifdim\multitablelinespace=0pt
+\setbox0=\vbox{X}\global\multitablelinespace=\the\baselineskip
+\global\advance\multitablelinespace by-\ht0
+\fi
+% Test to see if parskip is larger than space between lines of
+% table. If not, do nothing.
+%        If so, set to same dimension as multitablelinespace.
+\ifdim\multitableparskip>\multitablelinespace
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt % to keep parskip somewhat smaller
+                                      % than skip between lines in the table.
+\fi%
+\ifdim\multitableparskip=0pt
+\global\multitableparskip=\multitablelinespace
+\global\advance\multitableparskip-7pt % to keep parskip somewhat smaller
+                                      % than skip between lines in the table.
+\fi}
+
+
+\message{conditionals,}
+
+% @iftex, @ifnotdocbook, @ifnothtml, @ifnotinfo, @ifnotplaintext,
+% @ifnotxml always succeed.  They currently do nothing; we don't
+% attempt to check whether the conditionals are properly nested.  But we
+% have to remember that they are conditionals, so that @end doesn't
+% attempt to close an environment group.
+%
+\def\makecond#1{%
+  \expandafter\let\csname #1\endcsname = \relax
+  \expandafter\let\csname iscond.#1\endcsname = 1
+}
+\makecond{iftex}
+\makecond{ifnotdocbook}
+\makecond{ifnothtml}
+\makecond{ifnotinfo}
+\makecond{ifnotplaintext}
+\makecond{ifnotxml}
+
+% Ignore @ignore, @ifhtml, @ifinfo, and the like.
+%
+\def\direntry{\doignore{direntry}}
+\def\documentdescription{\doignore{documentdescription}}
+\def\docbook{\doignore{docbook}}
+\def\html{\doignore{html}}
+\def\ifdocbook{\doignore{ifdocbook}}
+\def\ifhtml{\doignore{ifhtml}}
+\def\ifinfo{\doignore{ifinfo}}
+\def\ifnottex{\doignore{ifnottex}}
+\def\ifplaintext{\doignore{ifplaintext}}
+\def\ifxml{\doignore{ifxml}}
+\def\ignore{\doignore{ignore}}
+\def\menu{\doignore{menu}}
+\def\xml{\doignore{xml}}
+
+% Ignore text until a line `@end #1', keeping track of nested conditionals.
+%
+% A count to remember the depth of nesting.
+\newcount\doignorecount
+
+\def\doignore#1{\begingroup
+  % Scan in ``verbatim'' mode:
+  \obeylines
+  \catcode`\@ = \other
+  \catcode`\{ = \other
+  \catcode`\} = \other
+  %
+  % Make sure that spaces turn into tokens that match what \doignoretext wants.
+  \spaceisspace
+  %
+  % Count number of #1's that we've seen.
+  \doignorecount = 0
+  %
+  % Swallow text until we reach the matching `@end #1'.
+  \dodoignore{#1}%
+}
+
+{ \catcode`_=11 % We want to use \_STOP_ which cannot appear in texinfo source.
+  \obeylines %
+  %
+  \gdef\dodoignore#1{%
+    % #1 contains the command name as a string, e.g., `ifinfo'.
+    %
+    % Define a command to find the next `@end #1'.
+    \long\def\doignoretext##1^^M@end #1{%
+      \doignoretextyyy##1^^M@#1\_STOP_}%
+    %
+    % And this command to find another #1 command, at the beginning of a
+    % line.  (Otherwise, we would consider a line `@c @ifset', for
+    % example, to count as an @ifset for nesting.)
+    \long\def\doignoretextyyy##1^^M@#1##2\_STOP_{\doignoreyyy{##2}\_STOP_}%
+    %
+    % And now expand that command.
+    \doignoretext ^^M%
+  }%
+}
+
+\def\doignoreyyy#1{%
+  \def\temp{#1}%
+  \ifx\temp\empty                      % Nothing found.
+    \let\next\doignoretextzzz
+  \else                                        % Found a nested condition, ...
+    \advance\doignorecount by 1
+    \let\next\doignoretextyyy          % ..., look for another.
+    % If we're here, #1 ends with ^^M\ifinfo (for example).
+  \fi
+  \next #1% the token \_STOP_ is present just after this macro.
+}
+
+% We have to swallow the remaining "\_STOP_".
+%
+\def\doignoretextzzz#1{%
+  \ifnum\doignorecount = 0     % We have just found the outermost @end.
+    \let\next\enddoignore
+  \else                                % Still inside a nested condition.
+    \advance\doignorecount by -1
+    \let\next\doignoretext      % Look for the next @end.
+  \fi
+  \next
+}
+
+% Finish off ignored text.
+{ \obeylines%
+  % Ignore anything after the last `@end #1'; this matters in verbatim
+  % environments, where otherwise the newline after an ignored conditional
+  % would result in a blank line in the output.
+  \gdef\enddoignore#1^^M{\endgroup\ignorespaces}%
+}
+
+
+% @set VAR sets the variable VAR to an empty value.
+% @set VAR REST-OF-LINE sets VAR to the value REST-OF-LINE.
+%
+% Since we want to separate VAR from REST-OF-LINE (which might be
+% empty), we can't just use \parsearg; we have to insert a space of our
+% own to delimit the rest of the line, and then take it out again if we
+% didn't need it.
+% We rely on the fact that \parsearg sets \catcode`\ =10.
+%
+\parseargdef\set{\setyyy#1 \endsetyyy}
+\def\setyyy#1 #2\endsetyyy{%
+  {%
+    \makevalueexpandable
+    \def\temp{#2}%
+    \edef\next{\gdef\makecsname{SET#1}}%
+    \ifx\temp\empty
+      \next{}%
+    \else
+      \setzzz#2\endsetzzz
+    \fi
+  }%
+}
+% Remove the trailing space \setxxx inserted.
+\def\setzzz#1 \endsetzzz{\next{#1}}
+
+% @clear VAR clears (i.e., unsets) the variable VAR.
+%
+\parseargdef\clear{%
+  {%
+    \makevalueexpandable
+    \global\expandafter\let\csname SET#1\endcsname=\relax
+  }%
+}
+
+% @value{foo} gets the text saved in variable foo.
+\def\value{\begingroup\makevalueexpandable\valuexxx}
+\def\valuexxx#1{\expandablevalue{#1}\endgroup}
+{
+  \catcode`\-=\active \catcode`\_=\active
+  %
+  \gdef\makevalueexpandable{%
+    \let\value = \expandablevalue
+    % We don't want these characters active, ...
+    \catcode`\-=\other \catcode`\_=\other
+    % ..., but we might end up with active ones in the argument if
+    % we're called from @code, as @code{@value{foo-bar_}}, though.
+    % So \let them to their normal equivalents.
+    \let-\normaldash \let_\normalunderscore
+  }
+}
+
+\def\expandablevalue#1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    {[No value for ``#1'']}%
+    \message{Variable `#1', used in @value, is not set.}%
+  \else
+    \csname SET#1\endcsname
+  \fi
+}
+
+% Like \expandablevalue, but completely expandable (the \message in the
+% definition above operates at the execution level of TeX).  Used when
+% writing to auxiliary files, due to the expansion that \write does.
+% If flag is undefined, pass through an unexpanded @value command: maybe it
+% will be set by the time it is read back in.
+%
+% NB flag names containing - or _ may not work here.
+\def\dummyvalue#1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    \string\value{#1}%
+  \else
+    \csname SET#1\endcsname
+  \fi
+}
+
+% Used for @value's in index entries to form the sort key: expand the @value
+% if possible, otherwise sort late.
+\def\indexnofontsvalue#1{%
+  \expandafter\ifx\csname SET#1\endcsname\relax
+    ZZZZZZZ%
+  \else
+    \csname SET#1\endcsname
+  \fi
+}
+
+% @ifset VAR ... @end ifset reads the `...' iff VAR has been defined
+% with @set.
+%
+% To get the special treatment we need for `@end ifset,' we call
+% \makecond and then redefine.
+%
+\makecond{ifset}
+\def\ifset{\parsearg{\doifset{\let\next=\ifsetfail}}}
+\def\doifset#1#2{%
+  {%
+    \makevalueexpandable
+    \let\next=\empty
+    \expandafter\ifx\csname SET#2\endcsname\relax
+      #1% If not set, redefine \next.
+    \fi
+    \expandafter
+  }\next
+}
+\def\ifsetfail{\doignore{ifset}}
+
+% @ifclear VAR ... @end executes the `...' iff VAR has never been
+% defined with @set, or has been undefined with @clear.
+%
+% The `\else' inside the `\doifset' parameter is a trick to reuse the
+% above code: if the variable is not set, do nothing, if it is set,
+% then redefine \next to \ifclearfail.
+%
+\makecond{ifclear}
+\def\ifclear{\parsearg{\doifset{\else \let\next=\ifclearfail}}}
+\def\ifclearfail{\doignore{ifclear}}
+
+% @ifcommandisdefined CMD ... @end executes the `...' if CMD (written
+% without the @) is in fact defined.  We can only feasibly check at the
+% TeX level, so something like `mathcode' is going to considered
+% defined even though it is not a Texinfo command.
+%
+\makecond{ifcommanddefined}
+\def\ifcommanddefined{\parsearg{\doifcmddefined{\let\next=\ifcmddefinedfail}}}
+%
+\def\doifcmddefined#1#2{{%
+    \makevalueexpandable
+    \let\next=\empty
+    \expandafter\ifx\csname #2\endcsname\relax
+      #1% If not defined, \let\next as above.
+    \fi
+    \expandafter
+  }\next
+}
+\def\ifcmddefinedfail{\doignore{ifcommanddefined}}
+
+% @ifcommandnotdefined CMD ... handled similar to @ifclear above.
+\makecond{ifcommandnotdefined}
+\def\ifcommandnotdefined{%
+  \parsearg{\doifcmddefined{\else \let\next=\ifcmdnotdefinedfail}}}
+\def\ifcmdnotdefinedfail{\doignore{ifcommandnotdefined}}
+
+% Set the `txicommandconditionals' variable, so documents have a way to
+% test if the @ifcommand...defined conditionals are available.
+\set txicommandconditionals
+
+% @dircategory CATEGORY  -- specify a category of the dir file
+% which this file should belong to.  Ignore this in TeX.
+\let\dircategory=\comment
+
+% @defininfoenclose.
+\let\definfoenclose=\comment
+
+
+\message{indexing,}
+% Index generation facilities
+
+% Define \newwrite to be identical to plain tex's \newwrite
+% except not \outer, so it can be used within macros and \if's.
+\edef\newwrite{\makecsname{ptexnewwrite}}
+
+% \newindex {foo} defines an index named IX.
+% It automatically defines \IXindex such that
+% \IXindex ...rest of line... puts an entry in the index IX.
+% It also defines \IXindfile to be the number of the output channel for
+% the file that accumulates this index.  The file's extension is IX.
+% The name of an index should be no more than 2 characters long
+% for the sake of vms.
+%
+\def\newindex#1{%
+  \expandafter\chardef\csname#1indfile\endcsname=0
+  \expandafter\xdef\csname#1index\endcsname{%     % Define @#1index
+    \noexpand\doindex{#1}}
+}
+
+% @defindex foo  ==  \newindex{foo}
+%
+\def\defindex{\parsearg\newindex}
+
+% Define @defcodeindex, like @defindex except put all entries in @code.
+%
+\def\defcodeindex{\parsearg\newcodeindex}
+%
+\def\newcodeindex#1{%
+  \expandafter\chardef\csname#1indfile\endcsname=0
+  \expandafter\xdef\csname#1index\endcsname{%
+    \noexpand\docodeindex{#1}}%
+}
+
+% The default indices:
+\newindex{cp}%      concepts,
+\newcodeindex{fn}%  functions,
+\newcodeindex{vr}%  variables,
+\newcodeindex{tp}%  types,
+\newcodeindex{ky}%  keys
+\newcodeindex{pg}%  and programs.
+
+
+% @synindex foo bar    makes index foo feed into index bar.
+% Do this instead of @defindex foo if you don't want it as a separate index.
+%
+% @syncodeindex foo bar   similar, but put all entries made for index foo
+% inside @code.
+%
+\def\synindex#1 #2 {\dosynindex\doindex{#1}{#2}}
+\def\syncodeindex#1 #2 {\dosynindex\docodeindex{#1}{#2}}
+
+% #1 is \doindex or \docodeindex, #2 the index getting redefined (foo),
+% #3 the target index (bar).
+\def\dosynindex#1#2#3{%
+  \requireopenindexfile{#3}%
+  % redefine \fooindfile:
+  \expandafter\let\expandafter\temp\expandafter=\csname#3indfile\endcsname
+  \expandafter\let\csname#2indfile\endcsname=\temp
+  % redefine \fooindex:
+  \expandafter\xdef\csname#2index\endcsname{\noexpand#1{#3}}%
+}
+
+% Define \doindex, the driver for all index macros.
+% Argument #1 is generated by the calling \fooindex macro,
+% and it is the two-letter name of the index.
+
+\def\doindex#1{\edef\indexname{#1}\parsearg\doindexxxx}
+\def\doindexxxx #1{\doind{\indexname}{#1}}
+
+% like the previous two, but they put @code around the argument.
+\def\docodeindex#1{\edef\indexname{#1}\parsearg\docodeindexxxx}
+\def\docodeindexxxx #1{\docind{\indexname}{#1}}
+
+
+% Used for the aux, toc and index files to prevent expansion of Texinfo
+% commands.
+%
+\def\atdummies{%
+  \definedummyletter\@%
+  \definedummyletter\ %
+  \definedummyletter\{%
+  \definedummyletter\}%
+  \definedummyletter\&%
+  %
+  % Do the redefinitions.
+  \definedummies
+  \otherbackslash
+}
+
+% \definedummyword defines \#1 as \string\#1\space, thus effectively
+% preventing its expansion.  This is used only for control words,
+% not control letters, because the \space would be incorrect for
+% control characters, but is needed to separate the control word
+% from whatever follows.
+%
+% These can be used both for control words that take an argument and
+% those that do not.  If it is followed by {arg} in the input, then
+% that will dutifully get written to the index (or wherever).
+%
+% For control letters, we have \definedummyletter, which omits the
+% space.
+%
+\def\definedummyword  #1{\def#1{\string#1\space}}%
+\def\definedummyletter#1{\def#1{\string#1}}%
+\let\definedummyaccent\definedummyletter
+
+% Called from \atdummies to prevent the expansion of commands.
+%
+\def\definedummies{%
+  %
+  \let\commondummyword\definedummyword
+  \let\commondummyletter\definedummyletter
+  \let\commondummyaccent\definedummyaccent
+  \commondummiesnofonts
+  %
+  \definedummyletter\_%
+  \definedummyletter\-%
+  %
+  % Non-English letters.
+  \definedummyword\AA
+  \definedummyword\AE
+  \definedummyword\DH
+  \definedummyword\L
+  \definedummyword\O
+  \definedummyword\OE
+  \definedummyword\TH
+  \definedummyword\aa
+  \definedummyword\ae
+  \definedummyword\dh
+  \definedummyword\exclamdown
+  \definedummyword\l
+  \definedummyword\o
+  \definedummyword\oe
+  \definedummyword\ordf
+  \definedummyword\ordm
+  \definedummyword\questiondown
+  \definedummyword\ss
+  \definedummyword\th
+  %
+  % Although these internal commands shouldn't show up, sometimes they do.
+  \definedummyword\bf
+  \definedummyword\gtr
+  \definedummyword\hat
+  \definedummyword\less
+  \definedummyword\sf
+  \definedummyword\sl
+  \definedummyword\tclose
+  \definedummyword\tt
+  %
+  \definedummyword\LaTeX
+  \definedummyword\TeX
+  %
+  % Assorted special characters.
+  \definedummyword\ampchar
+  \definedummyword\atchar
+  \definedummyword\arrow
+  \definedummyword\backslashchar
+  \definedummyword\bullet
+  \definedummyword\comma
+  \definedummyword\copyright
+  \definedummyword\registeredsymbol
+  \definedummyword\dots
+  \definedummyword\enddots
+  \definedummyword\entrybreak
+  \definedummyword\equiv
+  \definedummyword\error
+  \definedummyword\euro
+  \definedummyword\expansion
+  \definedummyword\geq
+  \definedummyword\guillemetleft
+  \definedummyword\guillemetright
+  \definedummyword\guilsinglleft
+  \definedummyword\guilsinglright
+  \definedummyword\lbracechar
+  \definedummyword\leq
+  \definedummyword\mathopsup
+  \definedummyword\minus
+  \definedummyword\ogonek
+  \definedummyword\pounds
+  \definedummyword\point
+  \definedummyword\print
+  \definedummyword\quotedblbase
+  \definedummyword\quotedblleft
+  \definedummyword\quotedblright
+  \definedummyword\quoteleft
+  \definedummyword\quoteright
+  \definedummyword\quotesinglbase
+  \definedummyword\rbracechar
+  \definedummyword\result
+  \definedummyword\sub
+  \definedummyword\sup
+  \definedummyword\textdegree
+  %
+  \definedummyword\subentry
+  %
+  % We want to disable all macros so that they are not expanded by \write.
+  \macrolist
+  \let\value\dummyvalue
+  %
+  \normalturnoffactive
+}
+
+% \commondummiesnofonts: common to \definedummies and \indexnofonts.
+% Define \commondummyletter, \commondummyaccent and \commondummyword before
+% using.  Used for accents, font commands, and various control letters.
+%
+\def\commondummiesnofonts{%
+  % Control letters and accents.
+  \commondummyletter\!%
+  \commondummyaccent\"%
+  \commondummyaccent\'%
+  \commondummyletter\*%
+  \commondummyaccent\,%
+  \commondummyletter\.%
+  \commondummyletter\/%
+  \commondummyletter\:%
+  \commondummyaccent\=%
+  \commondummyletter\?%
+  \commondummyaccent\^%
+  \commondummyaccent\`%
+  \commondummyaccent\~%
+  \commondummyword\u
+  \commondummyword\v
+  \commondummyword\H
+  \commondummyword\dotaccent
+  \commondummyword\ogonek
+  \commondummyword\ringaccent
+  \commondummyword\tieaccent
+  \commondummyword\ubaraccent
+  \commondummyword\udotaccent
+  \commondummyword\dotless
+  %
+  % Texinfo font commands.
+  \commondummyword\b
+  \commondummyword\i
+  \commondummyword\r
+  \commondummyword\sansserif
+  \commondummyword\sc
+  \commondummyword\slanted
+  \commondummyword\t
+  %
+  % Commands that take arguments.
+  \commondummyword\abbr
+  \commondummyword\acronym
+  \commondummyword\anchor
+  \commondummyword\cite
+  \commondummyword\code
+  \commondummyword\command
+  \commondummyword\dfn
+  \commondummyword\dmn
+  \commondummyword\email
+  \commondummyword\emph
+  \commondummyword\env
+  \commondummyword\file
+  \commondummyword\image
+  \commondummyword\indicateurl
+  \commondummyword\inforef
+  \commondummyword\kbd
+  \commondummyword\key
+  \commondummyword\math
+  \commondummyword\option
+  \commondummyword\pxref
+  \commondummyword\ref
+  \commondummyword\samp
+  \commondummyword\strong
+  \commondummyword\tie
+  \commondummyword\U
+  \commondummyword\uref
+  \commondummyword\url
+  \commondummyword\var
+  \commondummyword\verb
+  \commondummyword\w
+  \commondummyword\xref
+}
+
+\let\indexlbrace\relax
+\let\indexrbrace\relax
+\let\indexatchar\relax
+\let\indexbackslash\relax
+
+{\catcode`\@=0
+\catcode`\\=13
+  @gdef@backslashdisappear{@def\{}}
+}
+
+{
+\catcode`\<=13
+\catcode`\-=13
+\catcode`\`=13
+  \gdef\indexnonalnumdisappear{%
+    \expandafter\ifx\csname SETtxiindexlquoteignore\endcsname\relax\else
+      % @set txiindexlquoteignore makes us ignore left quotes in the sort term.
+      % (Introduced for FSFS 2nd ed.)
+      \let`=\empty
+    \fi
+    %
+    \expandafter\ifx\csname SETtxiindexbackslashignore\endcsname\relax\else
+      \backslashdisappear
+    \fi
+    %
+    \expandafter\ifx\csname SETtxiindexhyphenignore\endcsname\relax\else
+      \def-{}%
+    \fi
+    \expandafter\ifx\csname SETtxiindexlessthanignore\endcsname\relax\else
+      \def<{}%
+    \fi
+    \expandafter\ifx\csname SETtxiindexatsignignore\endcsname\relax\else
+      \def\@{}%
+    \fi
+  }
+
+  \gdef\indexnonalnumreappear{%
+    \let-\normaldash
+    \let<\normalless
+  }
+}
+
+
+% \indexnofonts is used when outputting the strings to sort the index
+% by, and when constructing control sequence names.  It eliminates all
+% control sequences and just writes whatever the best ASCII sort string
+% would be for a given command (usually its argument).
+%
+\def\indexnofonts{%
+  % Accent commands should become @asis.
+  \def\commondummyaccent##1{\let##1\asis}%
+  % We can just ignore other control letters.
+  \def\commondummyletter##1{\let##1\empty}%
+  % All control words become @asis by default; overrides below.
+  \let\commondummyword\commondummyaccent
+  \commondummiesnofonts
+  %
+  % Don't no-op \tt, since it isn't a user-level command
+  % and is used in the definitions of the active chars like <, >, |, etc.
+  % Likewise with the other plain tex font commands.
+  %\let\tt=\asis
+  %
+  \def\ { }%
+  \def\@{@}%
+  \def\_{\normalunderscore}%
+  \def\-{}% @- shouldn't affect sorting
+  %
+  \uccode`\1=`\{ \uppercase{\def\{{1}}%
+  \uccode`\1=`\} \uppercase{\def\}{1}}%
+  \let\lbracechar\{%
+  \let\rbracechar\}%
+  %
+  %
+  \let\do\indexnofontsdef
+  %
+  % Non-English letters.
+  \do\AA{AA}%
+  \do\AE{AE}%
+  \do\DH{DZZ}%
+  \do\L{L}%
+  \do\OE{OE}%
+  \do\O{O}%
+  \do\TH{TH}%
+  \do\aa{aa}%
+  \do\ae{ae}%
+  \do\dh{dzz}%
+  \do\exclamdown{!}%
+  \do\l{l}%
+  \do\oe{oe}%
+  \do\ordf{a}%
+  \do\ordm{o}%
+  \do\o{o}%
+  \do\questiondown{?}%
+  \do\ss{ss}%
+  \do\th{th}%
+  %
+  \do\LaTeX{LaTeX}%
+  \do\TeX{TeX}%
+  %
+  % Assorted special characters.
+  \do\atchar{@}%
+  \do\arrow{->}%
+  \do\bullet{bullet}%
+  \do\comma{,}%
+  \do\copyright{copyright}%
+  \do\dots{...}%
+  \do\enddots{...}%
+  \do\equiv{==}%
+  \do\error{error}%
+  \do\euro{euro}%
+  \do\expansion{==>}%
+  \do\geq{>=}%
+  \do\guillemetleft{<<}%
+  \do\guillemetright{>>}%
+  \do\guilsinglleft{<}%
+  \do\guilsinglright{>}%
+  \do\leq{<=}%
+  \do\lbracechar{\{}%
+  \do\minus{-}%
+  \do\point{.}%
+  \do\pounds{pounds}%
+  \do\print{-|}%
+  \do\quotedblbase{"}%
+  \do\quotedblleft{"}%
+  \do\quotedblright{"}%
+  \do\quoteleft{`}%
+  \do\quoteright{'}%
+  \do\quotesinglbase{,}%
+  \do\rbracechar{\}}%
+  \do\registeredsymbol{R}%
+  \do\result{=>}%
+  \do\textdegree{o}%
+  %
+  % We need to get rid of all macros, leaving only the arguments (if present).
+  % Of course this is not nearly correct, but it is the best we can do for now.
+  % makeinfo does not expand macros in the argument to @deffn, which ends up
+  % writing an index entry, and texindex isn't prepared for an index sort entry
+  % that starts with \.
+  %
+  % Since macro invocations are followed by braces, we can just redefine them
+  % to take a single TeX argument.  The case of a macro invocation that
+  % goes to end-of-line is not handled.
+  %
+  \macrolist
+  \let\value\indexnofontsvalue
+}
+
+% Give the control sequence a definition that removes the {} that follows
+% its use, e.g. @AA{} -> AA
+\def\indexnofontsdef#1#2{\def#1##1{#2}}%
+
+
+
+
+% #1 is the index name, #2 is the entry text.
+\def\doind#1#2{%
+  \iflinks
+  {%
+    %
+    \requireopenindexfile{#1}%
+    \edef\writeto{\csname#1indfile\endcsname}%
+    %
+    \def\indextext{#2}%
+    \safewhatsit\doindwrite
+  }%
+  \fi
+}
+
+% Same as \doind, but for code indices
+\def\docind#1#2{%
+  \iflinks
+  {%
+    %
+    \requireopenindexfile{#1}%
+    \edef\writeto{\csname#1indfile\endcsname}%
+    %
+    \def\indextext{#2}%
+    \safewhatsit\docindwrite
+  }%
+  \fi
+}
+
+% Check if an index file has been opened, and if not, open it.
+\def\requireopenindexfile#1{%
+\ifnum\csname #1indfile\endcsname=0
+  \expandafter\newwrite \csname#1indfile\endcsname
+  \edef\suffix{#1}%
+  % A .fls suffix would conflict with the file extension for the output
+  % of -recorder, so use .f1s instead.
+  \ifx\suffix\indexisfl\def\suffix{f1}\fi
+  % Open the file
+  \immediate\openout\csname#1indfile\endcsname \jobname.\suffix
+  % Using \immediate above here prevents an object entering into the current
+  % box, which could confound checks such as those in \safewhatsit for
+  % preceding skips.
+  \typeout{Writing index file \jobname.\suffix}%
+\fi}
+\def\indexisfl{fl}
+
+% Definition for writing index entry sort key.
+{
+\catcode`\-=13
+\gdef\indexwritesortas{%
+  \begingroup
+  \indexnonalnumreappear
+  \indexwritesortasxxx}
+\gdef\indexwritesortasxxx#1{%
+  \xdef\indexsortkey{#1}\endgroup}
+}
+
+\def\indexwriteseealso#1{
+  \gdef\pagenumbertext{\string\seealso{#1}}%
+}
+\def\indexwriteseeentry#1{
+  \gdef\pagenumbertext{\string\seeentry{#1}}%
+}
+
+% The default definitions
+\def\sortas#1{}%
+\def\seealso#1{\i{\putwordSeeAlso}\ #1}% for sorted index file only
+\def\putwordSeeAlso{See also}
+\def\seeentry#1{\i{\putwordSee}\ #1}% for sorted index file only
+
+
+% Given index entry text like "aaa @subentry bbb @sortas{ZZZ}":
+%   * Set \bracedtext to "{aaa}{bbb}"
+%   * Set \fullindexsortkey to "aaa @subentry ZZZ"
+%   * If @seealso occurs, set \pagenumbertext
+%
+\def\splitindexentry#1{%
+  \gdef\fullindexsortkey{}%
+  \xdef\bracedtext{}%
+  \def\sep{}%
+  \def\seealso##1{}%
+  \def\seeentry##1{}%
+  \expandafter\doindexsegment#1\subentry\finish\subentry
+}
+
+% append the results from the next segment
+\def\doindexsegment#1\subentry{%
+  \def\segment{#1}%
+  \ifx\segment\isfinish
+  \else
+    %
+    % Fully expand the segment, throwing away any @sortas directives, and
+    % trim spaces.
+    \edef\trimmed{\segment}%
+    \edef\trimmed{\expandafter\eatspaces\expandafter{\trimmed}}%
+    \ifincodeindex
+      \edef\trimmed{\noexpand\code{\trimmed}}%
+    \fi
+    %
+    \xdef\bracedtext{\bracedtext{\trimmed}}%
+    %
+    % Get the string to sort by.  Process the segment with all
+    % font commands turned off.
+    \bgroup
+      \let\sortas\indexwritesortas
+      \let\seealso\indexwriteseealso
+      \let\seeentry\indexwriteseeentry
+      \indexnofonts
+      % The braces around the commands are recognized by texindex.
+      \def\lbracechar{{\string\indexlbrace}}%
+      \def\rbracechar{{\string\indexrbrace}}%
+      \let\{=\lbracechar
+      \let\}=\rbracechar
+      \def\@{{\string\indexatchar}}%
+      \def\atchar##1{\@}%
+      \def\backslashchar{{\string\indexbackslash}}%
+      \uccode`\~=`\\ \uppercase{\let~\backslashchar}%
+      %
+      \let\indexsortkey\empty
+      \global\let\pagenumbertext\empty
+      % Execute the segment and throw away the typeset output.  This executes
+      % any @sortas or @seealso commands in this segment.
+      \setbox\dummybox = \hbox{\segment}%
+      \ifx\indexsortkey\empty{%
+        \indexnonalnumdisappear
+        \xdef\trimmed{\segment}%
+        \xdef\trimmed{\expandafter\eatspaces\expandafter{\trimmed}}%
+        \xdef\indexsortkey{\trimmed}%
+        \ifx\indexsortkey\empty\xdef\indexsortkey{ }\fi
+      }\fi
+      %
+      % Append to \fullindexsortkey.
+      \edef\tmp{\gdef\noexpand\fullindexsortkey{%
+                  \fullindexsortkey\sep\indexsortkey}}%
+      \tmp
+    \egroup
+    \def\sep{\subentry}%
+    %
+    \expandafter\doindexsegment
+  \fi
+}
+\def\isfinish{\finish}%
+\newbox\dummybox % used above
+
+\let\subentry\relax
+
+% Use \ instead of @ in index files.  To support old texi2dvi and texindex.
+% This works without changing the escape character used in the toc or aux
+% files because the index entries are fully expanded here, and \string uses
+% the current value of \escapechar.
+\def\escapeisbackslash{\escapechar=`\\}
+
+% Use \ in index files by default.  texi2dvi didn't support @ as the escape
+% character (as it checked for "\entry" in the files, and not "@entry").  When
+% the new version of texi2dvi has had a chance to become more prevalent, then
+% the escape character can change back to @ again.  This should be an easy
+% change to make now because both @ and \ are only used as escape characters in
+% index files, never standing for themselves.
+%
+\set txiindexescapeisbackslash
+
+% Write the entry in \indextext to the index file.
+%
+
+\newif\ifincodeindex
+\def\doindwrite{\incodeindexfalse\doindwritex}
+\def\docindwrite{\incodeindextrue\doindwritex}
+
+\def\doindwritex{%
+  \maybemarginindex
+  %
+  \atdummies
+  %
+  \expandafter\ifx\csname SETtxiindexescapeisbackslash\endcsname\relax\else
+    \escapeisbackslash
+  \fi
+  %
+  % For texindex which always views { and } as separators.
+  \def\{{\lbracechar{}}%
+  \def\}{\rbracechar{}}%
+  \uccode`\~=`\\ \uppercase{\def~{\backslashchar{}}}%
+  %
+  % Split the entry into primary entry and any subentries, and get the index
+  % sort key.
+  \splitindexentry\indextext
+  %
+  % Set up the complete index entry, with both the sort key and
+  % the original text, including any font commands.  We write
+  % three arguments to \entry to the .?? file (four in the
+  % subentry case), texindex reduces to two when writing the .??s
+  % sorted result.
+  %
+  \edef\temp{%
+    \write\writeto{%
+      \string\entry{\fullindexsortkey}%
+        {\ifx\pagenumbertext\empty\noexpand\folio\else\pagenumbertext\fi}%
+        \bracedtext}%
+  }%
+  \temp
+}
+
+% Put the index entry in the margin if desired (undocumented).
+\def\maybemarginindex{%
+  \ifx\SETmarginindex\relax\else
+    \insert\margin{\hbox{\vrule height8pt depth3pt width0pt \relax\indextext}}%
+  \fi
+}
+\let\SETmarginindex=\relax
+
+
+% Take care of unwanted page breaks/skips around a whatsit:
+%
+% If a skip is the last thing on the list now, preserve it
+% by backing up by \lastskip, doing the \write, then inserting
+% the skip again.  Otherwise, the whatsit generated by the
+% \write or \pdfdest will make \lastskip zero.  The result is that
+% sequences like this:
+% @end defun
+% @tindex whatever
+% @defun ...
+% will have extra space inserted, because the \medbreak in the
+% start of the @defun won't see the skip inserted by the @end of
+% the previous defun.
+%
+% But don't do any of this if we're not in vertical mode.  We
+% don't want to do a \vskip and prematurely end a paragraph.
+%
+% Avoid page breaks due to these extra skips, too.
+%
+% But wait, there is a catch there:
+% We'll have to check whether \lastskip is zero skip.  \ifdim is not
+% sufficient for this purpose, as it ignores stretch and shrink parts
+% of the skip.  The only way seems to be to check the textual
+% representation of the skip.
+%
+% The following is almost like \def\zeroskipmacro{0.0pt} except that
+% the ``p'' and ``t'' characters have catcode \other, not 11 (letter).
+%
+\edef\zeroskipmacro{\expandafter\the\csname z@skip\endcsname}
+%
+\newskip\whatsitskip
+\newcount\whatsitpenalty
+%
+% ..., ready, GO:
+%
+\def\safewhatsit#1{\ifhmode
+  #1%
+ \else
+  % \lastskip and \lastpenalty cannot both be nonzero simultaneously.
+  \whatsitskip = \lastskip
+  \edef\lastskipmacro{\the\lastskip}%
+  \whatsitpenalty = \lastpenalty
+  %
+  % If \lastskip is nonzero, that means the last item was a
+  % skip.  And since a skip is discardable, that means this
+  % -\whatsitskip glue we're inserting is preceded by a
+  % non-discardable item, therefore it is not a potential
+  % breakpoint, therefore no \nobreak needed.
+  \ifx\lastskipmacro\zeroskipmacro
+  \else
+    \vskip-\whatsitskip
+  \fi
+  %
+  #1%
+  %
+  \ifx\lastskipmacro\zeroskipmacro
+    % If \lastskip was zero, perhaps the last item was a penalty, and
+    % perhaps it was >=10000, e.g., a \nobreak.  In that case, we want
+    % to re-insert the same penalty (values >10000 are used for various
+    % signals); since we just inserted a non-discardable item, any
+    % following glue (such as a \parskip) would be a breakpoint.  For example:
+    %   @deffn deffn-whatever
+    %   @vindex index-whatever
+    %   Description.
+    % would allow a break between the index-whatever whatsit
+    % and the "Description." paragraph.
+    \ifnum\whatsitpenalty>9999 \penalty\whatsitpenalty \fi
+  \else
+    % On the other hand, if we had a nonzero \lastskip,
+    % this make-up glue would be preceded by a non-discardable item
+    % (the whatsit from the \write), so we must insert a \nobreak.
+    \nobreak\vskip\whatsitskip
+  \fi
+\fi}
+
+% The index entry written in the file actually looks like
+%  \entry {sortstring}{page}{topic}
+% or
+%  \entry {sortstring}{page}{topic}{subtopic}
+% The texindex program reads in these files and writes files
+% containing these kinds of lines:
+%  \initial {c}
+%     before the first topic whose initial is c
+%  \entry {topic}{pagelist}
+%     for a topic that is used without subtopics
+%  \primary {topic}
+%  \entry {topic}{}
+%     for the beginning of a topic that is used with subtopics
+%  \secondary {subtopic}{pagelist}
+%     for each subtopic.
+%  \secondary {subtopic}{}
+%     for a subtopic with sub-subtopics
+%  \tertiary {subtopic}{subsubtopic}{pagelist}
+%     for each sub-subtopic.
+
+% Define the user-accessible indexing commands
+% @findex, @vindex, @kindex, @cindex.
+
+\def\findex {\fnindex}
+\def\kindex {\kyindex}
+\def\cindex {\cpindex}
+\def\vindex {\vrindex}
+\def\tindex {\tpindex}
+\def\pindex {\pgindex}
+
+% Define the macros used in formatting output of the sorted index material.
+
+% @printindex causes a particular index (the ??s file) to get printed.
+% It does not print any chapter heading (usually an @unnumbered).
+%
+\parseargdef\printindex{\begingroup
+  \dobreak \chapheadingskip{10000}%
+  %
+  \smallfonts \rm
+  \tolerance = 9500
+  \plainfrenchspacing
+  \everypar = {}% don't want the \kern\-parindent from indentation suppression.
+  %
+  % See comment in \requireopenindexfile.
+  \def\indexname{#1}\ifx\indexname\indexisfl\def\indexname{f1}\fi
+  %
+  % See if the index file exists and is nonempty.
+  \openin 1 \jobname.\indexname s
+  \ifeof 1
+    % \enddoublecolumns gets confused if there is no text in the index,
+    % and it loses the chapter title and the aux file entries for the
+    % index.  The easiest way to prevent this problem is to make sure
+    % there is some text.
+    \putwordIndexNonexistent
+    \typeout{No file \jobname.\indexname s.}%
+  \else
+    % If the index file exists but is empty, then \openin leaves \ifeof
+    % false.  We have to make TeX try to read something from the file, so
+    % it can discover if there is anything in it.
+    \read 1 to \thisline
+    \ifeof 1
+      \putwordIndexIsEmpty
+    \else
+      \expandafter\printindexzz\thisline\relax\relax\finish%
+    \fi
+  \fi
+  \closein 1
+\endgroup}
+
+% If the index file starts with a backslash, forgo reading the index
+% file altogether.  If somebody upgrades texinfo.tex they may still have
+% old index files using \ as the escape character.  Reading this would
+% at best lead to typesetting garbage, at worst a TeX syntax error.
+\def\printindexzz#1#2\finish{%
+  \expandafter\ifx\csname SETtxiindexescapeisbackslash\endcsname\relax
+    \uccode`\~=`\\ \uppercase{\if\noexpand~}\noexpand#1
+      \expandafter\ifx\csname SETtxiskipindexfileswithbackslash\endcsname\relax
+\errmessage{%
+ERROR: A sorted index file in an obsolete format was skipped.
+To fix this problem, please upgrade your version of 'texi2dvi'
+or 'texi2pdf' to that at <https://ftp.gnu.org/gnu/texinfo>.
+If you are using an old version of 'texindex' (part of the Texinfo
+distribution), you may also need to upgrade to a newer version (at least 6.0).
+You may be able to typeset the index if you run
+'texindex \jobname.\indexname' yourself.
+You could also try setting the 'txiindexescapeisbackslash' flag by
+running a command like
+'texi2dvi -t "@set txiindexescapeisbackslash" \jobname.texi'.  If you do
+this, Texinfo will try to use index files in the old format.
+If you continue to have problems, deleting the index files and starting again
+might help (with 'rm \jobname.?? \jobname.??s')%
+}%
+      \else
+        (Skipped sorted index file in obsolete format)
+      \fi
+    \else
+      \begindoublecolumns
+      \input \jobname.\indexname s
+      \enddoublecolumns
+    \fi
+  \else
+    \begindoublecolumns
+    \catcode`\\=0\relax
+    %
+    % Make @ an escape character to give macros a chance to work.  This
+    % should work because we (hopefully) don't otherwise use @ in index files.
+    %\catcode`\@=12\relax
+    \catcode`\@=0\relax
+    \input \jobname.\indexname s
+    \enddoublecolumns
+  \fi
+}
+
+% These macros are used by the sorted index file itself.
+% Change them to control the appearance of the index.
+
+{\catcode`\/=13 \catcode`\-=13 \catcode`\^=13 \catcode`\~=13 \catcode`\_=13
+\catcode`\|=13 \catcode`\<=13 \catcode`\>=13 \catcode`\+=13 \catcode`\"=13
+\catcode`\$=3
+\gdef\initialglyphs{%
+  % special control sequences used in the index sort key
+  \let\indexlbrace\{%
+  \let\indexrbrace\}%
+  \let\indexatchar\@%
+  \def\indexbackslash{\math{\backslash}}%
+  %
+  % Some changes for non-alphabetic characters.  Using the glyphs from the
+  % math fonts looks more consistent than the typewriter font used elsewhere
+  % for these characters.
+  \uccode`\~=`\\ \uppercase{\def~{\math{\backslash}}}
+  %
+  % In case @\ is used for backslash
+  \uppercase{\let\\=~}
+  % Can't get bold backslash so don't use bold forward slash
+  \catcode`\/=13
+  \def/{{\secrmnotbold \normalslash}}%
+  \def-{{\normaldash\normaldash}}% en dash `--'
+  \def^{{\chapbf \normalcaret}}%
+  \def~{{\chapbf \normaltilde}}%
+  \def\_{%
+     \leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }%
+  \def|{$\vert$}%
+  \def<{$\less$}%
+  \def>{$\gtr$}%
+  \def+{$\normalplus$}%
+}}
+
+\def\initial{%
+  \bgroup
+  \initialglyphs
+  \initialx
+}
+
+\def\initialx#1{%
+  % Remove any glue we may have, we'll be inserting our own.
+  \removelastskip
+  %
+  % We like breaks before the index initials, so insert a bonus.
+  % The glue before the bonus allows a little bit of space at the
+  % bottom of a column to reduce an increase in inter-line spacing.
+  \nobreak
+  \vskip 0pt plus 5\baselineskip
+  \penalty -300
+  \vskip 0pt plus -5\baselineskip
+  %
+  % Typeset the initial.  Making this add up to a whole number of
+  % baselineskips increases the chance of the dots lining up from column
+  % to column.  It still won't often be perfect, because of the stretch
+  % we need before each entry, but it's better.
+  %
+  % No shrink because it confuses \balancecolumns.
+  \vskip 1.67\baselineskip plus 1\baselineskip
+  \leftline{\secfonts \kern-0.05em \secbf #1}%
+  % \secfonts is inside the argument of \leftline so that the change of
+  % \baselineskip will not affect any glue inserted before the vbox that
+  % \leftline creates.
+  % Do our best not to break after the initial.
+  \nobreak
+  \vskip .33\baselineskip plus .1\baselineskip
+  \egroup % \initialglyphs
+}
+
+\newdimen\entryrightmargin
+\entryrightmargin=0pt
+
+% \entry typesets a paragraph consisting of the text (#1), dot leaders, and
+% then page number (#2) flushed to the right margin.  It is used for index
+% and table of contents entries.  The paragraph is indented by \leftskip.
+%
+\def\entry{%
+  \begingroup
+    %
+    % Start a new paragraph if necessary, so our assignments below can't
+    % affect previous text.
+    \par
+    %
+    % No extra space above this paragraph.
+    \parskip = 0in
+    %
+    % When reading the text of entry, convert explicit line breaks
+    % from @* into spaces.  The user might give these in long section
+    % titles, for instance.
+    \def\*{\unskip\space\ignorespaces}%
+    \def\entrybreak{\hfil\break}% An undocumented command
+    %
+    % Swallow the left brace of the text (first parameter):
+    \afterassignment\doentry
+    \let\temp =
+}
+\def\entrybreak{\unskip\space\ignorespaces}%
+\def\doentry{%
+    % Save the text of the entry
+    \global\setbox\boxA=\hbox\bgroup
+    \bgroup % Instead of the swallowed brace.
+      \noindent
+      \aftergroup\finishentry
+      % And now comes the text of the entry.
+      % Not absorbing as a macro argument reduces the chance of problems
+      % with catcodes occurring.
+}
+{\catcode`\@=11
+\gdef\finishentry#1{%
+    \egroup % end box A
+    \dimen@ = \wd\boxA % Length of text of entry
+    \global\setbox\boxA=\hbox\bgroup
+      \unhbox\boxA
+      % #1 is the page number.
+      %
+      % Get the width of the page numbers, and only use
+      % leaders if they are present.
+      \global\setbox\boxB = \hbox{#1}%
+      \ifdim\wd\boxB = 0pt
+        \null\nobreak\hfill\ %
+      \else
+        %
+        \null\nobreak\indexdotfill % Have leaders before the page number.
+        %
+        \ifpdforxetex
+          \pdfgettoks#1.%
+          \hskip\skip\thinshrinkable\the\toksA
+        \else
+          \hskip\skip\thinshrinkable #1%
+        \fi
+      \fi
+    \egroup % end \boxA
+    \ifdim\wd\boxB = 0pt
+      \noindent\unhbox\boxA\par
+      \nobreak
+    \else\bgroup
+      % We want the text of the entries to be aligned to the left, and the
+      % page numbers to be aligned to the right.
+      %
+      \parindent = 0pt
+      \advance\leftskip by 0pt plus 1fil
+      \advance\leftskip by 0pt plus -1fill
+      \rightskip = 0pt plus -1fil
+      \advance\rightskip by 0pt plus 1fill
+      % Cause last line, which could consist of page numbers on their own
+      % if the list of page numbers is long, to be aligned to the right.
+      \parfillskip=0pt plus -1fill
+      %
+      \advance\rightskip by \entryrightmargin
+      % Determine how far we can stretch into the margin.
+      % This allows, e.g., "Appendix H  GNU Free Documentation License" to
+      % fit on one line in @letterpaper format.
+      \ifdim\entryrightmargin>2.1em
+        \dimen@i=2.1em
+      \else
+        \dimen@i=0em
+      \fi
+      \advance \parfillskip by 0pt minus 1\dimen@i
+      %
+      \dimen@ii = \hsize
+      \advance\dimen@ii by -1\leftskip
+      \advance\dimen@ii by -1\entryrightmargin
+      \advance\dimen@ii by 1\dimen@i
+      \ifdim\wd\boxA > \dimen@ii % If the entry doesn't fit in one line
+      \ifdim\dimen@ > 0.8\dimen@ii   % due to long index text
+        % Try to split the text roughly evenly.  \dimen@ will be the length of
+        % the first line.
+        \dimen@ = 0.7\dimen@
+        \dimen@ii = \hsize
+        \ifnum\dimen@>\dimen@ii
+          % If the entry is too long (for example, if it needs more than
+          % two lines), use all the space in the first line.
+          \dimen@ = \dimen@ii
+        \fi
+        \advance\leftskip by 0pt plus 1fill % ragged right
+        \advance \dimen@ by 1\rightskip
+        \parshape = 2 0pt \dimen@ 0em \dimen@ii
+        % Ideally we'd add a finite glue at the end of the first line only,
+        % instead of using \parshape with explicit line lengths, but TeX
+        % doesn't seem to provide a way to do such a thing.
+        %
+        % Indent all lines but the first one.
+        \advance\leftskip by 1em
+        \advance\parindent by -1em
+      \fi\fi
+      \indent % start paragraph
+      \unhbox\boxA
+      %
+      % Do not prefer a separate line ending with a hyphen to fewer lines.
+      \finalhyphendemerits = 0
+      %
+      % Word spacing - no stretch
+      \spaceskip=\fontdimen2\font minus \fontdimen4\font
+      %
+      \linepenalty=1000  % Discourage line breaks.
+      \hyphenpenalty=5000  % Discourage hyphenation.
+      %
+      \par % format the paragraph
+    \egroup % The \vbox
+    \fi
+  \endgroup
+}}
+
+\newskip\thinshrinkable
+\skip\thinshrinkable=.15em minus .15em
+
+% Like plain.tex's \dotfill, except uses up at least 1 em.
+% The filll stretch here overpowers both the fil and fill stretch to push
+% the page number to the right.
+\def\indexdotfill{\cleaders
+  \hbox{$\mathsurround=0pt \mkern1.5mu.\mkern1.5mu$}\hskip 1em plus 1filll}
+
+
+\def\primary #1{\line{#1\hfil}}
+
+\def\secondary{\indententry{0.5cm}}
+\def\tertiary{\indententry{1cm}}
+
+\def\indententry#1#2#3{%
+  \bgroup
+  \leftskip=#1
+  \entry{#2}{#3}%
+  \egroup
+}
+
+% Define two-column mode, which we use to typeset indexes.
+% Adapted from the TeXbook, page 416, which is to say,
+% the manmac.tex format used to print the TeXbook itself.
+\catcode`\@=11  % private names
+
+\newbox\partialpage
+\newdimen\doublecolumnhsize
+
+\def\begindoublecolumns{\begingroup % ended by \enddoublecolumns
+  % If not much space left on page, start a new page.
+  \ifdim\pagetotal>0.8\vsize\vfill\eject\fi
+  %
+  % Grab any single-column material above us.
+  \output = {%
+    \savetopmark
+    %
+    \global\setbox\partialpage = \vbox{%
+      % Unvbox the main output page.
+      \unvbox\PAGE
+      \kern-\topskip \kern\baselineskip
+    }%
+  }%
+  \eject % run that output routine to set \partialpage
+  %
+  % Use the double-column output routine for subsequent pages.
+  \output = {\doublecolumnout}%
+  %
+  % Change the page size parameters.  We could do this once outside this
+  % routine, in each of @smallbook, @afourpaper, and the default 8.5x11
+  % format, but then we repeat the same computation.  Repeating a couple
+  % of assignments once per index is clearly meaningless for the
+  % execution time, so we may as well do it in one place.
+  %
+  % First we halve the line length, less a little for the gutter between
+  % the columns.  We compute the gutter based on the line length, so it
+  % changes automatically with the paper format.  The magic constant
+  % below is chosen so that the gutter has the same value (well, +-<1pt)
+  % as it did when we hard-coded it.
+  %
+  % We put the result in a separate register, \doublecolumhsize, so we
+  % can restore it in \pagesofar, after \hsize itself has (potentially)
+  % been clobbered.
+  %
+  \doublecolumnhsize = \hsize
+    \advance\doublecolumnhsize by -.04154\hsize
+    \divide\doublecolumnhsize by 2
+  \hsize = \doublecolumnhsize
+  %
+  % Get the available space for the double columns -- the normal
+  % (undoubled) page height minus any material left over from the
+  % previous page.
+  \advance\vsize by -\ht\partialpage
+  \vsize = 2\vsize
+  %
+  % For the benefit of balancing columns
+  \advance\baselineskip by 0pt plus 0.5pt
+}
+
+% The double-column output routine for all double-column pages except
+% the last, which is done by \balancecolumns.
+%
+\def\doublecolumnout{%
+  %
+  \savetopmark
+  \splittopskip=\topskip \splitmaxdepth=\maxdepth
+  \dimen@ = \vsize
+  \divide\dimen@ by 2
+  %
+  % box0 will be the left-hand column, box2 the right.
+  \setbox0=\vsplit\PAGE to\dimen@ \setbox2=\vsplit\PAGE to\dimen@
+  \global\advance\vsize by 2\ht\partialpage
+  \onepageout\pagesofar % empty except for the first time we are called
+  \unvbox\PAGE
+  \penalty\outputpenalty
+}
+%
+% Re-output the contents of the output page -- any previous material,
+% followed by the two boxes we just split, in box0 and box2.
+\def\pagesofar{%
+  \unvbox\partialpage
+  %
+  \hsize = \doublecolumnhsize
+  \wd0=\hsize \wd2=\hsize
+  \hbox to\txipagewidth{\box0\hfil\box2}%
+}
+
+
+% Finished with double columns.
+\def\enddoublecolumns{%
+  % The following penalty ensures that the page builder is exercised
+  % _before_ we change the output routine.  This is necessary in the
+  % following situation:
+  %
+  % The last section of the index consists only of a single entry.
+  % Before this section, \pagetotal is less than \pagegoal, so no
+  % break occurs before the last section starts.  However, the last
+  % section, consisting of \initial and the single \entry, does not
+  % fit on the page and has to be broken off.  Without the following
+  % penalty the page builder will not be exercised until \eject
+  % below, and by that time we'll already have changed the output
+  % routine to the \balancecolumns version, so the next-to-last
+  % double-column page will be processed with \balancecolumns, which
+  % is wrong:  The two columns will go to the main vertical list, with
+  % the broken-off section in the recent contributions.  As soon as
+  % the output routine finishes, TeX starts reconsidering the page
+  % break.  The two columns and the broken-off section both fit on the
+  % page, because the two columns now take up only half of the page
+  % goal.  When TeX sees \eject from below which follows the final
+  % section, it invokes the new output routine that we've set after
+  % \balancecolumns below; \onepageout will try to fit the two columns
+  % and the final section into the vbox of \txipageheight (see
+  % \pagebody), causing an overfull box.
+  %
+  % Note that glue won't work here, because glue does not exercise the
+  % page builder, unlike penalties (see The TeXbook, pp. 280-281).
+  \penalty0
+  %
+  \output = {%
+    % Split the last of the double-column material.
+    \savetopmark
+    \balancecolumns
+  }%
+  \eject % call the \output just set
+  \ifdim\pagetotal=0pt
+    % Having called \balancecolumns once, we do not
+    % want to call it again.  Therefore, reset \output to its normal
+    % definition right away.
+    \global\output=\expandafter{\the\defaultoutput}
+    %
+    \endgroup % started in \begindoublecolumns
+    % Leave the double-column material on the current page, no automatic
+    % page break.
+    \box\balancedcolumns
+    %
+    % \pagegoal was set to the doubled \vsize above, since we restarted
+    % the current page.  We're now back to normal single-column
+    % typesetting, so reset \pagegoal to the normal \vsize.
+    \global\vsize = \txipageheight %
+    \pagegoal = \txipageheight %
+  \else
+    % We had some left-over material.  This might happen when \doublecolumnout
+    % is called in \balancecolumns.  Try again.
+    \expandafter\enddoublecolumns
+  \fi
+}
+\newbox\balancedcolumns
+\setbox\balancedcolumns=\vbox{shouldnt see this}%
+%
+% Only called for the last of the double column material.  \doublecolumnout
+% does the others.
+\def\balancecolumns{%
+  \setbox0 = \vbox{\unvbox\PAGE}% like \box255 but more efficient, see p.120.
+  \dimen@ = \ht0
+  \ifdim\dimen@<7\baselineskip
+    % Don't split a short final column in two.
+    \setbox2=\vbox{}%
+    \global\setbox\balancedcolumns=\vbox{\pagesofar}%
+  \else
+    % double the leading vertical space
+    \advance\dimen@ by \topskip
+    \advance\dimen@ by-\baselineskip
+    \divide\dimen@ by 2 % target to split to
+    \dimen@ii = \dimen@
+    \splittopskip = \topskip
+    % Loop until left column is at least as high as the right column.
+    {%
+      \vbadness = 10000
+      \loop
+        \global\setbox3 = \copy0
+        \global\setbox1 = \vsplit3 to \dimen@
+      \ifdim\ht1<\ht3
+        \global\advance\dimen@ by 1pt
+      \repeat
+    }%
+    % Now the left column is in box 1, and the right column in box 3.
+    %
+    % Check whether the left column has come out higher than the page itself.
+    % (Note that we have doubled \vsize for the double columns, so
+    % the actual height of the page is 0.5\vsize).
+    \ifdim2\ht1>\vsize
+      % It appears that we have been called upon to balance too much material.
+      % Output some of it with \doublecolumnout, leaving the rest on the page.
+      \setbox\PAGE=\box0
+      \doublecolumnout
+    \else
+      % Compare the heights of the two columns.
+      \ifdim4\ht1>5\ht3
+        % Column heights are too different, so don't make their bottoms
+        % flush with each other.
+        \setbox2=\vbox to \ht1 {\unvbox3\vfill}%
+        \setbox0=\vbox to \ht1 {\unvbox1\vfill}%
+      \else
+        % Make column bottoms flush with each other.
+        \setbox2=\vbox to\ht1{\unvbox3\unskip}%
+        \setbox0=\vbox to\ht1{\unvbox1\unskip}%
+      \fi
+      \global\setbox\balancedcolumns=\vbox{\pagesofar}%
+    \fi
+  \fi
+  %
+}
+\catcode`\@ = \other
+
+
+\message{sectioning,}
+% Chapters, sections, etc.
+
+% Let's start with @part.
+\outer\parseargdef\part{\partzzz{#1}}
+\def\partzzz#1{%
+  \chapoddpage
+  \null
+  \vskip.3\vsize  % move it down on the page a bit
+  \begingroup
+    \noindent \titlefonts\rm #1\par % the text
+    \let\lastnode=\empty      % no node to associate with
+    \writetocentry{part}{#1}{}% but put it in the toc
+    \headingsoff              % no headline or footline on the part page
+    % This outputs a mark at the end of the page that clears \thischapter
+    % and \thissection, as is done in \startcontents.
+    \let\pchapsepmacro\relax
+    \chapmacro{}{Yomitfromtoc}{}%
+    \chapoddpage
+  \endgroup
+}
+
+% \unnumberedno is an oxymoron.  But we count the unnumbered
+% sections so that we can refer to them unambiguously in the pdf
+% outlines by their "section number".  We avoid collisions with chapter
+% numbers by starting them at 10000.  (If a document ever has 10000
+% chapters, we're in trouble anyway, I'm sure.)
+\newcount\unnumberedno \unnumberedno = 10000
+\newcount\chapno
+\newcount\secno        \secno=0
+\newcount\subsecno     \subsecno=0
+\newcount\subsubsecno  \subsubsecno=0
+
+% This counter is funny since it counts through charcodes of letters A, B, ...
+\newcount\appendixno  \appendixno = `\@
+%
+% \def\appendixletter{\char\the\appendixno}
+% We do the following ugly conditional instead of the above simple
+% construct for the sake of pdftex, which needs the actual
+% letter in the expansion, not just typeset.
+%
+\def\appendixletter{%
+  \ifnum\appendixno=`A A%
+  \else\ifnum\appendixno=`B B%
+  \else\ifnum\appendixno=`C C%
+  \else\ifnum\appendixno=`D D%
+  \else\ifnum\appendixno=`E E%
+  \else\ifnum\appendixno=`F F%
+  \else\ifnum\appendixno=`G G%
+  \else\ifnum\appendixno=`H H%
+  \else\ifnum\appendixno=`I I%
+  \else\ifnum\appendixno=`J J%
+  \else\ifnum\appendixno=`K K%
+  \else\ifnum\appendixno=`L L%
+  \else\ifnum\appendixno=`M M%
+  \else\ifnum\appendixno=`N N%
+  \else\ifnum\appendixno=`O O%
+  \else\ifnum\appendixno=`P P%
+  \else\ifnum\appendixno=`Q Q%
+  \else\ifnum\appendixno=`R R%
+  \else\ifnum\appendixno=`S S%
+  \else\ifnum\appendixno=`T T%
+  \else\ifnum\appendixno=`U U%
+  \else\ifnum\appendixno=`V V%
+  \else\ifnum\appendixno=`W W%
+  \else\ifnum\appendixno=`X X%
+  \else\ifnum\appendixno=`Y Y%
+  \else\ifnum\appendixno=`Z Z%
+  % The \the is necessary, despite appearances, because \appendixletter is
+  % expanded while writing the .toc file.  \char\appendixno is not
+  % expandable, thus it is written literally, thus all appendixes come out
+  % with the same letter (or @) in the toc without it.
+  \else\char\the\appendixno
+  \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
+  \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi}
+
+% Each @chapter defines these (using marks) as the number+name, number
+% and name of the chapter.  Page headings and footings can use
+% these.  @section does likewise.
+\def\thischapter{}
+\def\thischapternum{}
+\def\thischaptername{}
+\def\thissection{}
+\def\thissectionnum{}
+\def\thissectionname{}
+
+\newcount\absseclevel % used to calculate proper heading level
+\newcount\secbase\secbase=0 % @raisesections/@lowersections modify this count
+
+% @raisesections: treat @section as chapter, @subsection as section, etc.
+\def\raisesections{\global\advance\secbase by -1}
+
+% @lowersections: treat @chapter as section, @section as subsection, etc.
+\def\lowersections{\global\advance\secbase by 1}
+
+% we only have subsub.
+\chardef\maxseclevel = 3
+%
+% A numbered section within an unnumbered changes to unnumbered too.
+% To achieve this, remember the "biggest" unnum. sec. we are currently in:
+\chardef\unnlevel = \maxseclevel
+%
+% Trace whether the current chapter is an appendix or not:
+% \chapheadtype is "N" or "A", unnumbered chapters are ignored.
+\def\chapheadtype{N}
+
+% Choose a heading macro
+% #1 is heading type
+% #2 is heading level
+% #3 is text for heading
+\def\genhead#1#2#3{%
+  % Compute the abs. sec. level:
+  \absseclevel=#2
+  \advance\absseclevel by \secbase
+  % Make sure \absseclevel doesn't fall outside the range:
+  \ifnum \absseclevel < 0
+    \absseclevel = 0
+  \else
+    \ifnum \absseclevel > 3
+      \absseclevel = 3
+    \fi
+  \fi
+  % The heading type:
+  \def\headtype{#1}%
+  \if \headtype U%
+    \ifnum \absseclevel < \unnlevel
+      \chardef\unnlevel = \absseclevel
+    \fi
+  \else
+    % Check for appendix sections:
+    \ifnum \absseclevel = 0
+      \edef\chapheadtype{\headtype}%
+    \else
+      \if \headtype A\if \chapheadtype N%
+       \errmessage{@appendix... within a non-appendix chapter}%
+      \fi\fi
+    \fi
+    % Check for numbered within unnumbered:
+    \ifnum \absseclevel > \unnlevel
+      \def\headtype{U}%
+    \else
+      \chardef\unnlevel = 3
+    \fi
+  \fi
+  % Now print the heading:
+  \if \headtype U%
+    \ifcase\absseclevel
+       \unnumberedzzz{#3}%
+    \or \unnumberedseczzz{#3}%
+    \or \unnumberedsubseczzz{#3}%
+    \or \unnumberedsubsubseczzz{#3}%
+    \fi
+  \else
+    \if \headtype A%
+      \ifcase\absseclevel
+         \appendixzzz{#3}%
+      \or \appendixsectionzzz{#3}%
+      \or \appendixsubseczzz{#3}%
+      \or \appendixsubsubseczzz{#3}%
+      \fi
+    \else
+      \ifcase\absseclevel
+         \chapterzzz{#3}%
+      \or \seczzz{#3}%
+      \or \numberedsubseczzz{#3}%
+      \or \numberedsubsubseczzz{#3}%
+      \fi
+    \fi
+  \fi
+  \suppressfirstparagraphindent
+}
+
+% an interface:
+\def\numhead{\genhead N}
+\def\apphead{\genhead A}
+\def\unnmhead{\genhead U}
+
+% @chapter, @appendix, @unnumbered.  Increment top-level counter, reset
+% all lower-level sectioning counters to zero.
+%
+% Also set \chaplevelprefix, which we prepend to @float sequence numbers
+% (e.g., figures), q.v.  By default (before any chapter), that is empty.
+\let\chaplevelprefix = \empty
+%
+\outer\parseargdef\chapter{\numhead0{#1}} % normally numhead0 calls chapterzzz
+\def\chapterzzz#1{%
+  % section resetting is \global in case the chapter is in a group, such
+  % as an @include file.
+  \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+    \global\advance\chapno by 1
+  %
+  % Used for \float.
+  \gdef\chaplevelprefix{\the\chapno.}%
+  \resetallfloatnos
+  %
+  % \putwordChapter can contain complex things in translations.
+  \toks0=\expandafter{\putwordChapter}%
+  \message{\the\toks0 \space \the\chapno}%
+  %
+  % Write the actual heading.
+  \chapmacro{#1}{Ynumbered}{\the\chapno}%
+  %
+  % So @section and the like are numbered underneath this chapter.
+  \global\let\section = \numberedsec
+  \global\let\subsection = \numberedsubsec
+  \global\let\subsubsection = \numberedsubsubsec
+}
+
+\outer\parseargdef\appendix{\apphead0{#1}} % normally calls appendixzzz
+%
+\def\appendixzzz#1{%
+  \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+    \global\advance\appendixno by 1
+  \gdef\chaplevelprefix{\appendixletter.}%
+  \resetallfloatnos
+  %
+  % \putwordAppendix can contain complex things in translations.
+  \toks0=\expandafter{\putwordAppendix}%
+  \message{\the\toks0 \space \appendixletter}%
+  %
+  \chapmacro{#1}{Yappendix}{\appendixletter}%
+  %
+  \global\let\section = \appendixsec
+  \global\let\subsection = \appendixsubsec
+  \global\let\subsubsection = \appendixsubsubsec
+}
+
+% normally unnmhead0 calls unnumberedzzz:
+\outer\parseargdef\unnumbered{\unnmhead0{#1}}
+\def\unnumberedzzz#1{%
+  \global\secno=0 \global\subsecno=0 \global\subsubsecno=0
+    \global\advance\unnumberedno by 1
+  %
+  % Since an unnumbered has no number, no prefix for figures.
+  \global\let\chaplevelprefix = \empty
+  \resetallfloatnos
+  %
+  % This used to be simply \message{#1}, but TeX fully expands the
+  % argument to \message.  Therefore, if #1 contained @-commands, TeX
+  % expanded them.  For example, in `@unnumbered The @cite{Book}', TeX
+  % expanded @cite (which turns out to cause errors because \cite is meant
+  % to be executed, not expanded).
+  %
+  % Anyway, we don't want the fully-expanded definition of @cite to appear
+  % as a result of the \message, we just want `@cite' itself.  We use
+  % \the<toks register> to achieve this: TeX expands \the<toks> only once,
+  % simply yielding the contents of <toks register>.  (We also do this for
+  % the toc entries.)
+  \toks0 = {#1}%
+  \message{(\the\toks0)}%
+  %
+  \chapmacro{#1}{Ynothing}{\the\unnumberedno}%
+  %
+  \global\let\section = \unnumberedsec
+  \global\let\subsection = \unnumberedsubsec
+  \global\let\subsubsection = \unnumberedsubsubsec
+}
+
+% @centerchap is like @unnumbered, but the heading is centered.
+\outer\parseargdef\centerchap{%
+  \let\centerparametersmaybe = \centerparameters
+  \unnmhead0{#1}%
+  \let\centerparametersmaybe = \relax
+}
+
+% @top is like @unnumbered.
+\let\top\unnumbered
+
+% Sections.
+%
+\outer\parseargdef\numberedsec{\numhead1{#1}} % normally calls seczzz
+\def\seczzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Ynumbered}{\the\chapno.\the\secno}%
+}
+
+% normally calls appendixsectionzzz:
+\outer\parseargdef\appendixsection{\apphead1{#1}}
+\def\appendixsectionzzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Yappendix}{\appendixletter.\the\secno}%
+}
+\let\appendixsec\appendixsection
+
+% normally calls unnumberedseczzz:
+\outer\parseargdef\unnumberedsec{\unnmhead1{#1}}
+\def\unnumberedseczzz#1{%
+  \global\subsecno=0 \global\subsubsecno=0  \global\advance\secno by 1
+  \sectionheading{#1}{sec}{Ynothing}{\the\unnumberedno.\the\secno}%
+}
+
+% Subsections.
+%
+% normally calls numberedsubseczzz:
+\outer\parseargdef\numberedsubsec{\numhead2{#1}}
+\def\numberedsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Ynumbered}{\the\chapno.\the\secno.\the\subsecno}%
+}
+
+% normally calls appendixsubseczzz:
+\outer\parseargdef\appendixsubsec{\apphead2{#1}}
+\def\appendixsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Yappendix}%
+                 {\appendixletter.\the\secno.\the\subsecno}%
+}
+
+% normally calls unnumberedsubseczzz:
+\outer\parseargdef\unnumberedsubsec{\unnmhead2{#1}}
+\def\unnumberedsubseczzz#1{%
+  \global\subsubsecno=0  \global\advance\subsecno by 1
+  \sectionheading{#1}{subsec}{Ynothing}%
+                 {\the\unnumberedno.\the\secno.\the\subsecno}%
+}
+
+% Subsubsections.
+%
+% normally numberedsubsubseczzz:
+\outer\parseargdef\numberedsubsubsec{\numhead3{#1}}
+\def\numberedsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Ynumbered}%
+                 {\the\chapno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% normally appendixsubsubseczzz:
+\outer\parseargdef\appendixsubsubsec{\apphead3{#1}}
+\def\appendixsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Yappendix}%
+                 {\appendixletter.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% normally unnumberedsubsubseczzz:
+\outer\parseargdef\unnumberedsubsubsec{\unnmhead3{#1}}
+\def\unnumberedsubsubseczzz#1{%
+  \global\advance\subsubsecno by 1
+  \sectionheading{#1}{subsubsec}{Ynothing}%
+                 {\the\unnumberedno.\the\secno.\the\subsecno.\the\subsubsecno}%
+}
+
+% These macros control what the section commands do, according
+% to what kind of chapter we are in (ordinary, appendix, or unnumbered).
+% Define them by default for a numbered chapter.
+\let\section = \numberedsec
+\let\subsection = \numberedsubsec
+\let\subsubsection = \numberedsubsubsec
+
+% Define @majorheading, @heading and @subheading
+
+\def\majorheading{%
+  {\advance\chapheadingskip by 10pt \chapbreak }%
+  \parsearg\chapheadingzzz
+}
+
+\def\chapheading{\chapbreak \parsearg\chapheadingzzz}
+\def\chapheadingzzz#1{%
+  \vbox{\chapfonts \raggedtitlesettings #1\par}%
+  \nobreak\bigskip \nobreak
+  \suppressfirstparagraphindent
+}
+
+% @heading, @subheading, @subsubheading.
+\parseargdef\heading{\sectionheading{#1}{sec}{Yomitfromtoc}{}
+  \suppressfirstparagraphindent}
+\parseargdef\subheading{\sectionheading{#1}{subsec}{Yomitfromtoc}{}
+  \suppressfirstparagraphindent}
+\parseargdef\subsubheading{\sectionheading{#1}{subsubsec}{Yomitfromtoc}{}
+  \suppressfirstparagraphindent}
+
+% These macros generate a chapter, section, etc. heading only
+% (including whitespace, linebreaking, etc. around it),
+% given all the information in convenient, parsed form.
+
+% Args are the skip and penalty (usually negative)
+\def\dobreak#1#2{\par\ifdim\lastskip<#1\removelastskip\penalty#2\vskip#1\fi}
+
+% Parameter controlling skip before chapter headings (if needed)
+\newskip\chapheadingskip
+
+% Define plain chapter starts, and page on/off switching for it.
+\def\chapbreak{\dobreak \chapheadingskip {-4000}}
+
+% Start a new page
+\def\chappager{\par\vfill\supereject}
+
+% \chapoddpage - start on an odd page for a new chapter
+% Because \domark is called before \chapoddpage, the filler page will
+% get the headings for the next chapter, which is wrong.  But we don't
+% care -- we just disable all headings on the filler page.
+\def\chapoddpage{%
+  \chappager
+  \ifodd\pageno \else
+    \begingroup
+      \headingsoff
+      \null
+      \chappager
+    \endgroup
+  \fi
+}
+
+\parseargdef\setchapternewpage{\csname CHAPPAG#1\endcsname}
+
+\def\CHAPPAGoff{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chapbreak
+\global\def\HEADINGSon{\HEADINGSsinglechapoff}}
+
+\def\CHAPPAGon{%
+\global\let\contentsalignmacro = \chappager
+\global\let\pchapsepmacro=\chappager
+\global\def\HEADINGSon{\HEADINGSsingle}}
+
+\def\CHAPPAGodd{%
+\global\let\contentsalignmacro = \chapoddpage
+\global\let\pchapsepmacro=\chapoddpage
+\global\def\HEADINGSon{\HEADINGSdouble}}
+
+\CHAPPAGon
+
+% \chapmacro - Chapter opening.
+%
+% #1 is the text, #2 is the section type (Ynumbered, Ynothing,
+% Yappendix, Yomitfromtoc), #3 the chapter number.
+% Not used for @heading series.
+%
+% To test against our argument.
+\def\Ynothingkeyword{Ynothing}
+\def\Yappendixkeyword{Yappendix}
+\def\Yomitfromtockeyword{Yomitfromtoc}
+%
+\def\chapmacro#1#2#3{%
+  \expandafter\ifx\thisenv\titlepage\else
+    \checkenv{}% chapters, etc., should not start inside an environment.
+  \fi
+  % Insert the first mark before the heading break (see notes for \domark).
+  \let\prevchapterdefs=\currentchapterdefs
+  \let\prevsectiondefs=\currentsectiondefs
+  \gdef\currentsectiondefs{\gdef\thissectionname{}\gdef\thissectionnum{}%
+                        \gdef\thissection{}}%
+  %
+  \def\temptype{#2}%
+  \ifx\temptype\Ynothingkeyword
+    \gdef\currentchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}%
+                          \gdef\thischapter{\thischaptername}}%
+  \else\ifx\temptype\Yomitfromtockeyword
+    \gdef\currentchapterdefs{\gdef\thischaptername{#1}\gdef\thischapternum{}%
+                          \gdef\thischapter{}}%
+  \else\ifx\temptype\Yappendixkeyword
+    \toks0={#1}%
+    \xdef\currentchapterdefs{%
+      \gdef\noexpand\thischaptername{\the\toks0}%
+      \gdef\noexpand\thischapternum{\appendixletter}%
+      % \noexpand\putwordAppendix avoids expanding indigestible
+      % commands in some of the translations.
+      \gdef\noexpand\thischapter{\noexpand\putwordAppendix{}
+                                 \noexpand\thischapternum:
+                                 \noexpand\thischaptername}%
+    }%
+  \else
+    \toks0={#1}%
+    \xdef\currentchapterdefs{%
+      \gdef\noexpand\thischaptername{\the\toks0}%
+      \gdef\noexpand\thischapternum{\the\chapno}%
+      % \noexpand\putwordChapter avoids expanding indigestible
+      % commands in some of the translations.
+      \gdef\noexpand\thischapter{\noexpand\putwordChapter{}
+                                 \noexpand\thischapternum:
+                                 \noexpand\thischaptername}%
+    }%
+  \fi\fi\fi
+  %
+  % Output the mark.  Pass it through \safewhatsit, to take care of
+  % the preceding space.
+  \safewhatsit\domark
+  %
+  % Insert the chapter heading break.
+  \pchapsepmacro
+  %
+  % Now the second mark, after the heading break.  No break points
+  % between here and the heading.
+  \let\prevchapterdefs=\currentchapterdefs
+  \let\prevsectiondefs=\currentsectiondefs
+  \domark
+  %
+  {%
+    \chapfonts \rm
+    \let\footnote=\errfootnoteheading % give better error message
+    %
+    % Have to define \currentsection before calling \donoderef, because the
+    % xref code eventually uses it.  On the other hand, it has to be called
+    % after \pchapsepmacro, or the headline will change too soon.
+    \gdef\currentsection{#1}%
+    %
+    % Only insert the separating space if we have a chapter/appendix
+    % number, and don't print the unnumbered ``number''.
+    \ifx\temptype\Ynothingkeyword
+      \setbox0 = \hbox{}%
+      \def\toctype{unnchap}%
+    \else\ifx\temptype\Yomitfromtockeyword
+      \setbox0 = \hbox{}% contents like unnumbered, but no toc entry
+      \def\toctype{omit}%
+    \else\ifx\temptype\Yappendixkeyword
+      \setbox0 = \hbox{\putwordAppendix{} #3\enspace}%
+      \def\toctype{app}%
+    \else
+      \setbox0 = \hbox{#3\enspace}%
+      \def\toctype{numchap}%
+    \fi\fi\fi
+    %
+    % Write the toc entry for this chapter.  Must come before the
+    % \donoderef, because we include the current node name in the toc
+    % entry, and \donoderef resets it to empty.
+    \writetocentry{\toctype}{#1}{#3}%
+    %
+    % For pdftex, we have to write out the node definition (aka, make
+    % the pdfdest) after any page break, but before the actual text has
+    % been typeset.  If the destination for the pdf outline is after the
+    % text, then jumping from the outline may wind up with the text not
+    % being visible, for instance under high magnification.
+    \donoderef{#2}%
+    %
+    % Typeset the actual heading.
+    \nobreak % Avoid page breaks at the interline glue.
+    \vbox{\raggedtitlesettings \hangindent=\wd0 \centerparametersmaybe
+          \unhbox0 #1\par}%
+  }%
+  \nobreak\bigskip % no page break after a chapter title
+  \nobreak
+}
+
+% @centerchap -- centered and unnumbered.
+\let\centerparametersmaybe = \relax
+\def\centerparameters{%
+  \advance\rightskip by 3\rightskip
+  \leftskip = \rightskip
+  \parfillskip = 0pt
+}
+
+
+% Section titles.  These macros combine the section number parts and
+% call the generic \sectionheading to do the printing.
+%
+\newskip\secheadingskip
+\def\secheadingbreak{\dobreak \secheadingskip{-1000}}
+
+% Subsection titles.
+\newskip\subsecheadingskip
+\def\subsecheadingbreak{\dobreak \subsecheadingskip{-500}}
+
+% Subsubsection titles.
+\def\subsubsecheadingskip{\subsecheadingskip}
+\def\subsubsecheadingbreak{\subsecheadingbreak}
+
+
+% Print any size, any type, section title.
+%
+% #1 is the text of the title,
+% #2 is the section level (sec/subsec/subsubsec),
+% #3 is the section type (Ynumbered, Ynothing, Yappendix, Yomitfromtoc),
+% #4 is the section number.
+%
+\def\seckeyword{sec}
+%
+\def\sectionheading#1#2#3#4{%
+  {%
+    \def\sectionlevel{#2}%
+    \def\temptype{#3}%
+    %
+    % It is ok for the @heading series commands to appear inside an
+    % environment (it's been historically allowed, though the logic is
+    % dubious), but not the others.
+    \ifx\temptype\Yomitfromtockeyword\else
+      \checkenv{}% non-@*heading should not be in an environment.
+    \fi
+    \let\footnote=\errfootnoteheading
+    %
+    % Switch to the right set of fonts.
+    \csname #2fonts\endcsname \rm
+    %
+    % Insert first mark before the heading break (see notes for \domark).
+    \let\prevsectiondefs=\currentsectiondefs
+    \ifx\temptype\Ynothingkeyword
+      \ifx\sectionlevel\seckeyword
+        \gdef\currentsectiondefs{\gdef\thissectionname{#1}\gdef\thissectionnum{}%
+                              \gdef\thissection{\thissectionname}}%
+      \fi
+    \else\ifx\temptype\Yomitfromtockeyword
+      % Don't redefine \thissection.
+    \else\ifx\temptype\Yappendixkeyword
+      \ifx\sectionlevel\seckeyword
+        \toks0={#1}%
+        \xdef\currentsectiondefs{%
+          \gdef\noexpand\thissectionname{\the\toks0}%
+          \gdef\noexpand\thissectionnum{#4}%
+          % \noexpand\putwordSection avoids expanding indigestible
+          % commands in some of the translations.
+          \gdef\noexpand\thissection{\noexpand\putwordSection{}
+                                     \noexpand\thissectionnum:
+                                     \noexpand\thissectionname}%
+        }%
+      \fi
+    \else
+      \ifx\sectionlevel\seckeyword
+        \toks0={#1}%
+        \xdef\currentsectiondefs{%
+          \gdef\noexpand\thissectionname{\the\toks0}%
+          \gdef\noexpand\thissectionnum{#4}%
+          % \noexpand\putwordSection avoids expanding indigestible
+          % commands in some of the translations.
+          \gdef\noexpand\thissection{\noexpand\putwordSection{}
+                                     \noexpand\thissectionnum:
+                                     \noexpand\thissectionname}%
+        }%
+      \fi
+    \fi\fi\fi
+    %
+    % Go into vertical mode.  Usually we'll already be there, but we
+    % don't want the following whatsit to end up in a preceding paragraph
+    % if the document didn't happen to have a blank line.
+    \par
+    %
+    % Output the mark.  Pass it through \safewhatsit, to take care of
+    % the preceding space.
+    \safewhatsit\domark
+    %
+    % Insert space above the heading.
+    \csname #2headingbreak\endcsname
+    %
+    % Now the second mark, after the heading break.  No break points
+    % between here and the heading.
+    \global\let\prevsectiondefs=\currentsectiondefs
+    \domark
+    %
+    % Only insert the space after the number if we have a section number.
+    \ifx\temptype\Ynothingkeyword
+      \setbox0 = \hbox{}%
+      \def\toctype{unn}%
+      \gdef\currentsection{#1}%
+    \else\ifx\temptype\Yomitfromtockeyword
+      % for @headings -- no section number, don't include in toc,
+      % and don't redefine \currentsection.
+      \setbox0 = \hbox{}%
+      \def\toctype{omit}%
+      \let\sectionlevel=\empty
+    \else\ifx\temptype\Yappendixkeyword
+      \setbox0 = \hbox{#4\enspace}%
+      \def\toctype{app}%
+      \gdef\currentsection{#1}%
+    \else
+      \setbox0 = \hbox{#4\enspace}%
+      \def\toctype{num}%
+      \gdef\currentsection{#1}%
+    \fi\fi\fi
+    %
+    % Write the toc entry (before \donoderef).  See comments in \chapmacro.
+    \writetocentry{\toctype\sectionlevel}{#1}{#4}%
+    %
+    % Write the node reference (= pdf destination for pdftex).
+    % Again, see comments in \chapmacro.
+    \donoderef{#3}%
+    %
+    % Interline glue will be inserted when the vbox is completed.
+    % That glue will be a valid breakpoint for the page, since it'll be
+    % preceded by a whatsit (usually from the \donoderef, or from the
+    % \writetocentry if there was no node).  We don't want to allow that
+    % break, since then the whatsits could end up on page n while the
+    % section is on page n+1, thus toc/etc. are wrong.  Debian bug 276000.
+    \nobreak
+    %
+    % Output the actual section heading.
+    \vbox{\hyphenpenalty=10000 \tolerance=5000 \parindent=0pt \ptexraggedright
+          \hangindent=\wd0  % zero if no section number
+          \unhbox0 #1}%
+  }%
+  % Add extra space after the heading -- half of whatever came above it.
+  % Don't allow stretch, though.
+  \kern .5 \csname #2headingskip\endcsname
+  %
+  % Do not let the kern be a potential breakpoint, as it would be if it
+  % was followed by glue.
+  \nobreak
+  %
+  % We'll almost certainly start a paragraph next, so don't let that
+  % glue accumulate.  (Not a breakpoint because it's preceded by a
+  % discardable item.)  However, when a paragraph is not started next
+  % (\startdefun, \cartouche, \center, etc.), this needs to be wiped out
+  % or the negative glue will cause weirdly wrong output, typically
+  % obscuring the section heading with something else.
+  \vskip-\parskip
+  %
+  % This is so the last item on the main vertical list is a known
+  % \penalty > 10000, so \startdefun, etc., can recognize the situation
+  % and do the needful.
+  \penalty 10001
+}
+
+
+\message{toc,}
+% Table of contents.
+\newwrite\tocfile
+
+% Write an entry to the toc file, opening it if necessary.
+% Called from @chapter, etc.
+%
+% Example usage: \writetocentry{sec}{Section Name}{\the\chapno.\the\secno}
+% We append the current node name (if any) and page number as additional
+% arguments for the \{chap,sec,...}entry macros which will eventually
+% read this.  The node name is used in the pdf outlines as the
+% destination to jump to.
+%
+% We open the .toc file for writing here instead of at @setfilename (or
+% any other fixed time) so that @contents can be anywhere in the document.
+% But if #1 is `omit', then we don't do anything.  This is used for the
+% table of contents chapter openings themselves.
+%
+\newif\iftocfileopened
+\def\omitkeyword{omit}%
+%
+\def\writetocentry#1#2#3{%
+  \edef\writetoctype{#1}%
+  \ifx\writetoctype\omitkeyword \else
+    \iftocfileopened\else
+      \immediate\openout\tocfile = \jobname.toc
+      \global\tocfileopenedtrue
+    \fi
+    %
+    \iflinks
+      {\atdummies
+       \edef\temp{%
+         \write\tocfile{@#1entry{#2}{#3}{\lastnode}{\noexpand\folio}}}%
+       \temp
+      }%
+    \fi
+  \fi
+  %
+  % Tell \shipout to create a pdf destination on each page, if we're
+  % writing pdf.  These are used in the table of contents.  We can't
+  % just write one on every page because the title pages are numbered
+  % 1 and 2 (the page numbers aren't printed), and so are the first
+  % two pages of the document.  Thus, we'd have two destinations named
+  % `1', and two named `2'.
+  \ifpdforxetex
+    \global\pdfmakepagedesttrue
+  \fi
+}
+
+
+% These characters do not print properly in the Computer Modern roman
+% fonts, so we must take special care.  This is more or less redundant
+% with the Texinfo input format setup at the end of this file.
+%
+\def\activecatcodes{%
+  \catcode`\"=\active
+  \catcode`\$=\active
+  \catcode`\<=\active
+  \catcode`\>=\active
+  \catcode`\\=\active
+  \catcode`\^=\active
+  \catcode`\_=\active
+  \catcode`\|=\active
+  \catcode`\~=\active
+}
+
+
+% Read the toc file, which is essentially Texinfo input.
+\def\readtocfile{%
+  \setupdatafile
+  \activecatcodes
+  \input \tocreadfilename
+}
+
+\newskip\contentsrightmargin \contentsrightmargin=1in
+\newcount\savepageno
+\newcount\lastnegativepageno \lastnegativepageno = -1
+
+% Prepare to read what we've written to \tocfile.
+%
+\def\startcontents#1{%
+  % If @setchapternewpage on, and @headings double, the contents should
+  % start on an odd page, unlike chapters.
+  \contentsalignmacro
+  \immediate\closeout\tocfile
+  %
+  % Don't need to put `Contents' or `Short Contents' in the headline.
+  % It is abundantly clear what they are.
+  \chapmacro{#1}{Yomitfromtoc}{}%
+  %
+  \savepageno = \pageno
+  \begingroup                  % Set up to handle contents files properly.
+    \raggedbottom              % Worry more about breakpoints than the bottom.
+    \entryrightmargin=\contentsrightmargin % Don't use the full line length.
+    %
+    % Roman numerals for page numbers.
+    \ifnum \pageno>0 \global\pageno = \lastnegativepageno \fi
+    \def\thistitle{}% no title in double-sided headings
+    % Record where the Roman numerals started.
+    \ifnum\romancount=0 \global\romancount=\pagecount \fi
+}
+
+% redefined for the two-volume lispref.  We always output on
+% \jobname.toc even if this is redefined.
+%
+\def\tocreadfilename{\jobname.toc}
+
+% Normal (long) toc.
+%
+\def\contents{%
+  \startcontents{\putwordTOC}%
+    \openin 1 \tocreadfilename\space
+    \ifeof 1 \else
+      \readtocfile
+    \fi
+    \vfill \eject
+    \contentsalignmacro % in case @setchapternewpage odd is in effect
+    \ifeof 1 \else
+      \pdfmakeoutlines
+    \fi
+    \closein 1
+  \endgroup
+  \contentsendroman
+}
+
+% And just the chapters.
+\def\summarycontents{%
+  \startcontents{\putwordShortTOC}%
+    %
+    \let\partentry = \shortpartentry
+    \let\numchapentry = \shortchapentry
+    \let\appentry = \shortchapentry
+    \let\unnchapentry = \shortunnchapentry
+    % We want a true roman here for the page numbers.
+    \secfonts
+    \let\rm=\shortcontrm \let\bf=\shortcontbf
+    \let\sl=\shortcontsl \let\tt=\shortconttt
+    \rm
+    \hyphenpenalty = 10000
+    \advance\baselineskip by 1pt % Open it up a little.
+    \def\numsecentry##1##2##3##4{}
+    \let\appsecentry = \numsecentry
+    \let\unnsecentry = \numsecentry
+    \let\numsubsecentry = \numsecentry
+    \let\appsubsecentry = \numsecentry
+    \let\unnsubsecentry = \numsecentry
+    \let\numsubsubsecentry = \numsecentry
+    \let\appsubsubsecentry = \numsecentry
+    \let\unnsubsubsecentry = \numsecentry
+    \openin 1 \tocreadfilename\space
+    \ifeof 1 \else
+      \readtocfile
+    \fi
+    \closein 1
+    \vfill \eject
+    \contentsalignmacro % in case @setchapternewpage odd is in effect
+  \endgroup
+  \contentsendroman
+}
+\let\shortcontents = \summarycontents
+
+% Get ready to use Arabic numerals again
+\def\contentsendroman{%
+  \lastnegativepageno = \pageno
+  \global\pageno = \savepageno
+  %
+  % If \romancount > \arabiccount, the contents are at the end of the
+  % document.  Otherwise, advance where the Arabic numerals start for
+  % the page numbers.
+  \ifnum\romancount>\arabiccount\else\global\arabiccount=\pagecount\fi
+}
+
+% Typeset the label for a chapter or appendix for the short contents.
+% The arg is, e.g., `A' for an appendix, or `3' for a chapter.
+%
+\def\shortchaplabel#1{%
+  % This space should be enough, since a single number is .5em, and the
+  % widest letter (M) is 1em, at least in the Computer Modern fonts.
+  % But use \hss just in case.
+  % (This space doesn't include the extra space that gets added after
+  % the label; that gets put in by \shortchapentry above.)
+  %
+  % We'd like to right-justify chapter numbers, but that looks strange
+  % with appendix letters.  And right-justifying numbers and
+  % left-justifying letters looks strange when there is less than 10
+  % chapters.  Have to read the whole toc once to know how many chapters
+  % there are before deciding ...
+  \hbox to 1em{#1\hss}%
+}
+
+% These macros generate individual entries in the table of contents.
+% The first argument is the chapter or section name.
+% The last argument is the page number.
+% The arguments in between are the chapter number, section number, ...
+
+% Parts, in the main contents.  Replace the part number, which doesn't
+% exist, with an empty box.  Let's hope all the numbers have the same width.
+% Also ignore the page number, which is conventionally not printed.
+\def\numeralbox{\setbox0=\hbox{8}\hbox to \wd0{\hfil}}
+\def\partentry#1#2#3#4{%
+  % Add stretch and a bonus for breaking the page before the part heading.
+  % This reduces the chance of the page being broken immediately after the
+  % part heading, before a following chapter heading.
+  \vskip 0pt plus 5\baselineskip
+  \penalty-300
+  \vskip 0pt plus -5\baselineskip
+  \dochapentry{\numeralbox\labelspace#1}{}%
+}
+%
+% Parts, in the short toc.
+\def\shortpartentry#1#2#3#4{%
+  \penalty-300
+  \vskip.5\baselineskip plus.15\baselineskip minus.1\baselineskip
+  \shortchapentry{{\bf #1}}{\numeralbox}{}{}%
+}
+
+% Chapters, in the main contents.
+\def\numchapentry#1#2#3#4{\dochapentry{#2\labelspace#1}{#4}}
+
+% Chapters, in the short toc.
+% See comments in \dochapentry re vbox and related settings.
+\def\shortchapentry#1#2#3#4{%
+  \tocentry{\shortchaplabel{#2}\labelspace #1}{\doshortpageno\bgroup#4\egroup}%
+}
+
+% Appendices, in the main contents.
+% Need the word Appendix, and a fixed-size box.
+%
+\def\appendixbox#1{%
+  % We use M since it's probably the widest letter.
+  \setbox0 = \hbox{\putwordAppendix{} M}%
+  \hbox to \wd0{\putwordAppendix{} #1\hss}}
+%
+\def\appentry#1#2#3#4{\dochapentry{\appendixbox{#2}\hskip.7em#1}{#4}}
+
+% Unnumbered chapters.
+\def\unnchapentry#1#2#3#4{\dochapentry{#1}{#4}}
+\def\shortunnchapentry#1#2#3#4{\tocentry{#1}{\doshortpageno\bgroup#4\egroup}}
+
+% Sections.
+\def\numsecentry#1#2#3#4{\dosecentry{#2\labelspace#1}{#4}}
+\let\appsecentry=\numsecentry
+\def\unnsecentry#1#2#3#4{\dosecentry{#1}{#4}}
+
+% Subsections.
+\def\numsubsecentry#1#2#3#4{\dosubsecentry{#2\labelspace#1}{#4}}
+\let\appsubsecentry=\numsubsecentry
+\def\unnsubsecentry#1#2#3#4{\dosubsecentry{#1}{#4}}
+
+% And subsubsections.
+\def\numsubsubsecentry#1#2#3#4{\dosubsubsecentry{#2\labelspace#1}{#4}}
+\let\appsubsubsecentry=\numsubsubsecentry
+\def\unnsubsubsecentry#1#2#3#4{\dosubsubsecentry{#1}{#4}}
+
+% This parameter controls the indentation of the various levels.
+% Same as \defaultparindent.
+\newdimen\tocindent \tocindent = 15pt
+
+% Now for the actual typesetting. In all these, #1 is the text and #2 is the
+% page number.
+%
+% If the toc has to be broken over pages, we want it to be at chapters
+% if at all possible; hence the \penalty.
+\def\dochapentry#1#2{%
+   \penalty-300 \vskip1\baselineskip plus.33\baselineskip minus.25\baselineskip
+   \begingroup
+     % Move the page numbers slightly to the right
+     \advance\entryrightmargin by -0.05em
+     \chapentryfonts
+     \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+   \endgroup
+   \nobreak\vskip .25\baselineskip plus.1\baselineskip
+}
+
+\def\dosecentry#1#2{\begingroup
+  \secentryfonts \leftskip=\tocindent
+  \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+\def\dosubsecentry#1#2{\begingroup
+  \subsecentryfonts \leftskip=2\tocindent
+  \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+\def\dosubsubsecentry#1#2{\begingroup
+  \subsubsecentryfonts \leftskip=3\tocindent
+  \tocentry{#1}{\dopageno\bgroup#2\egroup}%
+\endgroup}
+
+% We use the same \entry macro as for the index entries.
+\let\tocentry = \entry
+
+% Space between chapter (or whatever) number and the title.
+\def\labelspace{\hskip1em \relax}
+
+\def\dopageno#1{{\rm #1}}
+\def\doshortpageno#1{{\rm #1}}
+
+\def\chapentryfonts{\secfonts \rm}
+\def\secentryfonts{\textfonts}
+\def\subsecentryfonts{\textfonts}
+\def\subsubsecentryfonts{\textfonts}
+
+
+\message{environments,}
+% @foo ... @end foo.
+
+% @tex ... @end tex    escapes into raw TeX temporarily.
+% One exception: @ is still an escape character, so that @end tex works.
+% But \@ or @@ will get a plain @ character.
+
+\envdef\tex{%
+  \setregularquotes
+  \catcode `\\=0 \catcode `\{=1 \catcode `\}=2
+  \catcode `\$=3 \catcode `\&=4 \catcode `\#=6
+  \catcode `\^=7 \catcode `\_=8 \catcode `\~=\active \let~=\tie
+  \catcode `\%=14
+  \catcode `\+=\other
+  \catcode `\"=\other
+  \catcode `\|=\other
+  \catcode `\<=\other
+  \catcode `\>=\other
+  \catcode `\`=\other
+  \catcode `\'=\other
+  %
+  % ' is active in math mode (mathcode"8000).  So reset it, and all our
+  % other math active characters (just in case), to plain's definitions.
+  \mathactive
+  %
+  % Inverse of the list at the beginning of the file.
+  \let\b=\ptexb
+  \let\bullet=\ptexbullet
+  \let\c=\ptexc
+  \let\,=\ptexcomma
+  \let\.=\ptexdot
+  \let\dots=\ptexdots
+  \let\equiv=\ptexequiv
+  \let\!=\ptexexclam
+  \let\i=\ptexi
+  \let\indent=\ptexindent
+  \let\noindent=\ptexnoindent
+  \let\{=\ptexlbrace
+  \let\+=\tabalign
+  \let\}=\ptexrbrace
+  \let\/=\ptexslash
+  \let\sp=\ptexsp
+  \let\*=\ptexstar
+  %\let\sup=\ptexsup % do not redefine, we want @sup to work in math mode
+  \let\t=\ptext
+  \expandafter \let\csname top\endcsname=\ptextop  % we've made it outer
+  \let\frenchspacing=\plainfrenchspacing
+  %
+  \def\endldots{\mathinner{\ldots\ldots\ldots\ldots}}%
+  \def\enddots{\relax\ifmmode\endldots\else$\mathsurround=0pt \endldots\,$\fi}%
+  \def\@{@}%
+}
+% There is no need to define \Etex.
+
+% Define @lisp ... @end lisp.
+% @lisp environment forms a group so it can rebind things,
+% including the definition of @end lisp (which normally is erroneous).
+
+% Amount to narrow the margins by for @lisp.
+\newskip\lispnarrowing \lispnarrowing=0.4in
+
+% This is the definition that ^^M gets inside @lisp, @example, and other
+% such environments.  \null is better than a space, since it doesn't
+% have any width.
+\def\lisppar{\null\endgraf}
+
+% This space is always present above and below environments.
+\newskip\envskipamount \envskipamount = 0pt
+
+% Make spacing and below environment symmetrical.  We use \parskip here
+% to help in doing that, since in @example-like environments \parskip
+% is reset to zero; thus the \afterenvbreak inserts no space -- but the
+% start of the next paragraph will insert \parskip.
+%
+\def\aboveenvbreak{{%
+  % =10000 instead of <10000 because of a special case in \itemzzz and
+  % \sectionheading, q.v.
+  \ifnum \lastpenalty=10000 \else
+    \advance\envskipamount by \parskip
+    \endgraf
+    \ifdim\lastskip<\envskipamount
+      \removelastskip
+      \ifnum\lastpenalty<10000
+        % Penalize breaking before the environment, because preceding text
+        % often leads into it.
+        \penalty100
+      \fi
+      \vskip\envskipamount
+    \fi
+  \fi
+}}
+
+\def\afterenvbreak{{%
+  % =10000 instead of <10000 because of a special case in \itemzzz and
+  % \sectionheading, q.v.
+  \ifnum \lastpenalty=10000 \else
+    \advance\envskipamount by \parskip
+    \endgraf
+    \ifdim\lastskip<\envskipamount
+      \removelastskip
+      % it's not a good place to break if the last penalty was \nobreak
+      % or better ...
+      \ifnum\lastpenalty<10000 \penalty-50 \fi
+      \vskip\envskipamount
+    \fi
+  \fi
+}}
+
+% \nonarrowing is a flag.  If "set", @lisp etc don't narrow margins; it will
+% also clear it, so that its embedded environments do the narrowing again.
+\let\nonarrowing=\relax
+
+% @cartouche ... @end cartouche: draw rectangle w/rounded corners around
+% environment contents.
+
+%
+\def\ctl{{\circle\char'013\hskip -6pt}}% 6pt from pl file: 1/2charwidth
+\def\ctr{{\hskip 6pt\circle\char'010}}
+\def\cbl{{\circle\char'012\hskip -6pt}}
+\def\cbr{{\hskip 6pt\circle\char'011}}
+\def\carttop{\hbox to \cartouter{\hskip\lskip
+        \ctl\leaders\hrule height\circthick\hfil\ctr
+        \hskip\rskip}}
+\def\cartbot{\hbox to \cartouter{\hskip\lskip
+        \cbl\leaders\hrule height\circthick\hfil\cbr
+        \hskip\rskip}}
+%
+\newskip\lskip\newskip\rskip
+
+% only require the font if @cartouche is actually used
+\def\cartouchefontdefs{%
+  \font\circle=lcircle10\relax
+  \circthick=\fontdimen8\circle
+}
+\newdimen\circthick
+\newdimen\cartouter\newdimen\cartinner
+\newskip\normbskip\newskip\normpskip\newskip\normlskip
+
+
+\envdef\cartouche{%
+  \cartouchefontdefs
+  \ifhmode\par\fi  % can't be in the midst of a paragraph.
+  \startsavinginserts
+  \lskip=\leftskip \rskip=\rightskip
+  \leftskip=0pt\rightskip=0pt % we want these *outside*.
+  \cartinner=\hsize \advance\cartinner by-\lskip
+  \advance\cartinner by-\rskip
+  \cartouter=\hsize
+  \advance\cartouter by 18.4pt % allow for 3pt kerns on either
+                               % side, and for 6pt waste from
+                               % each corner char, and rule thickness
+  \normbskip=\baselineskip \normpskip=\parskip \normlskip=\lineskip
+  %
+  % If this cartouche directly follows a sectioning command, we need the
+  % \parskip glue (backspaced over by default) or the cartouche can
+  % collide with the section heading.
+  \ifnum\lastpenalty>10000 \vskip\parskip \penalty\lastpenalty \fi
+  %
+  \setbox\groupbox=\vbox\bgroup
+      \baselineskip=0pt\parskip=0pt\lineskip=0pt
+      \carttop
+      \hbox\bgroup
+         \hskip\lskip
+         \vrule\kern3pt
+         \vbox\bgroup
+             \kern3pt
+             \hsize=\cartinner
+             \baselineskip=\normbskip
+             \lineskip=\normlskip
+             \parskip=\normpskip
+             \vskip -\parskip
+             \comment % For explanation, see the end of def\group.
+}
+\def\Ecartouche{%
+              \ifhmode\par\fi
+             \kern3pt
+         \egroup
+         \kern3pt\vrule
+         \hskip\rskip
+      \egroup
+      \cartbot
+  \egroup
+  \addgroupbox
+  \checkinserts
+}
+
+
+% This macro is called at the beginning of all the @example variants,
+% inside a group.
+\newdimen\nonfillparindent
+\def\nonfillstart{%
+  \aboveenvbreak
+  \ifdim\hfuzz < 12pt \hfuzz = 12pt \fi % Don't be fussy
+  \sepspaces % Make spaces be word-separators rather than space tokens.
+  \let\par = \lisppar % don't ignore blank lines
+  \obeylines % each line of input is a line of output
+  \parskip = 0pt
+  % Turn off paragraph indentation but redefine \indent to emulate
+  % the normal \indent.
+  \nonfillparindent=\parindent
+  \parindent = 0pt
+  \let\indent\nonfillindent
+  %
+  \emergencystretch = 0pt % don't try to avoid overfull boxes
+  \ifx\nonarrowing\relax
+    \advance \leftskip by \lispnarrowing
+    \exdentamount=\lispnarrowing
+  \else
+    \let\nonarrowing = \relax
+  \fi
+  \let\exdent=\nofillexdent
+}
+
+\begingroup
+\obeyspaces
+% We want to swallow spaces (but not other tokens) after the fake
+% @indent in our nonfill-environments, where spaces are normally
+% active and set to @tie, resulting in them not being ignored after
+% @indent.
+\gdef\nonfillindent{\futurelet\temp\nonfillindentcheck}%
+\gdef\nonfillindentcheck{%
+\ifx\temp %
+\expandafter\nonfillindentgobble%
+\else%
+\leavevmode\nonfillindentbox%
+\fi%
+}%
+\endgroup
+\def\nonfillindentgobble#1{\nonfillindent}
+\def\nonfillindentbox{\hbox to \nonfillparindent{\hss}}
+
+% If you want all examples etc. small: @set dispenvsize small.
+% If you want even small examples the full size: @set dispenvsize nosmall.
+% This affects the following displayed environments:
+%    @example, @display, @format, @lisp, @verbatim
+%
+\def\smallword{small}
+\def\nosmallword{nosmall}
+\let\SETdispenvsize\relax
+\def\setnormaldispenv{%
+  \ifx\SETdispenvsize\smallword
+    % end paragraph for sake of leading, in case document has no blank
+    % line.  This is redundant with what happens in \aboveenvbreak, but
+    % we need to do it before changing the fonts, and it's inconvenient
+    % to change the fonts afterward.
+    \ifnum \lastpenalty=10000 \else \endgraf \fi
+    \smallexamplefonts \rm
+  \fi
+}
+\def\setsmalldispenv{%
+  \ifx\SETdispenvsize\nosmallword
+  \else
+    \ifnum \lastpenalty=10000 \else \endgraf \fi
+    \smallexamplefonts \rm
+  \fi
+}
+
+% We often define two environments, @foo and @smallfoo.
+% Let's do it in one command.  #1 is the env name, #2 the definition.
+\def\makedispenvdef#1#2{%
+  \expandafter\envdef\csname#1\endcsname {\setnormaldispenv #2}%
+  \expandafter\envdef\csname small#1\endcsname {\setsmalldispenv #2}%
+  \expandafter\let\csname E#1\endcsname \afterenvbreak
+  \expandafter\let\csname Esmall#1\endcsname \afterenvbreak
+}
+
+% Define two environment synonyms (#1 and #2) for an environment.
+\def\maketwodispenvdef#1#2#3{%
+  \makedispenvdef{#1}{#3}%
+  \makedispenvdef{#2}{#3}%
+}
+%
+% @lisp: indented, narrowed, typewriter font;
+% @example: same as @lisp.
+%
+% @smallexample and @smalllisp: use smaller fonts.
+% Originally contributed by Pavel@xerox.
+%
+\maketwodispenvdef{lisp}{example}{%
+  \nonfillstart
+  \tt\setcodequotes
+  \let\kbdfont = \kbdexamplefont % Allow @kbd to do something special.
+  \parsearg\gobble
+}
+% @display/@smalldisplay: same as @lisp except keep current font.
+%
+\makedispenvdef{display}{%
+  \nonfillstart
+  \gobble
+}
+
+% @format/@smallformat: same as @display except don't narrow margins.
+%
+\makedispenvdef{format}{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \gobble
+}
+
+% @flushleft: same as @format, but doesn't obey \SETdispenvsize.
+\envdef\flushleft{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \gobble
+}
+\let\Eflushleft = \afterenvbreak
+
+% @flushright.
+%
+\envdef\flushright{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \advance\leftskip by 0pt plus 1fill\relax
+  \gobble
+}
+\let\Eflushright = \afterenvbreak
+
+
+% @raggedright does more-or-less normal line breaking but no right
+% justification.  From plain.tex.
+\envdef\raggedright{%
+  \rightskip0pt plus2.4em \spaceskip.3333em \xspaceskip.5em\relax
+}
+\let\Eraggedright\par
+
+\envdef\raggedleft{%
+  \parindent=0pt \leftskip0pt plus2em
+  \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt
+  \hbadness=10000 % Last line will usually be underfull, so turn off
+                  % badness reporting.
+}
+\let\Eraggedleft\par
+
+\envdef\raggedcenter{%
+  \parindent=0pt \rightskip0pt plus1em \leftskip0pt plus1em
+  \spaceskip.3333em \xspaceskip.5em \parfillskip=0pt
+  \hbadness=10000 % Last line will usually be underfull, so turn off
+                  % badness reporting.
+}
+\let\Eraggedcenter\par
+
+
+% @quotation does normal linebreaking (hence we can't use \nonfillstart)
+% and narrows the margins.  We keep \parskip nonzero in general, since
+% we're doing normal filling.  So, when using \aboveenvbreak and
+% \afterenvbreak, temporarily make \parskip 0.
+%
+\makedispenvdef{quotation}{\quotationstart}
+%
+\def\quotationstart{%
+  \indentedblockstart % same as \indentedblock, but increase right margin too.
+  \ifx\nonarrowing\relax
+    \advance\rightskip by \lispnarrowing
+  \fi
+  \parsearg\quotationlabel
+}
+
+% We have retained a nonzero parskip for the environment, since we're
+% doing normal filling.
+%
+\def\Equotation{%
+  \par
+  \ifx\quotationauthor\thisisundefined\else
+    % indent a bit.
+    \leftline{\kern 2\leftskip \sl ---\quotationauthor}%
+  \fi
+  {\parskip=0pt \afterenvbreak}%
+}
+\def\Esmallquotation{\Equotation}
+
+% If we're given an argument, typeset it in bold with a colon after.
+\def\quotationlabel#1{%
+  \def\temp{#1}%
+  \ifx\temp\empty \else
+    {\bf #1: }%
+  \fi
+}
+
+% @indentedblock is like @quotation, but indents only on the left and
+% has no optional argument.
+%
+\makedispenvdef{indentedblock}{\indentedblockstart}
+%
+\def\indentedblockstart{%
+  {\parskip=0pt \aboveenvbreak}% because \aboveenvbreak inserts \parskip
+  \parindent=0pt
+  %
+  % @cartouche defines \nonarrowing to inhibit narrowing at next level down.
+  \ifx\nonarrowing\relax
+    \advance\leftskip by \lispnarrowing
+    \exdentamount = \lispnarrowing
+  \else
+    \let\nonarrowing = \relax
+  \fi
+}
+
+% Keep a nonzero parskip for the environment, since we're doing normal filling.
+%
+\def\Eindentedblock{%
+  \par
+  {\parskip=0pt \afterenvbreak}%
+}
+\def\Esmallindentedblock{\Eindentedblock}
+
+
+% LaTeX-like @verbatim...@end verbatim and @verb{<char>...<char>}
+% If we want to allow any <char> as delimiter,
+% we need the curly braces so that makeinfo sees the @verb command, eg:
+% `@verbx...x' would look like the '@verbx' command.  --janneke@gnu.org
+%
+% [Knuth]: Donald Ervin Knuth, 1996.  The TeXbook.
+%
+% [Knuth] p.344; only we need to do the other characters Texinfo sets
+% active too.  Otherwise, they get lost as the first character on a
+% verbatim line.
+\def\dospecials{%
+  \do\ \do\\\do\{\do\}\do\$\do\&%
+  \do\#\do\^\do\^^K\do\_\do\^^A\do\%\do\~%
+  \do\<\do\>\do\|\do\@\do+\do\"%
+  % Don't do the quotes -- if we do, @set txicodequoteundirected and
+  % @set txicodequotebacktick will not have effect on @verb and
+  % @verbatim, and ?` and !` ligatures won't get disabled.
+  %\do\`\do\'%
+}
+%
+% [Knuth] p. 380
+\def\uncatcodespecials{%
+  \def\do##1{\catcode`##1=\other}\dospecials}
+%
+% Setup for the @verb command.
+%
+% Eight spaces for a tab
+\begingroup
+  \catcode`\^^I=\active
+  \gdef\tabeightspaces{\catcode`\^^I=\active\def^^I{\ \ \ \ \ \ \ \ }}
+\endgroup
+%
+\def\setupverb{%
+  \tt  % easiest (and conventionally used) font for verbatim
+  \def\par{\leavevmode\endgraf}%
+  \setcodequotes
+  \tabeightspaces
+  % Respect line breaks,
+  % print special symbols as themselves, and
+  % make each space count
+  % must do in this order:
+  \obeylines \uncatcodespecials \sepspaces
+}
+
+% Setup for the @verbatim environment
+%
+% Real tab expansion.
+\newdimen\tabw \setbox0=\hbox{\tt\space} \tabw=8\wd0 % tab amount
+%
+% We typeset each line of the verbatim in an \hbox, so we can handle
+% tabs.
+\newbox\verbbox
+\def\starttabbox{\setbox\verbbox=\hbox\bgroup}
+%
+\begingroup
+  \catcode`\^^I=\active
+  \gdef\tabexpand{%
+    \catcode`\^^I=\active
+    \def^^I{\leavevmode\egroup
+      \dimen\verbbox=\wd\verbbox % the width so far, or since the previous tab
+      \divide\dimen\verbbox by\tabw
+      \multiply\dimen\verbbox by\tabw % compute previous multiple of \tabw
+      \advance\dimen\verbbox by\tabw  % advance to next multiple of \tabw
+      \wd\verbbox=\dimen\verbbox
+      \leavevmode\box\verbbox \starttabbox
+    }%
+  }
+\endgroup
+
+% start the verbatim environment.
+\def\setupverbatim{%
+  \let\nonarrowing = t%
+  \nonfillstart
+  \tt % easiest (and conventionally used) font for verbatim
+  \def\par{\egroup\leavevmode\box\verbbox\endgraf\starttabbox}%
+  \tabexpand
+  \setcodequotes
+  % Respect line breaks,
+  % print special symbols as themselves, and
+  % make each space count.
+  % Must do in this order:
+  \obeylines \uncatcodespecials \sepspaces
+}
+
+% Do the @verb magic: verbatim text is quoted by unique
+% delimiter characters.  Before first delimiter expect a
+% right brace, after last delimiter expect closing brace:
+%
+%    \def\doverb'{'<char>#1<char>'}'{#1}
+%
+% [Knuth] p. 382; only eat outer {}
+\begingroup
+  \catcode`[=1\catcode`]=2\catcode`\{=\other\catcode`\}=\other
+  \gdef\doverb{#1[\def\next##1#1}[##1\endgroup]\next]
+\endgroup
+%
+\def\verb{\begingroup\setupverb\doverb}
+%
+%
+% Do the @verbatim magic: define the macro \doverbatim so that
+% the (first) argument ends when '@end verbatim' is reached, ie:
+%
+%     \def\doverbatim#1@end verbatim{#1}
+%
+% For Texinfo it's a lot easier than for LaTeX,
+% because texinfo's \verbatim doesn't stop at '\end{verbatim}':
+% we need not redefine '\', '{' and '}'.
+%
+% Inspired by LaTeX's verbatim command set [latex.ltx]
+%
+\begingroup
+  \catcode`\ =\active
+  \obeylines %
+  % ignore everything up to the first ^^M, that's the newline at the end
+  % of the @verbatim input line itself.  Otherwise we get an extra blank
+  % line in the output.
+  \xdef\doverbatim#1^^M#2@end verbatim{%
+    \starttabbox#2\egroup\noexpand\end\gobble verbatim}%
+  % We really want {...\end verbatim} in the body of the macro, but
+  % without the active space; thus we have to use \xdef and \gobble.
+  % The \egroup ends the \verbbox started at the end of the last line in
+  % the block.
+\endgroup
+%
+\envdef\verbatim{%
+    \setnormaldispenv\setupverbatim\doverbatim
+}
+\let\Everbatim = \afterenvbreak
+
+
+% @verbatiminclude FILE - insert text of file in verbatim environment.
+%
+\def\verbatiminclude{\parseargusing\filenamecatcodes\doverbatiminclude}
+%
+\def\doverbatiminclude#1{%
+  {%
+    \makevalueexpandable
+    \setupverbatim
+    {%
+      \indexnofonts       % Allow `@@' and other weird things in file names.
+      \wlog{texinfo.tex: doing @verbatiminclude of #1^^J}%
+      \edef\tmp{\noexpand\input #1 }
+      \expandafter
+    }\expandafter\starttabbox\tmp\egroup
+    \afterenvbreak
+  }%
+}
+
+% @copying ... @end copying.
+% Save the text away for @insertcopying later.
+%
+% We save the uninterpreted tokens, rather than creating a box.
+% Saving the text in a box would be much easier, but then all the
+% typesetting commands (@smallbook, font changes, etc.) have to be done
+% beforehand -- and a) we want @copying to be done first in the source
+% file; b) letting users define the frontmatter in as flexible order as
+% possible is desirable.
+%
+\def\copying{\checkenv{}\begingroup\scanargctxt\docopying}
+\def\docopying#1@end copying{\endgroup\def\copyingtext{#1}}
+%
+\def\insertcopying{%
+  \begingroup
+    \parindent = 0pt  % paragraph indentation looks wrong on title page
+    \scanexp\copyingtext
+  \endgroup
+}
+
+
+\message{defuns,}
+% @defun etc.
+
+\newskip\defbodyindent \defbodyindent=.4in
+\newskip\defargsindent \defargsindent=50pt
+\newskip\deflastargmargin \deflastargmargin=18pt
+\newcount\defunpenalty
+
+% Start the processing of @deffn:
+\def\startdefun{%
+  \ifnum\lastpenalty<10000
+    \medbreak
+    \defunpenalty=10003 % Will keep this @deffn together with the
+                        % following @def command, see below.
+  \else
+    % If there are two @def commands in a row, we'll have a \nobreak,
+    % which is there to keep the function description together with its
+    % header.  But if there's nothing but headers, we need to allow a
+    % break somewhere.  Check specifically for penalty 10002, inserted
+    % by \printdefunline, instead of 10000, since the sectioning
+    % commands also insert a nobreak penalty, and we don't want to allow
+    % a break between a section heading and a defun.
+    %
+    % As a further refinement, we avoid "club" headers by signalling
+    % with penalty of 10003 after the very first @deffn in the
+    % sequence (see above), and penalty of 10002 after any following
+    % @def command.
+    \ifnum\lastpenalty=10002 \penalty2000 \else \defunpenalty=10002 \fi
+    %
+    % Similarly, after a section heading, do not allow a break.
+    % But do insert the glue.
+    \medskip  % preceded by discardable penalty, so not a breakpoint
+  \fi
+  %
+  \parindent=0in
+  \advance\leftskip by \defbodyindent
+  \exdentamount=\defbodyindent
+}
+
+\def\dodefunx#1{%
+  % First, check whether we are in the right environment:
+  \checkenv#1%
+  %
+  % As above, allow line break if we have multiple x headers in a row.
+  % It's not a great place, though.
+  \ifnum\lastpenalty=10002 \penalty3000 \else \defunpenalty=10002 \fi
+  %
+  % And now, it's time to reuse the body of the original defun:
+  \expandafter\gobbledefun#1%
+}
+\def\gobbledefun#1\startdefun{}
+
+% \printdefunline \deffnheader{text}
+%
+\def\printdefunline#1#2{%
+  \begingroup
+    % call \deffnheader:
+    #1#2 \endheader
+    % common ending:
+    \interlinepenalty = 10000
+    \advance\rightskip by 0pt plus 1fil\relax
+    \endgraf
+    \nobreak\vskip -\parskip
+    \penalty\defunpenalty  % signal to \startdefun and \dodefunx
+    % Some of the @defun-type tags do not enable magic parentheses,
+    % rendering the following check redundant.  But we don't optimize.
+    \checkparencounts
+  \endgroup
+}
+
+\def\Edefun{\endgraf\medbreak}
+
+% \makedefun{deffn} creates \deffn, \deffnx and \Edeffn;
+% the only thing remaining is to define \deffnheader.
+%
+\def\makedefun#1{%
+  \expandafter\let\csname E#1\endcsname = \Edefun
+  \edef\temp{\noexpand\domakedefun
+    \makecsname{#1}\makecsname{#1x}\makecsname{#1header}}%
+  \temp
+}
+
+% \domakedefun \deffn \deffnx \deffnheader { (defn. of \deffnheader) }
+%
+% Define \deffn and \deffnx, without parameters.
+% \deffnheader has to be defined explicitly.
+%
+\def\domakedefun#1#2#3{%
+  \envdef#1{%
+    \startdefun
+    \doingtypefnfalse    % distinguish typed functions from all else
+    \parseargusing\activeparens{\printdefunline#3}%
+  }%
+  \def#2{\dodefunx#1}%
+  \def#3%
+}
+
+\newif\ifdoingtypefn       % doing typed function?
+\newif\ifrettypeownline    % typeset return type on its own line?
+
+% @deftypefnnewline on|off says whether the return type of typed functions
+% are printed on their own line.  This affects @deftypefn, @deftypefun,
+% @deftypeop, and @deftypemethod.
+%
+\parseargdef\deftypefnnewline{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETtxideftypefnnl\endcsname
+      = \empty
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETtxideftypefnnl\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @txideftypefnnl value `\temp',
+                must be on|off}%
+  \fi\fi
+}
+
+% \dosubind {index}{topic}{subtopic}
+%
+% If SUBTOPIC is present, precede it with a space, and call \doind.
+% (At some time during the 20th century, this made a two-level entry in an
+% index such as the operation index.  Nobody seemed to notice the change in
+% behaviour though.)
+\def\dosubind#1#2#3{%
+  \def\thirdarg{#3}%
+  \ifx\thirdarg\empty
+    \doind{#1}{#2}%
+  \else
+    \doind{#1}{#2\space#3}%
+  \fi
+}
+
+% Untyped functions:
+
+% @deffn category name args
+\makedefun{deffn}{\deffngeneral{}}
+
+% @deffn category class name args
+\makedefun{defop}#1 {\defopon{#1\ \putwordon}}
+
+% \defopon {category on}class name args
+\def\defopon#1#2 {\deffngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
+
+% \deffngeneral {subind}category name args
+%
+\def\deffngeneral#1#2 #3 #4\endheader{%
+  \dosubind{fn}{\code{#3}}{#1}%
+  \defname{#2}{}{#3}\magicamp\defunargs{#4\unskip}%
+}
+
+% Typed functions:
+
+% @deftypefn category type name args
+\makedefun{deftypefn}{\deftypefngeneral{}}
+
+% @deftypeop category class type name args
+\makedefun{deftypeop}#1 {\deftypeopon{#1\ \putwordon}}
+
+% \deftypeopon {category on}class type name args
+\def\deftypeopon#1#2 {\deftypefngeneral{\putwordon\ \code{#2}}{#1\ \code{#2}} }
+
+% \deftypefngeneral {subind}category type name args
+%
+\def\deftypefngeneral#1#2 #3 #4 #5\endheader{%
+  \dosubind{fn}{\code{#4}}{#1}%
+  \doingtypefntrue
+  \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+% Typed variables:
+
+% @deftypevr category type var args
+\makedefun{deftypevr}{\deftypecvgeneral{}}
+
+% @deftypecv category class type var args
+\makedefun{deftypecv}#1 {\deftypecvof{#1\ \putwordof}}
+
+% \deftypecvof {category of}class type var args
+\def\deftypecvof#1#2 {\deftypecvgeneral{\putwordof\ \code{#2}}{#1\ \code{#2}} }
+
+% \deftypecvgeneral {subind}category type var args
+%
+\def\deftypecvgeneral#1#2 #3 #4 #5\endheader{%
+  \dosubind{vr}{\code{#4}}{#1}%
+  \defname{#2}{#3}{#4}\defunargs{#5\unskip}%
+}
+
+% Untyped variables:
+
+% @defvr category var args
+\makedefun{defvr}#1 {\deftypevrheader{#1} {} }
+
+% @defcv category class var args
+\makedefun{defcv}#1 {\defcvof{#1\ \putwordof}}
+
+% \defcvof {category of}class var args
+\def\defcvof#1#2 {\deftypecvof{#1}#2 {} }
+
+% Types:
+
+% @deftp category name args
+\makedefun{deftp}#1 #2 #3\endheader{%
+  \doind{tp}{\code{#2}}%
+  \defname{#1}{}{#2}\defunargs{#3\unskip}%
+}
+
+% Remaining @defun-like shortcuts:
+\makedefun{defun}{\deffnheader{\putwordDeffunc} }
+\makedefun{defmac}{\deffnheader{\putwordDefmac} }
+\makedefun{defspec}{\deffnheader{\putwordDefspec} }
+\makedefun{deftypefun}{\deftypefnheader{\putwordDeffunc} }
+\makedefun{defvar}{\defvrheader{\putwordDefvar} }
+\makedefun{defopt}{\defvrheader{\putwordDefopt} }
+\makedefun{deftypevar}{\deftypevrheader{\putwordDefvar} }
+\makedefun{defmethod}{\defopon\putwordMethodon}
+\makedefun{deftypemethod}{\deftypeopon\putwordMethodon}
+\makedefun{defivar}{\defcvof\putwordInstanceVariableof}
+\makedefun{deftypeivar}{\deftypecvof\putwordInstanceVariableof}
+
+% \defname, which formats the name of the @def (not the args).
+% #1 is the category, such as "Function".
+% #2 is the return type, if any.
+% #3 is the function name.
+%
+% We are followed by (but not passed) the arguments, if any.
+%
+\def\defname#1#2#3{%
+  \par
+  % Get the values of \leftskip and \rightskip as they were outside the @def...
+  \advance\leftskip by -\defbodyindent
+  %
+  % Determine if we are typesetting the return type of a typed function
+  % on a line by itself.
+  \rettypeownlinefalse
+  \ifdoingtypefn  % doing a typed function specifically?
+    % then check user option for putting return type on its own line:
+    \expandafter\ifx\csname SETtxideftypefnnl\endcsname\relax \else
+      \rettypeownlinetrue
+    \fi
+  \fi
+  %
+  % How we'll format the category name.  Putting it in brackets helps
+  % distinguish it from the body text that may end up on the next line
+  % just below it.
+  \def\temp{#1}%
+  \setbox0=\hbox{\kern\deflastargmargin \ifx\temp\empty\else [\rm\temp]\fi}
+  %
+  % Figure out line sizes for the paragraph shape.  We'll always have at
+  % least two.
+  \tempnum = 2
+  %
+  % The first line needs space for \box0; but if \rightskip is nonzero,
+  % we need only space for the part of \box0 which exceeds it:
+  \dimen0=\hsize  \advance\dimen0 by -\wd0  \advance\dimen0 by \rightskip
+  %
+  % If doing a return type on its own line, we'll have another line.
+  \ifrettypeownline
+    \advance\tempnum by 1
+    \def\maybeshapeline{0in \hsize}%
+  \else
+    \def\maybeshapeline{}%
+  \fi
+  %
+  % The continuations:
+  \dimen2=\hsize  \advance\dimen2 by -\defargsindent
+  %
+  % The final paragraph shape:
+  \parshape \tempnum  0in \dimen0  \maybeshapeline  \defargsindent \dimen2
+  %
+  % Put the category name at the right margin.
+  \noindent
+  \hbox to 0pt{%
+    \hfil\box0 \kern-\hsize
+    % \hsize has to be shortened this way:
+    \kern\leftskip
+    % Intentionally do not respect \rightskip, since we need the space.
+  }%
+  %
+  % Allow all lines to be underfull without complaint:
+  \tolerance=10000 \hbadness=10000
+  \exdentamount=\defbodyindent
+  {%
+    % defun fonts. We use typewriter by default (used to be bold) because:
+    % . we're printing identifiers, they should be in tt in principle.
+    % . in languages with many accents, such as Czech or French, it's
+    %   common to leave accents off identifiers.  The result looks ok in
+    %   tt, but exceedingly strange in rm.
+    % . we don't want -- and --- to be treated as ligatures.
+    % . this still does not fix the ?` and !` ligatures, but so far no
+    %   one has made identifiers using them :).
+    \df \tt
+    \def\temp{#2}% text of the return type
+    \ifx\temp\empty\else
+      \tclose{\temp}% typeset the return type
+      \ifrettypeownline
+        % put return type on its own line; prohibit line break following:
+        \hfil\vadjust{\nobreak}\break
+      \else
+        \space  % type on same line, so just followed by a space
+      \fi
+    \fi           % no return type
+    #3% output function name
+  }%
+  {\rm\enskip}% hskip 0.5 em of \rmfont
+  %
+  \boldbrax
+  % arguments will be output next, if any.
+}
+
+% Print arguments in slanted roman (not ttsl), inconsistently with using
+% tt for the name.  This is because literal text is sometimes needed in
+% the argument list (groff manual), and ttsl and tt are not very
+% distinguishable.  Prevent hyphenation at `-' chars.
+%
+\def\defunargs#1{%
+  % use sl by default (not ttsl),
+  % tt for the names.
+  \df \sl \hyphenchar\font=0
+  %
+  % On the other hand, if an argument has two dashes (for instance), we
+  % want a way to get ttsl.  We used to recommend @var for that, so
+  % leave the code in, but it's strange for @var to lead to typewriter.
+  % Nowadays we recommend @code, since the difference between a ttsl hyphen
+  % and a tt hyphen is pretty tiny.  @code also disables ?` !`.
+  \def\var##1{{\setregularquotes\ttslanted{##1}}}%
+  #1%
+  \sl\hyphenchar\font=45
+}
+
+% We want ()&[] to print specially on the defun line.
+%
+\def\activeparens{%
+  \catcode`\(=\active \catcode`\)=\active
+  \catcode`\[=\active \catcode`\]=\active
+  \catcode`\&=\active
+}
+
+% Make control sequences which act like normal parenthesis chars.
+\let\lparen = ( \let\rparen = )
+
+% Be sure that we always have a definition for `(', etc.  For example,
+% if the fn name has parens in it, \boldbrax will not be in effect yet,
+% so TeX would otherwise complain about undefined control sequence.
+{
+  \activeparens
+  \global\let(=\lparen \global\let)=\rparen
+  \global\let[=\lbrack \global\let]=\rbrack
+  \global\let& = \&
+
+  \gdef\boldbrax{\let(=\opnr\let)=\clnr\let[=\lbrb\let]=\rbrb}
+  \gdef\magicamp{\let&=\amprm}
+}
+\let\ampchar\&
+
+\newcount\parencount
+
+% If we encounter &foo, then turn on ()-hacking afterwards
+\newif\ifampseen
+\def\amprm#1 {\ampseentrue{\bf\&#1 }}
+
+\def\parenfont{%
+  \ifampseen
+    % At the first level, print parens in roman,
+    % otherwise use the default font.
+    \ifnum \parencount=1 \rm \fi
+  \else
+    % The \sf parens (in \boldbrax) actually are a little bolder than
+    % the contained text.  This is especially needed for [ and ] .
+    \sf
+  \fi
+}
+\def\infirstlevel#1{%
+  \ifampseen
+    \ifnum\parencount=1
+      #1%
+    \fi
+  \fi
+}
+\def\bfafterword#1 {#1 \bf}
+
+\def\opnr{%
+  \global\advance\parencount by 1
+  {\parenfont(}%
+  \infirstlevel \bfafterword
+}
+\def\clnr{%
+  {\parenfont)}%
+  \infirstlevel \sl
+  \global\advance\parencount by -1
+}
+
+\newcount\brackcount
+\def\lbrb{%
+  \global\advance\brackcount by 1
+  {\bf[}%
+}
+\def\rbrb{%
+  {\bf]}%
+  \global\advance\brackcount by -1
+}
+
+\def\checkparencounts{%
+  \ifnum\parencount=0 \else \badparencount \fi
+  \ifnum\brackcount=0 \else \badbrackcount \fi
+}
+% these should not use \errmessage; the glibc manual, at least, actually
+% has such constructs (when documenting function pointers).
+\def\badparencount{%
+  \message{Warning: unbalanced parentheses in @def...}%
+  \global\parencount=0
+}
+\def\badbrackcount{%
+  \message{Warning: unbalanced square brackets in @def...}%
+  \global\brackcount=0
+}
+
+
+\message{macros,}
+% @macro.
+
+% To do this right we need a feature of e-TeX, \scantokens,
+% which we arrange to emulate with a temporary file in ordinary TeX.
+\ifx\eTeXversion\thisisundefined
+  \newwrite\macscribble
+  \def\scantokens#1{%
+    \toks0={#1}%
+    \immediate\openout\macscribble=\jobname.tmp
+    \immediate\write\macscribble{\the\toks0}%
+    \immediate\closeout\macscribble
+    \input \jobname.tmp
+  }
+\fi
+
+\let\E=\expandafter
+
+% Used at the time of macro expansion.
+% Argument is macro body with arguments substituted
+\def\scanmacro#1{%
+  \newlinechar`\^^M
+  % expand the expansion of \eatleadingcr twice to maybe remove a leading
+  % newline (and \else and \fi tokens), then call \eatspaces on the result.
+  \def\xeatspaces##1{%
+    \E\E\E\E\E\E\E\eatspaces\E\E\E\E\E\E\E{\eatleadingcr##1%
+  }}%
+  \def\xempty##1{}%
+  %
+  % Process the macro body under the current catcode regime.
+  \scantokens{#1@comment}%
+  %
+  % The \comment is to remove the \newlinechar added by \scantokens, and
+  % can be noticed by \parsearg.  Note \c isn't used because this means cedilla
+  % in math mode.
+}
+
+% Used for copying and captions
+\def\scanexp#1{%
+  \expandafter\scanmacro\expandafter{#1}%
+}
+
+\newcount\paramno   % Count of parameters
+\newtoks\macname    % Macro name
+\newif\ifrecursive  % Is it recursive?
+
+% List of all defined macros in the form
+%    \commondummyword\macro1\commondummyword\macro2...
+% Currently is also contains all @aliases; the list can be split
+% if there is a need.
+\def\macrolist{}
+
+% Add the macro to \macrolist
+\def\addtomacrolist#1{\expandafter \addtomacrolistxxx \csname#1\endcsname}
+\def\addtomacrolistxxx#1{%
+     \toks0 = \expandafter{\macrolist\commondummyword#1}%
+     \xdef\macrolist{\the\toks0}%
+}
+
+% Utility routines.
+% This does \let #1 = #2, with \csnames; that is,
+%   \let \csname#1\endcsname = \csname#2\endcsname
+% (except of course we have to play expansion games).
+%
+\def\cslet#1#2{%
+  \expandafter\let
+  \csname#1\expandafter\endcsname
+  \csname#2\endcsname
+}
+
+% Trim leading and trailing spaces off a string.
+% Concepts from aro-bend problem 15 (see CTAN).
+{\catcode`\@=11
+\gdef\eatspaces #1{\expandafter\trim@\expandafter{#1 }}
+\gdef\trim@ #1{\trim@@ @#1 @ #1 @ @@}
+\gdef\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @}
+\def\unbrace#1{#1}
+\unbrace{\gdef\trim@@@ #1 } #2@{#1}
+}
+
+{\catcode`\^^M=\other%
+\gdef\eatleadingcr#1{\if\noexpand#1\noexpand^^M\else\E#1\fi}}%
+% Warning: this won't work for a delimited argument
+% or for an empty argument
+
+% Trim a single trailing ^^M off a string.
+{\catcode`\^^M=\other \catcode`\Q=3%
+\gdef\eatcr #1{\eatcra #1Q^^MQ}%
+\gdef\eatcra#1^^MQ{\eatcrb#1Q}%
+\gdef\eatcrb#1Q#2Q{#1}%
+}
+
+% Macro bodies are absorbed as an argument in a context where
+% all characters are catcode 10, 11 or 12, except \ which is active
+% (as in normal texinfo). It is necessary to change the definition of \
+% to recognize macro arguments; this is the job of \mbodybackslash.
+%
+% Non-ASCII encodings make 8-bit characters active, so un-activate
+% them to avoid their expansion.  Must do this non-globally, to
+% confine the change to the current group.
+%
+% It's necessary to have hard CRs when the macro is executed. This is
+% done by making ^^M (\endlinechar) catcode 12 when reading the macro
+% body, and then making it the \newlinechar in \scanmacro.
+%
+\def\scanctxt{% used as subroutine
+  \catcode`\"=\other
+  \catcode`\+=\other
+  \catcode`\<=\other
+  \catcode`\>=\other
+  \catcode`\^=\other
+  \catcode`\_=\other
+  \catcode`\|=\other
+  \catcode`\~=\other
+  \passthroughcharstrue
+}
+
+\def\scanargctxt{% used for copying and captions, not macros.
+  \scanctxt
+  \catcode`\@=\other
+  \catcode`\\=\other
+  \catcode`\^^M=\other
+}
+
+\def\macrobodyctxt{% used for @macro definitions
+  \scanctxt
+  \catcode`\ =\other
+  \catcode`\@=\other
+  \catcode`\{=\other
+  \catcode`\}=\other
+  \catcode`\^^M=\other
+  \usembodybackslash
+}
+
+% Used when scanning braced macro arguments.  Note, however, that catcode
+% changes here are ineffectual if the macro invocation was nested inside
+% an argument to another Texinfo command.
+\def\macroargctxt{%
+  \scanctxt
+  \catcode`\ =\active
+  \catcode`\@=\other
+  \catcode`\^^M=\other
+  \catcode`\\=\active
+}
+
+\def\macrolineargctxt{% used for whole-line arguments without braces
+  \scanctxt
+  \catcode`\@=\other
+  \catcode`\{=\other
+  \catcode`\}=\other
+}
+
+% \mbodybackslash is the definition of \ in @macro bodies.
+% It maps \foo\ => \csname macarg.foo\endcsname => #N
+% where N is the macro parameter number.
+% We define \csname macarg.\endcsname to be \realbackslash, so
+% \\ in macro replacement text gets you a backslash.
+%
+{\catcode`@=0 @catcode`@\=@active
+ @gdef@usembodybackslash{@let\=@mbodybackslash}
+ @gdef@mbodybackslash#1\{@csname macarg.#1@endcsname}
+}
+\expandafter\def\csname macarg.\endcsname{\realbackslash}
+
+\def\margbackslash#1{\char`\#1 }
+
+\def\macro{\recursivefalse\parsearg\macroxxx}
+\def\rmacro{\recursivetrue\parsearg\macroxxx}
+
+\def\macroxxx#1{%
+  \getargs{#1}% now \macname is the macname and \argl the arglist
+  \ifx\argl\empty       % no arguments
+     \paramno=0\relax
+  \else
+     \expandafter\parsemargdef \argl;%
+     \if\paramno>256\relax
+       \ifx\eTeXversion\thisisundefined
+         \errhelp = \EMsimple
+         \errmessage{You need eTeX to compile a file with macros with more than 256 arguments}
+       \fi
+     \fi
+  \fi
+  \if1\csname ismacro.\the\macname\endcsname
+     \message{Warning: redefining \the\macname}%
+  \else
+     \expandafter\ifx\csname \the\macname\endcsname \relax
+     \else \errmessage{Macro name \the\macname\space already defined}\fi
+     \global\cslet{macsave.\the\macname}{\the\macname}%
+     \global\expandafter\let\csname ismacro.\the\macname\endcsname=1%
+     \addtomacrolist{\the\macname}%
+  \fi
+  \begingroup \macrobodyctxt
+  \ifrecursive \expandafter\parsermacbody
+  \else \expandafter\parsemacbody
+  \fi}
+
+\parseargdef\unmacro{%
+  \if1\csname ismacro.#1\endcsname
+    \global\cslet{#1}{macsave.#1}%
+    \global\expandafter\let \csname ismacro.#1\endcsname=0%
+    % Remove the macro name from \macrolist:
+    \begingroup
+      \expandafter\let\csname#1\endcsname \relax
+      \let\commondummyword\unmacrodo
+      \xdef\macrolist{\macrolist}%
+    \endgroup
+  \else
+    \errmessage{Macro #1 not defined}%
+  \fi
+}
+
+% Called by \do from \dounmacro on each macro.  The idea is to omit any
+% macro definitions that have been changed to \relax.
+%
+\def\unmacrodo#1{%
+  \ifx #1\relax
+    % remove this
+  \else
+    \noexpand\commondummyword \noexpand#1%
+  \fi
+}
+
+% \getargs -- Parse the arguments to a @macro line.  Set \macname to
+% the name of the macro, and \argl to the braced argument list.
+\def\getargs#1{\getargsxxx#1{}}
+\def\getargsxxx#1#{\getmacname #1 \relax\getmacargs}
+\def\getmacname#1 #2\relax{\macname={#1}}
+\def\getmacargs#1{\def\argl{#1}}
+% This made use of the feature that if the last token of a
+% <parameter list> is #, then the preceding argument is delimited by
+% an opening brace, and that opening brace is not consumed.
+
+% Parse the optional {params} list to @macro or @rmacro.
+% Set \paramno to the number of arguments,
+% and \paramlist to a parameter text for the macro (e.g. #1,#2,#3 for a
+% three-param macro.)  Define \macarg.BLAH for each BLAH in the params
+% list to some hook where the argument is to be expanded.  If there are
+% less than 10 arguments that hook is to be replaced by ##N where N
+% is the position in that list, that is to say the macro arguments are to be
+% defined `a la TeX in the macro body.
+%
+% That gets used by \mbodybackslash (above).
+%
+% If there are 10 or more arguments, a different technique is used: see
+% \parsemmanyargdef.
+%
+\def\parsemargdef#1;{%
+  \paramno=0\def\paramlist{}%
+  \let\hash\relax
+  % \hash is redefined to `#' later to get it into definitions
+  \let\xeatspaces\relax
+  \let\xempty\relax
+  \parsemargdefxxx#1,;,%
+  \ifnum\paramno<10\relax\else
+    \paramno0\relax
+    \parsemmanyargdef@@#1,;,% 10 or more arguments
+  \fi
+}
+\def\parsemargdefxxx#1,{%
+  \if#1;\let\next=\relax
+  \else \let\next=\parsemargdefxxx
+    \advance\paramno by 1
+    \expandafter\edef\csname macarg.\eatspaces{#1}\endcsname
+        {\xeatspaces{\hash\the\paramno\noexpand\xempty{}}}%
+    \edef\paramlist{\paramlist\hash\the\paramno,}%
+  \fi\next}
+% the \xempty{} is to give \eatleadingcr an argument in the case of an
+% empty macro argument.
+
+% \parsemacbody, \parsermacbody
+%
+% Read recursive and nonrecursive macro bodies. (They're different since
+% rec and nonrec macros end differently.)
+%
+% We are in \macrobodyctxt, and the \xdef causes backslashshes in the macro
+% body to be transformed.
+% Set \macrobody to the body of the macro, and call \defmacro.
+%
+{\catcode`\ =\other\long\gdef\parsemacbody#1@end macro{%
+\xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}%
+{\catcode`\ =\other\long\gdef\parsermacbody#1@end rmacro{%
+\xdef\macrobody{\eatcr{#1}}\endgroup\defmacro}}%
+
+% Make @ a letter, so that we can make private-to-Texinfo macro names.
+\edef\texiatcatcode{\the\catcode`\@}
+\catcode `@=11\relax
+
+%%%%%%%%%%%%%% Code for > 10 arguments only   %%%%%%%%%%%%%%%%%%
+
+% If there are 10 or more arguments, a different technique is used, where the
+% hook remains in the body, and when macro is to be expanded the body is
+% processed again to replace the arguments.
+%
+% In that case, the hook is \the\toks N-1, and we simply set \toks N-1 to the
+% argument N value and then \edef the body (nothing else will expand because of
+% the catcode regime under which the body was input).
+%
+% If you compile with TeX (not eTeX), and you have macros with 10 or more
+% arguments, no macro can have more than 256 arguments (else error).
+%
+% In case that there are 10 or more arguments we parse again the arguments
+% list to set new definitions for the \macarg.BLAH macros corresponding to
+% each BLAH argument. It was anyhow needed to parse already once this list
+% in order to count the arguments, and as macros with at most 9 arguments
+% are by far more frequent than macro with 10 or more arguments, defining
+% twice the \macarg.BLAH macros does not cost too much processing power.
+\def\parsemmanyargdef@@#1,{%
+  \if#1;\let\next=\relax
+  \else
+    \let\next=\parsemmanyargdef@@
+    \edef\tempb{\eatspaces{#1}}%
+    \expandafter\def\expandafter\tempa
+       \expandafter{\csname macarg.\tempb\endcsname}%
+    % Note that we need some extra \noexpand\noexpand, this is because we
+    % don't want \the  to be expanded in the \parsermacbody  as it uses an
+    % \xdef .
+    \expandafter\edef\tempa
+      {\noexpand\noexpand\noexpand\the\toks\the\paramno}%
+    \advance\paramno by 1\relax
+  \fi\next}
+
+
+\let\endargs@\relax
+\let\nil@\relax
+\def\nilm@{\nil@}%
+\long\def\nillm@{\nil@}%
+
+% This macro is expanded during the Texinfo macro expansion, not during its
+% definition.  It gets all the arguments' values and assigns them to macros
+% macarg.ARGNAME
+%
+% #1 is the macro name
+% #2 is the list of argument names
+% #3 is the list of argument values
+\def\getargvals@#1#2#3{%
+  \def\macargdeflist@{}%
+  \def\saveparamlist@{#2}% Need to keep a copy for parameter expansion.
+  \def\paramlist{#2,\nil@}%
+  \def\macroname{#1}%
+  \begingroup
+  \macroargctxt
+  \def\argvaluelist{#3,\nil@}%
+  \def\@tempa{#3}%
+  \ifx\@tempa\empty
+    \setemptyargvalues@
+  \else
+    \getargvals@@
+  \fi
+}
+\def\getargvals@@{%
+  \ifx\paramlist\nilm@
+      % Some sanity check needed here that \argvaluelist is also empty.
+      \ifx\argvaluelist\nillm@
+      \else
+        \errhelp = \EMsimple
+        \errmessage{Too many arguments in macro `\macroname'!}%
+      \fi
+      \let\next\macargexpandinbody@
+  \else
+    \ifx\argvaluelist\nillm@
+       % No more arguments values passed to macro.  Set remaining named-arg
+       % macros to empty.
+       \let\next\setemptyargvalues@
+    \else
+      % pop current arg name into \@tempb
+      \def\@tempa##1{\pop@{\@tempb}{\paramlist}##1\endargs@}%
+      \expandafter\@tempa\expandafter{\paramlist}%
+       % pop current argument value into \@tempc
+      \def\@tempa##1{\longpop@{\@tempc}{\argvaluelist}##1\endargs@}%
+      \expandafter\@tempa\expandafter{\argvaluelist}%
+       % Here \@tempb is the current arg name and \@tempc is the current arg value.
+       % First place the new argument macro definition into \@tempd
+       \expandafter\macname\expandafter{\@tempc}%
+       \expandafter\let\csname macarg.\@tempb\endcsname\relax
+       \expandafter\def\expandafter\@tempe\expandafter{%
+         \csname macarg.\@tempb\endcsname}%
+       \edef\@tempd{\long\def\@tempe{\the\macname}}%
+       \push@\@tempd\macargdeflist@
+       \let\next\getargvals@@
+    \fi
+  \fi
+  \next
+}
+
+\def\push@#1#2{%
+  \expandafter\expandafter\expandafter\def
+  \expandafter\expandafter\expandafter#2%
+  \expandafter\expandafter\expandafter{%
+  \expandafter#1#2}%
+}
+
+% Replace arguments by their values in the macro body, and place the result
+% in macro \@tempa.
+%
+\def\macvalstoargs@{%
+  %  To do this we use the property that token registers that are \the'ed
+  % within an \edef  expand only once. So we are going to place all argument
+  % values into respective token registers.
+  %
+  % First we save the token context, and initialize argument numbering.
+  \begingroup
+    \paramno0\relax
+    % Then, for each argument number #N, we place the corresponding argument
+    % value into a new token list register \toks#N
+    \expandafter\putargsintokens@\saveparamlist@,;,%
+    % Then, we expand the body so that argument are replaced by their
+    % values. The trick for values not to be expanded themselves is that they
+    % are within tokens and that tokens expand only once in an \edef .
+    \edef\@tempc{\csname mac.\macroname .body\endcsname}%
+    % Now we restore the token stack pointer to free the token list registers
+    % which we have used, but we make sure that expanded body is saved after
+    % group.
+    \expandafter
+  \endgroup
+  \expandafter\def\expandafter\@tempa\expandafter{\@tempc}%
+  }
+
+% Define the named-macro outside of this group and then close this group.
+%
+\def\macargexpandinbody@{%
+  \expandafter
+  \endgroup
+  \macargdeflist@
+  % First the replace in body the macro arguments by their values, the result
+  % is in \@tempa .
+  \macvalstoargs@
+  % Then we point at the \norecurse or \gobble (for recursive) macro value
+  % with \@tempb .
+  \expandafter\let\expandafter\@tempb\csname mac.\macroname .recurse\endcsname
+  % Depending on whether it is recursive or not, we need some tailing
+  % \egroup .
+  \ifx\@tempb\gobble
+     \let\@tempc\relax
+  \else
+     \let\@tempc\egroup
+  \fi
+  % And now we do the real job:
+  \edef\@tempd{\noexpand\@tempb{\macroname}\noexpand\scanmacro{\@tempa}\@tempc}%
+  \@tempd
+}
+
+\def\putargsintokens@#1,{%
+  \if#1;\let\next\relax
+  \else
+    \let\next\putargsintokens@
+    % First we allocate the new token list register, and give it a temporary
+    % alias \@tempb .
+    \toksdef\@tempb\the\paramno
+    % Then we place the argument value into that token list register.
+    \expandafter\let\expandafter\@tempa\csname macarg.#1\endcsname
+    \expandafter\@tempb\expandafter{\@tempa}%
+    \advance\paramno by 1\relax
+  \fi
+  \next
+}
+
+% Trailing missing arguments are set to empty.
+%
+\def\setemptyargvalues@{%
+  \ifx\paramlist\nilm@
+    \let\next\macargexpandinbody@
+  \else
+    \expandafter\setemptyargvaluesparser@\paramlist\endargs@
+    \let\next\setemptyargvalues@
+  \fi
+  \next
+}
+
+\def\setemptyargvaluesparser@#1,#2\endargs@{%
+  \expandafter\def\expandafter\@tempa\expandafter{%
+    \expandafter\def\csname macarg.#1\endcsname{}}%
+  \push@\@tempa\macargdeflist@
+  \def\paramlist{#2}%
+}
+
+% #1 is the element target macro
+% #2 is the list macro
+% #3,#4\endargs@ is the list value
+\def\pop@#1#2#3,#4\endargs@{%
+   \def#1{#3}%
+   \def#2{#4}%
+}
+\long\def\longpop@#1#2#3,#4\endargs@{%
+   \long\def#1{#3}%
+   \long\def#2{#4}%
+}
+
+
+%%%%%%%%%%%%%% End of code for > 10 arguments %%%%%%%%%%%%%%%%%%
+
+
+% This defines a Texinfo @macro or @rmacro, called by \parsemacbody.
+%    \macrobody has the body of the macro in it, with placeholders for
+% its parameters, looking like "\xeatspaces{\hash 1}".
+%    \paramno is the number of parameters
+%    \paramlist is a TeX parameter text, e.g. "#1,#2,#3,"
+% There are four cases: macros of zero, one, up to nine, and many arguments.
+% \xdef is used so that macro definitions will survive the file
+% they're defined in: @include reads the file inside a group.
+%
+\def\defmacro{%
+  \let\hash=##% convert placeholders to macro parameter chars
+  \ifnum\paramno=1
+    \def\xeatspaces##1{##1}%
+    % This removes the pair of braces around the argument.  We don't
+    % use \eatspaces, because this can cause ends of lines to be lost
+    % when the argument to \eatspaces is read, leading to line-based
+    % commands like "@itemize" not being read correctly.
+  \else
+    \let\xeatspaces\relax % suppress expansion
+  \fi
+  \ifcase\paramno
+  % 0
+    \expandafter\xdef\csname\the\macname\endcsname{%
+      \bgroup
+        \noexpand\spaceisspace
+        \noexpand\endlineisspace
+        \noexpand\expandafter % skip any whitespace after the macro name.
+        \expandafter\noexpand\csname\the\macname @@@\endcsname}%
+    \expandafter\xdef\csname\the\macname @@@\endcsname{%
+      \egroup
+      \noexpand\scanmacro{\macrobody}}%
+  \or % 1
+    \expandafter\xdef\csname\the\macname\endcsname{%
+       \bgroup
+       \noexpand\braceorline
+       \expandafter\noexpand\csname\the\macname @@@\endcsname}%
+    \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
+      \egroup
+      \noexpand\scanmacro{\macrobody}%
+      }%
+  \else % at most 9
+    \ifnum\paramno<10\relax
+      % @MACNAME sets the context for reading the macro argument
+      % @MACNAME@@ gets the argument, processes backslashes and appends a
+      % comma.
+      % @MACNAME@@@ removes braces surrounding the argument list.
+      % @MACNAME@@@@ scans the macro body with arguments substituted.
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \bgroup
+        \noexpand\expandafter  % This \expandafter skip any spaces after the
+        \noexpand\macroargctxt % macro before we change the catcode of space.
+        \noexpand\expandafter
+        \expandafter\noexpand\csname\the\macname @@\endcsname}%
+      \expandafter\xdef\csname\the\macname @@\endcsname##1{%
+          \noexpand\passargtomacro
+          \expandafter\noexpand\csname\the\macname @@@\endcsname{##1,}}%
+      \expandafter\xdef\csname\the\macname @@@\endcsname##1{%
+          \expandafter\noexpand\csname\the\macname @@@@\endcsname ##1}%
+      \expandafter\expandafter
+      \expandafter\xdef
+      \expandafter\expandafter
+        \csname\the\macname @@@@\endcsname\paramlist{%
+          \egroup\noexpand\scanmacro{\macrobody}}%
+    \else % 10 or more:
+      \expandafter\xdef\csname\the\macname\endcsname{%
+        \noexpand\getargvals@{\the\macname}{\argl}%
+      }%
+      \global\expandafter\let\csname mac.\the\macname .body\endcsname\macrobody
+      \global\expandafter\let\csname mac.\the\macname .recurse\endcsname\gobble
+    \fi
+  \fi}
+
+\catcode `\@\texiatcatcode\relax % end private-to-Texinfo catcodes
+
+\def\norecurse#1{\bgroup\cslet{#1}{macsave.#1}}
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+{\catcode`\@=0 \catcode`\\=13  % We need to manipulate \ so use @ as escape
+@catcode`@_=11  % private names
+@catcode`@!=11  % used as argument separator
+
+% \passargtomacro#1#2 -
+% Call #1 with a list of tokens #2, with any doubled backslashes in #2
+% compressed to one.
+%
+% This implementation works by expansion, and not execution (so we cannot use
+% \def or similar).  This reduces the risk of this failing in contexts where
+% complete expansion is done with no execution (for example, in writing out to
+% an auxiliary file for an index entry).
+%
+% State is kept in the input stream: the argument passed to
+% @look_ahead, @gobble_and_check_finish and @add_segment is
+%
+% THE_MACRO ARG_RESULT ! {PENDING_BS} NEXT_TOKEN  (... rest of input)
+%
+% where:
+% THE_MACRO - name of the macro we want to call
+% ARG_RESULT - argument list we build to pass to that macro
+% PENDING_BS - either a backslash or nothing
+% NEXT_TOKEN - used to look ahead in the input stream to see what's coming next
+
+@gdef@passargtomacro#1#2{%
+  @add_segment #1!{}@relax#2\@_finish\%
+}
+@gdef@_finish{@_finishx} @global@let@_finishx@relax
+
+% #1 - THE_MACRO ARG_RESULT
+% #2 - PENDING_BS
+% #3 - NEXT_TOKEN
+% #4 used to look ahead
+%
+% If the next token is not a backslash, process the rest of the argument;
+% otherwise, remove the next token.
+@gdef@look_ahead#1!#2#3#4{%
+  @ifx#4\%
+   @expandafter@gobble_and_check_finish
+  @else
+   @expandafter@add_segment
+  @fi#1!{#2}#4#4%
+}
+
+% #1 - THE_MACRO ARG_RESULT
+% #2 - PENDING_BS
+% #3 - NEXT_TOKEN
+% #4 should be a backslash, which is gobbled.
+% #5 looks ahead
+%
+% Double backslash found.  Add a single backslash, and look ahead.
+@gdef@gobble_and_check_finish#1!#2#3#4#5{%
+  @add_segment#1\!{}#5#5%
+}
+
+@gdef@is_fi{@fi}
+
+% #1 - THE_MACRO ARG_RESULT
+% #2 - PENDING_BS
+% #3 - NEXT_TOKEN
+% #4 is input stream until next backslash
+%
+% Input stream is either at the start of the argument, or just after a
+% backslash sequence, either a lone backslash, or a doubled backslash.
+% NEXT_TOKEN contains the first token in the input stream: if it is \finish,
+% finish; otherwise, append to ARG_RESULT the segment of the argument up until
+% the next backslash.  PENDING_BACKSLASH contains a backslash to represent
+% a backslash just before the start of the input stream that has not been
+% added to ARG_RESULT.
+@gdef@add_segment#1!#2#3#4\{%
+@ifx#3@_finish
+  @call_the_macro#1!%
+@else
+  % append the pending backslash to the result, followed by the next segment
+  @expandafter@is_fi@look_ahead#1#2#4!{\}@fi
+  % this @fi is discarded by @look_ahead.
+  % we can't get rid of it with \expandafter because we don't know how
+  % long #4 is.
+}
+
+% #1 - THE_MACRO
+% #2 - ARG_RESULT
+% #3 discards the res of the conditional in @add_segment, and @is_fi ends the
+% conditional.
+@gdef@call_the_macro#1#2!#3@fi{@is_fi #1{#2}}
+
+}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% \braceorline MAC is used for a one-argument macro MAC.  It checks
+% whether the next non-whitespace character is a {.  It sets the context
+% for reading the argument (slightly different in the two cases).  Then,
+% to read the argument, in the whole-line case, it then calls the regular
+% \parsearg MAC; in the lbrace case, it calls \passargtomacro MAC.
+%
+\def\braceorline#1{\let\macnamexxx=#1\futurelet\nchar\braceorlinexxx}
+\def\braceorlinexxx{%
+  \ifx\nchar\bgroup
+    \macroargctxt
+    \expandafter\passargtomacro
+  \else
+    \macrolineargctxt\expandafter\parsearg
+  \fi \macnamexxx}
+
+
+% @alias.
+% We need some trickery to remove the optional spaces around the equal
+% sign.  Make them active and then expand them all to nothing.
+%
+\def\alias{\parseargusing\obeyspaces\aliasxxx}
+\def\aliasxxx #1{\aliasyyy#1\relax}
+\def\aliasyyy #1=#2\relax{%
+  {%
+    \expandafter\let\obeyedspace=\empty
+    \addtomacrolist{#1}%
+    \xdef\next{\global\let\makecsname{#1}=\makecsname{#2}}%
+  }%
+  \next
+}
+
+
+\message{cross references,}
+
+\newwrite\auxfile
+\newif\ifhavexrefs    % True if xref values are known.
+\newif\ifwarnedxrefs  % True if we warned once that they aren't known.
+
+% @inforef is relatively simple.
+\def\inforef #1{\inforefzzz #1,,,,**}
+\def\inforefzzz #1,#2,#3,#4**{%
+  \putwordSee{} \putwordInfo{} \putwordfile{} \file{\ignorespaces #3{}},
+  node \samp{\ignorespaces#1{}}}
+
+% @node's only job in TeX is to define \lastnode, which is used in
+% cross-references.  The @node line might or might not have commas, and
+% might or might not have spaces before the first comma, like:
+% @node foo , bar , ...
+% We don't want such trailing spaces in the node name.
+%
+\parseargdef\node{\checkenv{}\donode #1 ,\finishnodeparse}
+%
+% also remove a trailing comma, in case of something like this:
+% @node Help-Cross,  ,  , Cross-refs
+\def\donode#1 ,#2\finishnodeparse{\dodonode #1,\finishnodeparse}
+\def\dodonode#1,#2\finishnodeparse{\gdef\lastnode{#1}\omittopnode}
+
+% Used so that the @top node doesn't have to be wrapped in an @ifnottex
+% conditional.
+% \doignore goes to more effort to skip nested conditionals but we don't need
+% that here.
+\def\omittopnode{%
+   \ifx\lastnode\wordTop
+   \expandafter\ignorenode\fi
+}
+\def\wordTop{Top}
+
+% Until the next @node or @bye command, divert output to a box that is not
+% output.
+\def\ignorenode{\setbox\dummybox\vbox\bgroup\def\node{\egroup\node}%
+\ignorenodebye
+}
+
+{\let\bye\relax
+\gdef\ignorenodebye{\let\bye\ignorenodebyedef}
+\gdef\ignorenodebyedef{\egroup(`Top' node ignored)\bye}}
+% The redefinition of \bye here is because it is declared \outer
+
+\let\lastnode=\empty
+
+% Write a cross-reference definition for the current node.  #1 is the
+% type (Ynumbered, Yappendix, Ynothing).
+%
+\def\donoderef#1{%
+  \ifx\lastnode\empty\else
+    \setref{\lastnode}{#1}%
+    \global\let\lastnode=\empty
+  \fi
+}
+
+% @anchor{NAME} -- define xref target at arbitrary point.
+%
+\newcount\savesfregister
+%
+\def\savesf{\relax \ifhmode \savesfregister=\spacefactor \fi}
+\def\restoresf{\relax \ifhmode \spacefactor=\savesfregister \fi}
+\def\anchor#1{\savesf \setref{#1}{Ynothing}\restoresf \ignorespaces}
+
+% \setref{NAME}{SNT} defines a cross-reference point NAME (a node or an
+% anchor), which consists of three parts:
+% 1) NAME-title - the current sectioning name taken from \currentsection,
+%                 or the anchor name.
+% 2) NAME-snt   - section number and type, passed as the SNT arg, or
+%                 empty for anchors.
+% 3) NAME-pg    - the page number.
+%
+% This is called from \donoderef, \anchor, and \dofloat.  In the case of
+% floats, there is an additional part, which is not written here:
+% 4) NAME-lof   - the text as it should appear in a @listoffloats.
+%
+\def\setref#1#2{%
+  \pdfmkdest{#1}%
+  \iflinks
+    {%
+      \requireauxfile
+      \atdummies  % preserve commands, but don't expand them
+      % match definition in \xrdef, \refx, \xrefX.
+      \def\value##1{##1}%
+      \edef\writexrdef##1##2{%
+       \write\auxfile{@xrdef{#1-% #1 of \setref, expanded by the \edef
+         ##1}{##2}}% these are parameters of \writexrdef
+      }%
+      \toks0 = \expandafter{\currentsection}%
+      \immediate \writexrdef{title}{\the\toks0 }%
+      \immediate \writexrdef{snt}{\csname #2\endcsname}% \Ynumbered etc.
+      \safewhatsit{\writexrdef{pg}{\folio}}% will be written later, at \shipout
+    }%
+  \fi
+}
+
+% @xrefautosectiontitle on|off says whether @section(ing) names are used
+% automatically in xrefs, if the third arg is not explicitly specified.
+% This was provided as a "secret" @set xref-automatic-section-title
+% variable, now it's official.
+%
+\parseargdef\xrefautomaticsectiontitle{%
+  \def\temp{#1}%
+  \ifx\temp\onword
+    \expandafter\let\csname SETxref-automatic-section-title\endcsname
+      = \empty
+  \else\ifx\temp\offword
+    \expandafter\let\csname SETxref-automatic-section-title\endcsname
+      = \relax
+  \else
+    \errhelp = \EMsimple
+    \errmessage{Unknown @xrefautomaticsectiontitle value `\temp',
+                must be on|off}%
+  \fi\fi
+}
+
+%
+% @xref, @pxref, and @ref generate cross-references.  For \xrefX, #1 is
+% the node name, #2 the name of the Info cross-reference, #3 the printed
+% node name, #4 the name of the Info file, #5 the name of the printed
+% manual.  All but the node name can be omitted.
+%
+\def\pxref{\putwordsee{} \xrefXX}
+\def\xref{\putwordSee{} \xrefXX}
+\def\ref{\xrefXX}
+
+\def\xrefXX#1{\def\xrefXXarg{#1}\futurelet\tokenafterxref\xrefXXX}
+\def\xrefXXX{\expandafter\xrefX\expandafter[\xrefXXarg,,,,,,,]}
+%
+\newbox\toprefbox
+\newbox\printedrefnamebox
+\newbox\infofilenamebox
+\newbox\printedmanualbox
+%
+\def\xrefX[#1,#2,#3,#4,#5,#6]{\begingroup
+  \unsepspaces
+  %
+  % Get args without leading/trailing spaces.
+  \def\printedrefname{\ignorespaces #3}%
+  \setbox\printedrefnamebox = \hbox{\printedrefname\unskip}%
+  %
+  \def\infofilename{\ignorespaces #4}%
+  \setbox\infofilenamebox = \hbox{\infofilename\unskip}%
+  %
+  \def\printedmanual{\ignorespaces #5}%
+  \setbox\printedmanualbox  = \hbox{\printedmanual\unskip}%
+  %
+  % If the printed reference name (arg #3) was not explicitly given in
+  % the @xref, figure out what we want to use.
+  \ifdim \wd\printedrefnamebox = 0pt
+    % No printed node name was explicitly given.
+    \expandafter\ifx\csname SETxref-automatic-section-title\endcsname \relax
+      % Not auto section-title: use node name inside the square brackets.
+      \def\printedrefname{\ignorespaces #1}%
+    \else
+      % Auto section-title: use chapter/section title inside
+      % the square brackets if we have it.
+      \ifdim \wd\printedmanualbox > 0pt
+        % It is in another manual, so we don't have it; use node name.
+        \def\printedrefname{\ignorespaces #1}%
+      \else
+        \ifhavexrefs
+          % We (should) know the real title if we have the xref values.
+          \def\printedrefname{\refx{#1-title}}%
+        \else
+          % Otherwise just copy the Info node name.
+          \def\printedrefname{\ignorespaces #1}%
+        \fi%
+      \fi
+    \fi
+  \fi
+  %
+  % Make link in pdf output.
+  \ifpdf
+    % For pdfTeX and LuaTeX
+    {\indexnofonts
+     \makevalueexpandable
+     \turnoffactive
+     % This expands tokens, so do it after making catcode changes, so _
+     % etc. don't get their TeX definitions.  This ignores all spaces in
+     % #4, including (wrongly) those in the middle of the filename.
+     \getfilename{#4}%
+     %
+     % This (wrongly) does not take account of leading or trailing
+     % spaces in #1, which should be ignored.
+     \setpdfdestname{#1}%
+     %
+     \ifx\pdfdestname\empty
+       \def\pdfdestname{Top}% no empty targets
+     \fi
+     %
+     \leavevmode
+     \startlink attr{/Border [0 0 0]}%
+     \ifnum\filenamelength>0
+       goto file{\the\filename.pdf} name{\pdfdestname}%
+     \else
+       goto name{\pdfmkpgn{\pdfdestname}}%
+     \fi
+    }%
+    \setcolor{\linkcolor}%
+  \else
+    \ifx\XeTeXrevision\thisisundefined
+    \else
+      % For XeTeX
+      {\indexnofonts
+       \makevalueexpandable
+       \turnoffactive
+       % This expands tokens, so do it after making catcode changes, so _
+       % etc. don't get their TeX definitions.  This ignores all spaces in
+       % #4, including (wrongly) those in the middle of the filename.
+       \getfilename{#4}%
+       %
+       % This (wrongly) does not take account of leading or trailing
+       % spaces in #1, which should be ignored.
+       \setpdfdestname{#1}%
+       %
+       \ifx\pdfdestname\empty
+         \def\pdfdestname{Top}% no empty targets
+       \fi
+       %
+       \leavevmode
+       \ifnum\filenamelength>0
+         % With default settings,
+         % XeTeX (xdvipdfmx) replaces link destination names with integers.
+         % In this case, the replaced destination names of
+         % remote PDFs are no longer known.  In order to avoid a replacement,
+         % you can use xdvipdfmx's command line option `-C 0x0010'.
+         % If you use XeTeX 0.99996+ (TeX Live 2016+),
+         % this command line option is no longer necessary
+         % because we can use the `dvipdfmx:config' special.
+         \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A
+           << /S /GoToR /F (\the\filename.pdf) /D (\pdfdestname) >> >>}%
+       \else
+         \special{pdf:bann << /Border [0 0 0] /Type /Annot /Subtype /Link /A
+           << /S /GoTo /D (\pdfdestname) >> >>}%
+       \fi
+      }%
+      \setcolor{\linkcolor}%
+    \fi
+  \fi
+  {%
+    % Have to otherify everything special to allow the \csname to
+    % include an _ in the xref name, etc.
+    \indexnofonts
+    \turnoffactive
+    \def\value##1{##1}%
+    \expandafter\global\expandafter\let\expandafter\Xthisreftitle
+      \csname XR#1-title\endcsname
+  }%
+  %
+  % Float references are printed completely differently: "Figure 1.2"
+  % instead of "[somenode], p.3".  \iffloat distinguishes them by
+  % \Xthisreftitle being set to a magic string.
+  \iffloat\Xthisreftitle
+    % If the user specified the print name (third arg) to the ref,
+    % print it instead of our usual "Figure 1.2".
+    \ifdim\wd\printedrefnamebox = 0pt
+      \refx{#1-snt}%
+    \else
+      \printedrefname
+    \fi
+    %
+    % If the user also gave the printed manual name (fifth arg), append
+    % "in MANUALNAME".
+    \ifdim \wd\printedmanualbox > 0pt
+      \space \putwordin{} \cite{\printedmanual}%
+    \fi
+  \else
+    % node/anchor (non-float) references.
+    %
+    % If we use \unhbox to print the node names, TeX does not insert
+    % empty discretionaries after hyphens, which means that it will not
+    % find a line break at a hyphen in a node names.  Since some manuals
+    % are best written with fairly long node names, containing hyphens,
+    % this is a loss.  Therefore, we give the text of the node name
+    % again, so it is as if TeX is seeing it for the first time.
+    %
+    \ifdim \wd\printedmanualbox > 0pt
+      % Cross-manual reference with a printed manual name.
+      %
+      \crossmanualxref{\cite{\printedmanual\unskip}}%
+    %
+    \else\ifdim \wd\infofilenamebox > 0pt
+      % Cross-manual reference with only an info filename (arg 4), no
+      % printed manual name (arg 5).  This is essentially the same as
+      % the case above; we output the filename, since we have nothing else.
+      %
+      \crossmanualxref{\code{\infofilename\unskip}}%
+    %
+    \else
+      % Reference within this manual.
+      %
+      % Only output a following space if the -snt ref is nonempty, as the ref
+      % will be empty for @unnumbered and @anchor.
+      \setbox2 = \hbox{\ignorespaces \refx{#1-snt}}%
+      \ifdim \wd2 > 0pt \refx{#1-snt}\space\fi
+      %
+      % output the `[mynode]' via the macro below so it can be overridden.
+      \xrefprintnodename\printedrefname
+      %
+      \expandafter\ifx\csname SETtxiomitxrefpg\endcsname\relax
+        % But we always want a comma and a space:
+        ,\space
+        %
+        % output the `page 3'.
+        \turnoffactive \putwordpage\tie\refx{#1-pg}%
+        % Add a , if xref followed by a space
+        \if\space\noexpand\tokenafterxref ,%
+        \else\ifx\     \tokenafterxref ,% @TAB
+        \else\ifx\*\tokenafterxref ,%   @*
+        \else\ifx\ \tokenafterxref ,%   @SPACE
+        \else\ifx\
+                  \tokenafterxref ,%    @NL
+        \else\ifx\tie\tokenafterxref ,% @tie
+        \fi\fi\fi\fi\fi\fi
+      \fi
+    \fi\fi
+  \fi
+  \endlink
+\endgroup}
+
+% Output a cross-manual xref to #1.  Used just above (twice).
+%
+% Only include the text "Section ``foo'' in" if the foo is neither
+% missing or Top.  Thus, @xref{,,,foo,The Foo Manual} outputs simply
+% "see The Foo Manual", the idea being to refer to the whole manual.
+%
+% But, this being TeX, we can't easily compare our node name against the
+% string "Top" while ignoring the possible spaces before and after in
+% the input.  By adding the arbitrary 7sp below, we make it much less
+% likely that a real node name would have the same width as "Top" (e.g.,
+% in a monospaced font).  Hopefully it will never happen in practice.
+%
+% For the same basic reason, we retypeset the "Top" at every
+% reference, since the current font is indeterminate.
+%
+\def\crossmanualxref#1{%
+  \setbox\toprefbox = \hbox{Top\kern7sp}%
+  \setbox2 = \hbox{\ignorespaces \printedrefname \unskip \kern7sp}%
+  \ifdim \wd2 > 7sp  % nonempty?
+    \ifdim \wd2 = \wd\toprefbox \else  % same as Top?
+      \putwordSection{} ``\printedrefname'' \putwordin{}\space
+    \fi
+  \fi
+  #1%
+}
+
+% This macro is called from \xrefX for the `[nodename]' part of xref
+% output.  It's a separate macro only so it can be changed more easily,
+% since square brackets don't work well in some documents.  Particularly
+% one that Bob is working on :).
+%
+\def\xrefprintnodename#1{[#1]}
+
+% Things referred to by \setref.
+%
+\def\Ynothing{}
+\def\Yomitfromtoc{}
+\def\Ynumbered{%
+  \ifnum\secno=0
+    \putwordChapter@tie \the\chapno
+  \else \ifnum\subsecno=0
+    \putwordSection@tie \the\chapno.\the\secno
+  \else \ifnum\subsubsecno=0
+    \putwordSection@tie \the\chapno.\the\secno.\the\subsecno
+  \else
+    \putwordSection@tie \the\chapno.\the\secno.\the\subsecno.\the\subsubsecno
+  \fi\fi\fi
+}
+\def\Yappendix{%
+  \ifnum\secno=0
+     \putwordAppendix@tie @char\the\appendixno{}%
+  \else \ifnum\subsecno=0
+     \putwordSection@tie @char\the\appendixno.\the\secno
+  \else \ifnum\subsubsecno=0
+    \putwordSection@tie @char\the\appendixno.\the\secno.\the\subsecno
+  \else
+    \putwordSection@tie
+      @char\the\appendixno.\the\secno.\the\subsecno.\the\subsubsecno
+  \fi\fi\fi
+}
+
+% \refx{NAME} - reference a cross-reference string named NAME.
+\def\refx#1{%
+  \requireauxfile
+  {%
+    \indexnofonts
+    \turnoffactive
+    \def\value##1{##1}%
+    \expandafter\global\expandafter\let\expandafter\thisrefX
+      \csname XR#1\endcsname
+  }%
+  \ifx\thisrefX\relax
+    % If not defined, say something at least.
+    \angleleft un\-de\-fined\angleright
+    \iflinks
+      \ifhavexrefs
+        {\toks0 = {#1}% avoid expansion of possibly-complex value
+         \message{\linenumber Undefined cross reference `\the\toks0'.}}%
+      \else
+        \ifwarnedxrefs\else
+          \global\warnedxrefstrue
+          \message{Cross reference values unknown; you must run TeX again.}%
+        \fi
+      \fi
+    \fi
+  \else
+    % It's defined, so just use it.
+    \thisrefX
+  \fi
+}
+
+% This is the macro invoked by entries in the aux file.  Define a control
+% sequence for a cross-reference target (we prepend XR to the control sequence
+% name to avoid collisions).  The value is the page number.  If this is a float
+% type, we have more work to do.
+%
+\def\xrdef#1#2{%
+  {% Expand the node or anchor name to remove control sequences.
+   % \turnoffactive stops 8-bit characters being changed to commands
+   % like @'e.  \refx does the same to retrieve the value in the definition.
+    \indexnofonts
+    \turnoffactive
+    \def\value##1{##1}%
+    \xdef\safexrefname{#1}%
+  }%
+  %
+  \bgroup
+    \expandafter\gdef\csname XR\safexrefname\endcsname{#2}%
+  \egroup
+  % We put the \gdef inside a group to avoid the definitions building up on
+  % TeX's save stack, which can cause it to run out of space for aux files with
+  % thousands of lines.  \gdef doesn't use the save stack, but \csname does
+  % when it defines an unknown control sequence as \relax.
+  %
+  % Was that xref control sequence that we just defined for a float?
+  \expandafter\iffloat\csname XR\safexrefname\endcsname
+    % it was a float, and we have the (safe) float type in \iffloattype.
+    \expandafter\let\expandafter\floatlist
+      \csname floatlist\iffloattype\endcsname
+    %
+    % Is this the first time we've seen this float type?
+    \expandafter\ifx\floatlist\relax
+      \toks0 = {\do}% yes, so just \do
+    \else
+      % had it before, so preserve previous elements in list.
+      \toks0 = \expandafter{\floatlist\do}%
+    \fi
+    %
+    % Remember this xref in the control sequence \floatlistFLOATTYPE,
+    % for later use in \listoffloats.
+    \expandafter\xdef\csname floatlist\iffloattype\endcsname{\the\toks0
+      {\safexrefname}}%
+  \fi
+}
+
+% If working on a large document in chapters, it is convenient to
+% be able to disable indexing, cross-referencing, and contents, for test runs.
+% This is done with @novalidate at the beginning of the file.
+%
+\newif\iflinks \linkstrue % by default we want the aux files.
+\let\novalidate = \linksfalse
+
+% Used when writing to the aux file, or when using data from it.
+\def\requireauxfile{%
+  \iflinks
+    \tryauxfile
+    % Open the new aux file.  TeX will close it automatically at exit.
+    \immediate\openout\auxfile=\jobname.aux
+  \fi
+  \global\let\requireauxfile=\relax   % Only do this once.
+}
+
+% Read the last existing aux file, if any.  No error if none exists.
+%
+\def\tryauxfile{%
+  \openin 1 \jobname.aux
+  \ifeof 1 \else
+    \readdatafile{aux}%
+    \global\havexrefstrue
+  \fi
+  \closein 1
+}
+
+\def\setupdatafile{%
+  \catcode`\^^@=\other
+  \catcode`\^^A=\other
+  \catcode`\^^B=\other
+  \catcode`\^^C=\other
+  \catcode`\^^D=\other
+  \catcode`\^^E=\other
+  \catcode`\^^F=\other
+  \catcode`\^^G=\other
+  \catcode`\^^H=\other
+  \catcode`\^^K=\other
+  \catcode`\^^L=\other
+  \catcode`\^^N=\other
+  \catcode`\^^P=\other
+  \catcode`\^^Q=\other
+  \catcode`\^^R=\other
+  \catcode`\^^S=\other
+  \catcode`\^^T=\other
+  \catcode`\^^U=\other
+  \catcode`\^^V=\other
+  \catcode`\^^W=\other
+  \catcode`\^^X=\other
+  \catcode`\^^Z=\other
+  \catcode`\^^[=\other
+  \catcode`\^^\=\other
+  \catcode`\^^]=\other
+  \catcode`\^^^=\other
+  \catcode`\^^_=\other
+  \catcode`\^=\other
+  %
+  % Special characters.  Should be turned off anyway, but...
+  \catcode`\~=\other
+  \catcode`\[=\other
+  \catcode`\]=\other
+  \catcode`\"=\other
+  \catcode`\_=\active
+  \catcode`\|=\active
+  \catcode`\<=\active
+  \catcode`\>=\active
+  \catcode`\$=\other
+  \catcode`\#=\other
+  \catcode`\&=\other
+  \catcode`\%=\other
+  \catcode`+=\other % avoid \+ for paranoia even though we've turned it off
+  %
+  \catcode`\\=\active
+  %
+  % @ is our escape character in .aux files, and we need braces.
+  \catcode`\{=1
+  \catcode`\}=2
+  \catcode`\@=0
+}
+
+\def\readdatafile#1{%
+\begingroup
+  \setupdatafile
+  \input\jobname.#1
+\endgroup}
+
+
+\message{insertions,}
+% including footnotes.
+
+\newcount \footnoteno
+
+% The trailing space in the following definition for supereject is
+% vital for proper filling; pages come out unaligned when you do a
+% pagealignmacro call if that space before the closing brace is
+% removed. (Generally, numeric constants should always be followed by a
+% space to prevent strange expansion errors.)
+\def\supereject{\par\penalty -20000\footnoteno =0 }
+
+% @footnotestyle is meaningful for Info output only.
+\let\footnotestyle=\comment
+
+{\catcode `\@=11
+%
+% Auto-number footnotes.  Otherwise like plain.
+\gdef\footnote{%
+  \global\advance\footnoteno by \@ne
+  \edef\thisfootno{$^{\the\footnoteno}$}%
+  %
+  % In case the footnote comes at the end of a sentence, preserve the
+  % extra spacing after we do the footnote number.
+  \let\@sf\empty
+  \ifhmode\edef\@sf{\spacefactor\the\spacefactor}\ptexslash\fi
+  %
+  % Remove inadvertent blank space before typesetting the footnote number.
+  \unskip
+  \thisfootno\@sf
+  \dofootnote
+}%
+
+% Don't bother with the trickery in plain.tex to not require the
+% footnote text as a parameter.  Our footnotes don't need to be so general.
+%
+% Oh yes, they do; otherwise, @ifset (and anything else that uses
+% \parseargline) fails inside footnotes because the tokens are fixed when
+% the footnote is read.  --karl, 16nov96.
+%
+\gdef\dofootnote{%
+  \insert\footins\bgroup
+  %
+  % Nested footnotes are not supported in TeX, that would take a lot
+  % more work.  (\startsavinginserts does not suffice.)
+  \let\footnote=\errfootnotenest
+  %
+  % We want to typeset this text as a normal paragraph, even if the
+  % footnote reference occurs in (for example) a display environment.
+  % So reset some parameters.
+  \hsize=\txipagewidth
+  \interlinepenalty\interfootnotelinepenalty
+  \splittopskip\ht\strutbox % top baseline for broken footnotes
+  \splitmaxdepth\dp\strutbox
+  \floatingpenalty\@MM
+  \leftskip\z@skip
+  \rightskip\z@skip
+  \spaceskip\z@skip
+  \xspaceskip\z@skip
+  \parindent\defaultparindent
+  %
+  \smallfonts \rm
+  %
+  % Because we use hanging indentation in footnotes, a @noindent appears
+  % to exdent this text, so make it be a no-op.  makeinfo does not use
+  % hanging indentation so @noindent can still be needed within footnote
+  % text after an @example or the like (not that this is good style).
+  \let\noindent = \relax
+  %
+  % Hang the footnote text off the number.  Use \everypar in case the
+  % footnote extends for more than one paragraph.
+  \everypar = {\hang}%
+  \textindent{\thisfootno}%
+  %
+  % Don't crash into the line above the footnote text.  Since this
+  % expands into a box, it must come within the paragraph, lest it
+  % provide a place where TeX can split the footnote.
+  \footstrut
+  %
+  % Invoke rest of plain TeX footnote routine.
+  \futurelet\next\fo@t
+}
+}%end \catcode `\@=11
+
+\def\errfootnotenest{%
+  \errhelp=\EMsimple
+  \errmessage{Nested footnotes not supported in texinfo.tex,
+    even though they work in makeinfo; sorry}
+}
+
+\def\errfootnoteheading{%
+  \errhelp=\EMsimple
+  \errmessage{Footnotes in chapters, sections, etc., are not supported}
+}
+
+% In case a @footnote appears in a vbox, save the footnote text and create
+% the real \insert just after the vbox finished.  Otherwise, the insertion
+% would be lost.
+% Similarly, if a @footnote appears inside an alignment, save the footnote
+% text to a box and make the \insert when a row of the table is finished.
+% And the same can be done for other insert classes.  --kasal, 16nov03.
+%
+% Replace the \insert primitive by a cheating macro.
+% Deeper inside, just make sure that the saved insertions are not spilled
+% out prematurely.
+%
+\def\startsavinginserts{%
+  \ifx \insert\ptexinsert
+    \let\insert\saveinsert
+  \else
+    \let\checkinserts\relax
+  \fi
+}
+
+% This \insert replacement works for both \insert\footins{foo} and
+% \insert\footins\bgroup foo\egroup, but it doesn't work for \insert27{foo}.
+%
+\def\saveinsert#1{%
+  \edef\next{\noexpand\savetobox \makeSAVEname#1}%
+  \afterassignment\next
+  % swallow the left brace
+  \let\temp =
+}
+\def\makeSAVEname#1{\makecsname{SAVE\expandafter\gobble\string#1}}
+\def\savetobox#1{\global\setbox#1 = \vbox\bgroup \unvbox#1}
+
+\def\checksaveins#1{\ifvoid#1\else \placesaveins#1\fi}
+
+\def\placesaveins#1{%
+  \ptexinsert \csname\expandafter\gobblesave\string#1\endcsname
+    {\box#1}%
+}
+
+% eat @SAVE -- beware, all of them have catcode \other:
+{
+  \def\dospecials{\do S\do A\do V\do E} \uncatcodespecials  %  ;-)
+  \gdef\gobblesave @SAVE{}
+}
+
+% initialization:
+\def\newsaveins #1{%
+  \edef\next{\noexpand\newsaveinsX \makeSAVEname#1}%
+  \next
+}
+\def\newsaveinsX #1{%
+  \csname newbox\endcsname #1%
+  \expandafter\def\expandafter\checkinserts\expandafter{\checkinserts
+    \checksaveins #1}%
+}
+
+% initialize:
+\let\checkinserts\empty
+\newsaveins\footins
+\newsaveins\margin
+
+
+% @image.  We use the macros from epsf.tex to support this.
+% If epsf.tex is not installed and @image is used, we complain.
+%
+% Check for and read epsf.tex up front.  If we read it only at @image
+% time, we might be inside a group, and then its definitions would get
+% undone and the next image would fail.
+\openin 1 = epsf.tex
+\ifeof 1 \else
+  % Do not bother showing banner with epsf.tex v2.7k (available in
+  % doc/epsf.tex and on ctan).
+  \def\epsfannounce{\toks0 = }%
+  \input epsf.tex
+\fi
+\closein 1
+%
+% We will only complain once about lack of epsf.tex.
+\newif\ifwarnednoepsf
+\newhelp\noepsfhelp{epsf.tex must be installed for images to
+  work.  It is also included in the Texinfo distribution, or you can get
+  it from https://ctan.org/texarchive/macros/texinfo/texinfo/doc/epsf.tex.}
+%
+\def\image#1{%
+  \ifx\epsfbox\thisisundefined
+    \ifwarnednoepsf \else
+      \errhelp = \noepsfhelp
+      \errmessage{epsf.tex not found, images will be ignored}%
+      \global\warnednoepsftrue
+    \fi
+  \else
+    \imagexxx #1,,,,,\finish
+  \fi
+}
+%
+% Arguments to @image:
+% #1 is (mandatory) image filename; we tack on .eps extension.
+% #2 is (optional) width, #3 is (optional) height.
+% #4 is (ignored optional) html alt text.
+% #5 is (ignored optional) extension.
+% #6 is just the usual extra ignored arg for parsing stuff.
+\newif\ifimagevmode
+\def\imagexxx#1,#2,#3,#4,#5,#6\finish{\begingroup
+  \catcode`\^^M = 5     % in case we're inside an example
+  \normalturnoffactive  % allow _ et al. in names
+  \makevalueexpandable
+  % If the image is by itself, center it.
+  \ifvmode
+    \imagevmodetrue
+  \else \ifx\centersub\centerV
+    % for @center @image, we need a vbox so we can have our vertical space
+    \imagevmodetrue
+    \vbox\bgroup % vbox has better behavior than vtop herev
+  \fi\fi
+  %
+  \ifimagevmode
+    \nobreak\medskip
+    % Usually we'll have text after the image which will insert
+    % \parskip glue, so insert it here too to equalize the space
+    % above and below.
+    \nobreak\vskip\parskip
+    \nobreak
+  \fi
+  %
+  % Leave vertical mode so that indentation from an enclosing
+  %  environment such as @quotation is respected.
+  % However, if we're at the top level, we don't want the
+  %  normal paragraph indentation.
+  % On the other hand, if we are in the case of @center @image, we don't
+  %  want to start a paragraph, which will create a hsize-width box and
+  %  eradicate the centering.
+  \ifx\centersub\centerV\else \noindent \fi
+  %
+  % Output the image.
+  \ifpdf
+    % For pdfTeX and LuaTeX <= 0.80
+    \dopdfimage{#1}{#2}{#3}%
+  \else
+    \ifx\XeTeXrevision\thisisundefined
+      % For epsf.tex
+      % \epsfbox itself resets \epsf?size at each figure.
+      \setbox0 = \hbox{\ignorespaces #2}%
+        \ifdim\wd0 > 0pt \epsfxsize=#2\relax \fi
+      \setbox0 = \hbox{\ignorespaces #3}%
+        \ifdim\wd0 > 0pt \epsfysize=#3\relax \fi
+      \epsfbox{#1.eps}%
+    \else
+      % For XeTeX
+      \doxeteximage{#1}{#2}{#3}%
+    \fi
+  \fi
+  %
+  \ifimagevmode
+    \medskip  % space after a standalone image
+  \fi
+  \ifx\centersub\centerV \egroup \fi
+\endgroup}
+
+
+% @float FLOATTYPE,LABEL,LOC ... @end float for displayed figures, tables,
+% etc.  We don't actually implement floating yet, we always include the
+% float "here".  But it seemed the best name for the future.
+%
+\envparseargdef\float{\eatcommaspace\eatcommaspace\dofloat#1, , ,\finish}
+
+% There may be a space before second and/or third parameter; delete it.
+\def\eatcommaspace#1, {#1,}
+
+% #1 is the optional FLOATTYPE, the text label for this float, typically
+% "Figure", "Table", "Example", etc.  Can't contain commas.  If omitted,
+% this float will not be numbered and cannot be referred to.
+%
+% #2 is the optional xref label.  Also must be present for the float to
+% be referable.
+%
+% #3 is the optional positioning argument; for now, it is ignored.  It
+% will somehow specify the positions allowed to float to (here, top, bottom).
+%
+% We keep a separate counter for each FLOATTYPE, which we reset at each
+% chapter-level command.
+\let\resetallfloatnos=\empty
+%
+\def\dofloat#1,#2,#3,#4\finish{%
+  \let\thiscaption=\empty
+  \let\thisshortcaption=\empty
+  %
+  % don't lose footnotes inside @float.
+  %
+  % BEWARE: when the floats start float, we have to issue warning whenever an
+  % insert appears inside a float which could possibly float. --kasal, 26may04
+  %
+  \startsavinginserts
+  %
+  % We can't be used inside a paragraph.
+  \par
+  %
+  \vtop\bgroup
+    \def\floattype{#1}%
+    \def\floatlabel{#2}%
+    \def\floatloc{#3}% we do nothing with this yet.
+    %
+    \ifx\floattype\empty
+      \let\safefloattype=\empty
+    \else
+      {%
+        % the floattype might have accents or other special characters,
+        % but we need to use it in a control sequence name.
+        \indexnofonts
+        \turnoffactive
+        \xdef\safefloattype{\floattype}%
+      }%
+    \fi
+    %
+    % If label is given but no type, we handle that as the empty type.
+    \ifx\floatlabel\empty \else
+      % We want each FLOATTYPE to be numbered separately (Figure 1,
+      % Table 1, Figure 2, ...).  (And if no label, no number.)
+      %
+      \expandafter\getfloatno\csname\safefloattype floatno\endcsname
+      \global\advance\floatno by 1
+      %
+      {%
+        % This magic value for \currentsection is output by \setref as the
+        % XREFLABEL-title value.  \xrefX uses it to distinguish float
+        % labels (which have a completely different output format) from
+        % node and anchor labels.  And \xrdef uses it to construct the
+        % lists of floats.
+        %
+        \edef\currentsection{\floatmagic=\safefloattype}%
+        \setref{\floatlabel}{Yfloat}%
+      }%
+    \fi
+    %
+    % start with \parskip glue, I guess.
+    \vskip\parskip
+    %
+    % Don't suppress indentation if a float happens to start a section.
+    \restorefirstparagraphindent
+}
+
+% we have these possibilities:
+% @float Foo,lbl & @caption{Cap}: Foo 1.1: Cap
+% @float Foo,lbl & no caption:    Foo 1.1
+% @float Foo & @caption{Cap}:     Foo: Cap
+% @float Foo & no caption:        Foo
+% @float ,lbl & Caption{Cap}:     1.1: Cap
+% @float ,lbl & no caption:       1.1
+% @float & @caption{Cap}:         Cap
+% @float & no caption:
+%
+\def\Efloat{%
+    \let\floatident = \empty
+    %
+    % In all cases, if we have a float type, it comes first.
+    \ifx\floattype\empty \else \def\floatident{\floattype}\fi
+    %
+    % If we have an xref label, the number comes next.
+    \ifx\floatlabel\empty \else
+      \ifx\floattype\empty \else % if also had float type, need tie first.
+        \appendtomacro\floatident{\tie}%
+      \fi
+      % the number.
+      \appendtomacro\floatident{\chaplevelprefix\the\floatno}%
+    \fi
+    %
+    % Start the printed caption with what we've constructed in
+    % \floatident, but keep it separate; we need \floatident again.
+    \let\captionline = \floatident
+    %
+    \ifx\thiscaption\empty \else
+      \ifx\floatident\empty \else
+        \appendtomacro\captionline{: }% had ident, so need a colon between
+      \fi
+      %
+      % caption text.
+      \appendtomacro\captionline{\scanexp\thiscaption}%
+    \fi
+    %
+    % If we have anything to print, print it, with space before.
+    % Eventually this needs to become an \insert.
+    \ifx\captionline\empty \else
+      \vskip.5\parskip
+      \captionline
+      %
+      % Space below caption.
+      \vskip\parskip
+    \fi
+    %
+    % If have an xref label, write the list of floats info.  Do this
+    % after the caption, to avoid chance of it being a breakpoint.
+    \ifx\floatlabel\empty \else
+      % Write the text that goes in the lof to the aux file as
+      % \floatlabel-lof.  Besides \floatident, we include the short
+      % caption if specified, else the full caption if specified, else nothing.
+      {%
+        \requireauxfile
+        \atdummies
+        %
+        \ifx\thisshortcaption\empty
+          \def\gtemp{\thiscaption}%
+        \else
+          \def\gtemp{\thisshortcaption}%
+        \fi
+        \immediate\write\auxfile{@xrdef{\floatlabel-lof}{\floatident
+          \ifx\gtemp\empty \else : \gtemp \fi}}%
+      }%
+    \fi
+  \egroup  % end of \vtop
+  %
+  \checkinserts
+}
+
+% Append the tokens #2 to the definition of macro #1, not expanding either.
+%
+\def\appendtomacro#1#2{%
+  \expandafter\def\expandafter#1\expandafter{#1#2}%
+}
+
+% @caption, @shortcaption
+%
+\def\caption{\docaption\thiscaption}
+\def\shortcaption{\docaption\thisshortcaption}
+\def\docaption{\checkenv\float \bgroup\scanargctxt\defcaption}
+\def\defcaption#1#2{\egroup \def#1{#2}}
+
+% The parameter is the control sequence identifying the counter we are
+% going to use.  Create it if it doesn't exist and assign it to \floatno.
+\def\getfloatno#1{%
+  \ifx#1\relax
+      % Haven't seen this figure type before.
+      \csname newcount\endcsname #1%
+      %
+      % Remember to reset this floatno at the next chap.
+      \expandafter\gdef\expandafter\resetallfloatnos
+        \expandafter{\resetallfloatnos #1=0 }%
+  \fi
+  \let\floatno#1%
+}
+
+% \setref calls this to get the XREFLABEL-snt value.  We want an @xref
+% to the FLOATLABEL to expand to "Figure 3.1".  We call \setref when we
+% first read the @float command.
+%
+\def\Yfloat{\floattype@tie \chaplevelprefix\the\floatno}%
+
+% Magic string used for the XREFLABEL-title value, so \xrefX can
+% distinguish floats from other xref types.
+\def\floatmagic{!!float!!}
+
+% #1 is the control sequence we are passed; we expand into a conditional
+% which is true if #1 represents a float ref.  That is, the magic
+% \currentsection value which we \setref above.
+%
+\def\iffloat#1{\expandafter\doiffloat#1==\finish}
+%
+% #1 is (maybe) the \floatmagic string.  If so, #2 will be the
+% (safe) float type for this float.  We set \iffloattype to #2.
+%
+\def\doiffloat#1=#2=#3\finish{%
+  \def\temp{#1}%
+  \def\iffloattype{#2}%
+  \ifx\temp\floatmagic
+}
+
+% @listoffloats FLOATTYPE - print a list of floats like a table of contents.
+%
+\parseargdef\listoffloats{%
+  \def\floattype{#1}% floattype
+  {%
+    % the floattype might have accents or other special characters,
+    % but we need to use it in a control sequence name.
+    \indexnofonts
+    \turnoffactive
+    \xdef\safefloattype{\floattype}%
+  }%
+  %
+  % \xrdef saves the floats as a \do-list in \floatlistSAFEFLOATTYPE.
+  \expandafter\ifx\csname floatlist\safefloattype\endcsname \relax
+    \ifhavexrefs
+      % if the user said @listoffloats foo but never @float foo.
+      \message{\linenumber No `\safefloattype' floats to list.}%
+    \fi
+  \else
+    \begingroup
+      \leftskip=\tocindent  % indent these entries like a toc
+      \let\do=\listoffloatsdo
+      \csname floatlist\safefloattype\endcsname
+    \endgroup
+  \fi
+}
+
+% This is called on each entry in a list of floats.  We're passed the
+% xref label, in the form LABEL-title, which is how we save it in the
+% aux file.  We strip off the -title and look up \XRLABEL-lof, which
+% has the text we're supposed to typeset here.
+%
+% Figures without xref labels will not be included in the list (since
+% they won't appear in the aux file).
+%
+\def\listoffloatsdo#1{\listoffloatsdoentry#1\finish}
+\def\listoffloatsdoentry#1-title\finish{{%
+  % Can't fully expand XR#1-lof because it can contain anything.  Just
+  % pass the control sequence.  On the other hand, XR#1-pg is just the
+  % page number, and we want to fully expand that so we can get a link
+  % in pdf output.
+  \toksA = \expandafter{\csname XR#1-lof\endcsname}%
+  %
+  % use the same \entry macro we use to generate the TOC and index.
+  \edef\writeentry{\noexpand\entry{\the\toksA}{\csname XR#1-pg\endcsname}}%
+  \writeentry
+}}
+
+
+\message{localization,}
+
+% For single-language documents, @documentlanguage is usually given very
+% early, just after @documentencoding.  Single argument is the language
+% (de) or locale (de_DE) abbreviation.
+%
+{
+  \catcode`\_ = \active
+  \globaldefs=1
+\parseargdef\documentlanguage{%
+  \tex % read txi-??.tex file in plain TeX.
+    % Read the file by the name they passed if it exists.
+    \let_ = \normalunderscore  % normal _ character for filename test
+    \openin 1 txi-#1.tex
+    \ifeof 1
+      \documentlanguagetrywithoutunderscore #1_\finish
+    \else
+      \globaldefs = 1  % everything in the txi-LL files needs to persist
+      \input txi-#1.tex
+    \fi
+    \closein 1
+  \endgroup % end raw TeX
+}
+%
+% If they passed de_DE, and txi-de_DE.tex doesn't exist,
+% try txi-de.tex.
+%
+\gdef\documentlanguagetrywithoutunderscore#1_#2\finish{%
+  \openin 1 txi-#1.tex
+  \ifeof 1
+    \errhelp = \nolanghelp
+    \errmessage{Cannot read language file txi-#1.tex}%
+  \else
+    \globaldefs = 1  % everything in the txi-LL files needs to persist
+    \input txi-#1.tex
+  \fi
+  \closein 1
+}
+}% end of special _ catcode
+%
+\newhelp\nolanghelp{The given language definition file cannot be found or
+is empty.  Maybe you need to install it?  Putting it in the current
+directory should work if nowhere else does.}
+
+% This macro is called from txi-??.tex files; the first argument is the
+% \language name to set (without the "\lang@" prefix), the second and
+% third args are \{left,right}hyphenmin.
+%
+% The language names to pass are determined when the format is built.
+% See the etex.log file created at that time, e.g.,
+% /usr/local/texlive/2008/texmf-var/web2c/pdftex/etex.log.
+%
+% With TeX Live 2008, etex now includes hyphenation patterns for all
+% available languages.  This means we can support hyphenation in
+% Texinfo, at least to some extent.  (This still doesn't solve the
+% accented characters problem.)
+%
+\catcode`@=11
+\def\txisetlanguage#1#2#3{%
+  % do not set the language if the name is undefined in the current TeX.
+  \expandafter\ifx\csname lang@#1\endcsname \relax
+    \message{no patterns for #1}%
+  \else
+    \global\language = \csname lang@#1\endcsname
+  \fi
+  % but there is no harm in adjusting the hyphenmin values regardless.
+  \global\lefthyphenmin = #2\relax
+  \global\righthyphenmin = #3\relax
+}
+
+% XeTeX and LuaTeX can handle Unicode natively.
+% Their default I/O uses UTF-8 sequences instead of a byte-wise operation.
+% Other TeX engines' I/O (pdfTeX, etc.) is byte-wise.
+%
+\newif\iftxinativeunicodecapable
+\newif\iftxiusebytewiseio
+
+\ifx\XeTeXrevision\thisisundefined
+  \ifx\luatexversion\thisisundefined
+    \txinativeunicodecapablefalse
+    \txiusebytewiseiotrue
+  \else
+    \txinativeunicodecapabletrue
+    \txiusebytewiseiofalse
+  \fi
+\else
+  \txinativeunicodecapabletrue
+  \txiusebytewiseiofalse
+\fi
+
+% Set I/O by bytes instead of UTF-8 sequence for XeTeX and LuaTex
+% for non-UTF-8 (byte-wise) encodings.
+%
+\def\setbytewiseio{%
+  \ifx\XeTeXrevision\thisisundefined
+  \else
+    \XeTeXdefaultencoding "bytes"  % For subsequent files to be read
+    \XeTeXinputencoding "bytes"  % For document root file
+    % Unfortunately, there seems to be no corresponding XeTeX command for
+    % output encoding.  This is a problem for auxiliary index and TOC files.
+    % The only solution would be perhaps to write out @U{...} sequences in
+    % place of non-ASCII characters.
+  \fi
+
+  \ifx\luatexversion\thisisundefined
+  \else
+    \directlua{
+    local utf8_char, byte, gsub = unicode.utf8.char, string.byte, string.gsub
+    local function convert_char (char)
+      return utf8_char(byte(char))
+    end
+
+    local function convert_line (line)
+      return gsub(line, ".", convert_char)
+    end
+
+    callback.register("process_input_buffer", convert_line)
+
+    local function convert_line_out (line)
+      local line_out = ""
+      for c in string.utfvalues(line) do
+         line_out = line_out .. string.char(c)
+      end
+      return line_out
+    end
+
+    callback.register("process_output_buffer", convert_line_out)
+    }
+  \fi
+
+  \txiusebytewiseiotrue
+}
+
+
+% Helpers for encodings.
+% Set the catcode of characters 128 through 255 to the specified number.
+%
+\def\setnonasciicharscatcode#1{%
+   \count255=128
+   \loop\ifnum\count255<256
+      \global\catcode\count255=#1\relax
+      \advance\count255 by 1
+   \repeat
+}
+
+\def\setnonasciicharscatcodenonglobal#1{%
+   \count255=128
+   \loop\ifnum\count255<256
+      \catcode\count255=#1\relax
+      \advance\count255 by 1
+   \repeat
+}
+
+% @documentencoding sets the definition of non-ASCII characters
+% according to the specified encoding.
+%
+\def\documentencoding{\parseargusing\filenamecatcodes\documentencodingzzz}
+\def\documentencodingzzz#1{%
+  %
+  % Encoding being declared for the document.
+  \def\declaredencoding{\csname #1.enc\endcsname}%
+  %
+  % Supported encodings: names converted to tokens in order to be able
+  % to compare them with \ifx.
+  \def\ascii{\csname US-ASCII.enc\endcsname}%
+  \def\latnine{\csname ISO-8859-15.enc\endcsname}%
+  \def\latone{\csname ISO-8859-1.enc\endcsname}%
+  \def\lattwo{\csname ISO-8859-2.enc\endcsname}%
+  \def\utfeight{\csname UTF-8.enc\endcsname}%
+  %
+  \ifx \declaredencoding \ascii
+     \asciichardefs
+  %
+  \else \ifx \declaredencoding \lattwo
+     \iftxinativeunicodecapable
+       \setbytewiseio
+     \fi
+     \setnonasciicharscatcode\active
+     \lattwochardefs
+  %
+  \else \ifx \declaredencoding \latone
+     \iftxinativeunicodecapable
+       \setbytewiseio
+     \fi
+     \setnonasciicharscatcode\active
+     \latonechardefs
+  %
+  \else \ifx \declaredencoding \latnine
+     \iftxinativeunicodecapable
+       \setbytewiseio
+     \fi
+     \setnonasciicharscatcode\active
+     \latninechardefs
+  %
+  \else \ifx \declaredencoding \utfeight
+     \iftxinativeunicodecapable
+       % For native Unicode handling (XeTeX and LuaTeX)
+       \nativeunicodechardefs
+     \else
+       % For treating UTF-8 as byte sequences (TeX, eTeX and pdfTeX)
+       \setnonasciicharscatcode\active
+       % since we already invoked \utfeightchardefs at the top level
+       % (below), do not re-invoke it, otherwise our check for duplicated
+       % definitions gets triggered.  Making non-ascii chars active is
+       % sufficient.
+     \fi
+  %
+  \else
+    \message{Ignoring unknown document encoding: #1.}%
+  %
+  \fi % utfeight
+  \fi % latnine
+  \fi % latone
+  \fi % lattwo
+  \fi % ascii
+  %
+  \ifx\XeTeXrevision\thisisundefined
+  \else
+    \ifx \declaredencoding \utfeight
+    \else
+      \ifx \declaredencoding \ascii
+      \else
+        \message{Warning: XeTeX with non-UTF-8 encodings cannot handle %
+        non-ASCII characters in auxiliary files.}%
+      \fi
+    \fi
+  \fi
+}
+
+% emacs-page
+% A message to be logged when using a character that isn't available
+% the default font encoding (OT1).
+%
+\def\missingcharmsg#1{\message{Character missing, sorry: #1.}}
+
+% Take account of \c (plain) vs. \, (Texinfo) difference.
+\def\cedilla#1{\ifx\c\ptexc\c{#1}\else\,{#1}\fi}
+
+% First, make active non-ASCII characters in order for them to be
+% correctly categorized when TeX reads the replacement text of
+% macros containing the character definitions.
+\setnonasciicharscatcode\active
+%
+
+\def\gdefchar#1#2{%
+\gdef#1{%
+   \ifpassthroughchars
+     \string#1%
+   \else
+     #2%
+   \fi
+}}
+
+% Latin1 (ISO-8859-1) character definitions.
+\def\latonechardefs{%
+  \gdefchar^^a0{\tie}
+  \gdefchar^^a1{\exclamdown}
+  \gdefchar^^a2{{\tcfont \char162}} % cent
+  \gdefchar^^a3{\pounds{}}
+  \gdefchar^^a4{{\tcfont \char164}} % currency
+  \gdefchar^^a5{{\tcfont \char165}} % yen
+  \gdefchar^^a6{{\tcfont \char166}} % broken bar
+  \gdefchar^^a7{\S}
+  \gdefchar^^a8{\"{}}
+  \gdefchar^^a9{\copyright{}}
+  \gdefchar^^aa{\ordf}
+  \gdefchar^^ab{\guillemetleft{}}
+  \gdefchar^^ac{\ensuremath\lnot}
+  \gdefchar^^ad{\-}
+  \gdefchar^^ae{\registeredsymbol{}}
+  \gdefchar^^af{\={}}
+  %
+  \gdefchar^^b0{\textdegree}
+  \gdefchar^^b1{$\pm$}
+  \gdefchar^^b2{$^2$}
+  \gdefchar^^b3{$^3$}
+  \gdefchar^^b4{\'{}}
+  \gdefchar^^b5{$\mu$}
+  \gdefchar^^b6{\P}
+  \gdefchar^^b7{\ensuremath\cdot}
+  \gdefchar^^b8{\cedilla\ }
+  \gdefchar^^b9{$^1$}
+  \gdefchar^^ba{\ordm}
+  \gdefchar^^bb{\guillemetright{}}
+  \gdefchar^^bc{$1\over4$}
+  \gdefchar^^bd{$1\over2$}
+  \gdefchar^^be{$3\over4$}
+  \gdefchar^^bf{\questiondown}
+  %
+  \gdefchar^^c0{\`A}
+  \gdefchar^^c1{\'A}
+  \gdefchar^^c2{\^A}
+  \gdefchar^^c3{\~A}
+  \gdefchar^^c4{\"A}
+  \gdefchar^^c5{\ringaccent A}
+  \gdefchar^^c6{\AE}
+  \gdefchar^^c7{\cedilla C}
+  \gdefchar^^c8{\`E}
+  \gdefchar^^c9{\'E}
+  \gdefchar^^ca{\^E}
+  \gdefchar^^cb{\"E}
+  \gdefchar^^cc{\`I}
+  \gdefchar^^cd{\'I}
+  \gdefchar^^ce{\^I}
+  \gdefchar^^cf{\"I}
+  %
+  \gdefchar^^d0{\DH}
+  \gdefchar^^d1{\~N}
+  \gdefchar^^d2{\`O}
+  \gdefchar^^d3{\'O}
+  \gdefchar^^d4{\^O}
+  \gdefchar^^d5{\~O}
+  \gdefchar^^d6{\"O}
+  \gdefchar^^d7{$\times$}
+  \gdefchar^^d8{\O}
+  \gdefchar^^d9{\`U}
+  \gdefchar^^da{\'U}
+  \gdefchar^^db{\^U}
+  \gdefchar^^dc{\"U}
+  \gdefchar^^dd{\'Y}
+  \gdefchar^^de{\TH}
+  \gdefchar^^df{\ss}
+  %
+  \gdefchar^^e0{\`a}
+  \gdefchar^^e1{\'a}
+  \gdefchar^^e2{\^a}
+  \gdefchar^^e3{\~a}
+  \gdefchar^^e4{\"a}
+  \gdefchar^^e5{\ringaccent a}
+  \gdefchar^^e6{\ae}
+  \gdefchar^^e7{\cedilla c}
+  \gdefchar^^e8{\`e}
+  \gdefchar^^e9{\'e}
+  \gdefchar^^ea{\^e}
+  \gdefchar^^eb{\"e}
+  \gdefchar^^ec{\`{\dotless i}}
+  \gdefchar^^ed{\'{\dotless i}}
+  \gdefchar^^ee{\^{\dotless i}}
+  \gdefchar^^ef{\"{\dotless i}}
+  %
+  \gdefchar^^f0{\dh}
+  \gdefchar^^f1{\~n}
+  \gdefchar^^f2{\`o}
+  \gdefchar^^f3{\'o}
+  \gdefchar^^f4{\^o}
+  \gdefchar^^f5{\~o}
+  \gdefchar^^f6{\"o}
+  \gdefchar^^f7{$\div$}
+  \gdefchar^^f8{\o}
+  \gdefchar^^f9{\`u}
+  \gdefchar^^fa{\'u}
+  \gdefchar^^fb{\^u}
+  \gdefchar^^fc{\"u}
+  \gdefchar^^fd{\'y}
+  \gdefchar^^fe{\th}
+  \gdefchar^^ff{\"y}
+}
+
+% Latin9 (ISO-8859-15) encoding character definitions.
+\def\latninechardefs{%
+  % Encoding is almost identical to Latin1.
+  \latonechardefs
+  %
+  \gdefchar^^a4{\euro{}}
+  \gdefchar^^a6{\v S}
+  \gdefchar^^a8{\v s}
+  \gdefchar^^b4{\v Z}
+  \gdefchar^^b8{\v z}
+  \gdefchar^^bc{\OE}
+  \gdefchar^^bd{\oe}
+  \gdefchar^^be{\"Y}
+}
+
+% Latin2 (ISO-8859-2) character definitions.
+\def\lattwochardefs{%
+  \gdefchar^^a0{\tie}
+  \gdefchar^^a1{\ogonek{A}}
+  \gdefchar^^a2{\u{}}
+  \gdefchar^^a3{\L}
+  \gdefchar^^a4{\missingcharmsg{CURRENCY SIGN}}
+  \gdefchar^^a5{\v L}
+  \gdefchar^^a6{\'S}
+  \gdefchar^^a7{\S}
+  \gdefchar^^a8{\"{}}
+  \gdefchar^^a9{\v S}
+  \gdefchar^^aa{\cedilla S}
+  \gdefchar^^ab{\v T}
+  \gdefchar^^ac{\'Z}
+  \gdefchar^^ad{\-}
+  \gdefchar^^ae{\v Z}
+  \gdefchar^^af{\dotaccent Z}
+  %
+  \gdefchar^^b0{\textdegree{}}
+  \gdefchar^^b1{\ogonek{a}}
+  \gdefchar^^b2{\ogonek{ }}
+  \gdefchar^^b3{\l}
+  \gdefchar^^b4{\'{}}
+  \gdefchar^^b5{\v l}
+  \gdefchar^^b6{\'s}
+  \gdefchar^^b7{\v{}}
+  \gdefchar^^b8{\cedilla\ }
+  \gdefchar^^b9{\v s}
+  \gdefchar^^ba{\cedilla s}
+  \gdefchar^^bb{\v t}
+  \gdefchar^^bc{\'z}
+  \gdefchar^^bd{\H{}}
+  \gdefchar^^be{\v z}
+  \gdefchar^^bf{\dotaccent z}
+  %
+  \gdefchar^^c0{\'R}
+  \gdefchar^^c1{\'A}
+  \gdefchar^^c2{\^A}
+  \gdefchar^^c3{\u A}
+  \gdefchar^^c4{\"A}
+  \gdefchar^^c5{\'L}
+  \gdefchar^^c6{\'C}
+  \gdefchar^^c7{\cedilla C}
+  \gdefchar^^c8{\v C}
+  \gdefchar^^c9{\'E}
+  \gdefchar^^ca{\ogonek{E}}
+  \gdefchar^^cb{\"E}
+  \gdefchar^^cc{\v E}
+  \gdefchar^^cd{\'I}
+  \gdefchar^^ce{\^I}
+  \gdefchar^^cf{\v D}
+  %
+  \gdefchar^^d0{\DH}
+  \gdefchar^^d1{\'N}
+  \gdefchar^^d2{\v N}
+  \gdefchar^^d3{\'O}
+  \gdefchar^^d4{\^O}
+  \gdefchar^^d5{\H O}
+  \gdefchar^^d6{\"O}
+  \gdefchar^^d7{$\times$}
+  \gdefchar^^d8{\v R}
+  \gdefchar^^d9{\ringaccent U}
+  \gdefchar^^da{\'U}
+  \gdefchar^^db{\H U}
+  \gdefchar^^dc{\"U}
+  \gdefchar^^dd{\'Y}
+  \gdefchar^^de{\cedilla T}
+  \gdefchar^^df{\ss}
+  %
+  \gdefchar^^e0{\'r}
+  \gdefchar^^e1{\'a}
+  \gdefchar^^e2{\^a}
+  \gdefchar^^e3{\u a}
+  \gdefchar^^e4{\"a}
+  \gdefchar^^e5{\'l}
+  \gdefchar^^e6{\'c}
+  \gdefchar^^e7{\cedilla c}
+  \gdefchar^^e8{\v c}
+  \gdefchar^^e9{\'e}
+  \gdefchar^^ea{\ogonek{e}}
+  \gdefchar^^eb{\"e}
+  \gdefchar^^ec{\v e}
+  \gdefchar^^ed{\'{\dotless{i}}}
+  \gdefchar^^ee{\^{\dotless{i}}}
+  \gdefchar^^ef{\v d}
+  %
+  \gdefchar^^f0{\dh}
+  \gdefchar^^f1{\'n}
+  \gdefchar^^f2{\v n}
+  \gdefchar^^f3{\'o}
+  \gdefchar^^f4{\^o}
+  \gdefchar^^f5{\H o}
+  \gdefchar^^f6{\"o}
+  \gdefchar^^f7{$\div$}
+  \gdefchar^^f8{\v r}
+  \gdefchar^^f9{\ringaccent u}
+  \gdefchar^^fa{\'u}
+  \gdefchar^^fb{\H u}
+  \gdefchar^^fc{\"u}
+  \gdefchar^^fd{\'y}
+  \gdefchar^^fe{\cedilla t}
+  \gdefchar^^ff{\dotaccent{}}
+}
+
+% UTF-8 character definitions.
+%
+% This code to support UTF-8 is based on LaTeX's utf8.def, with some
+% changes for Texinfo conventions.  It is included here under the GPL by
+% permission from Frank Mittelbach and the LaTeX team.
+%
+\newcount\countUTFx
+\newcount\countUTFy
+\newcount\countUTFz
+
+\gdef\UTFviiiTwoOctets#1#2{\expandafter
+   \UTFviiiDefined\csname u8:#1\string #2\endcsname}
+%
+\gdef\UTFviiiThreeOctets#1#2#3{\expandafter
+   \UTFviiiDefined\csname u8:#1\string #2\string #3\endcsname}
+%
+\gdef\UTFviiiFourOctets#1#2#3#4{\expandafter
+   \UTFviiiDefined\csname u8:#1\string #2\string #3\string #4\endcsname}
+
+\gdef\UTFviiiDefined#1{%
+  \ifx #1\relax
+    \message{\linenumber Unicode char \string #1 not defined for Texinfo}%
+  \else
+    \expandafter #1%
+  \fi
+}
+
+% Give non-ASCII bytes the active definitions for processing UTF-8 sequences
+\begingroup
+  \catcode`\~13
+  \catcode`\$12
+  \catcode`\"12
+
+  % Loop from \countUTFx to \countUTFy, performing \UTFviiiTmp
+  % substituting ~ and $ with a character token of that value.
+  \def\UTFviiiLoop{%
+    \global\catcode\countUTFx\active
+    \uccode`\~\countUTFx
+    \uccode`\$\countUTFx
+    \uppercase\expandafter{\UTFviiiTmp}%
+    \advance\countUTFx by 1
+    \ifnum\countUTFx < \countUTFy
+      \expandafter\UTFviiiLoop
+    \fi}
+
+  % For bytes other than the first in a UTF-8 sequence.  Not expected to
+  % be expanded except when writing to auxiliary files.
+  \countUTFx = "80
+  \countUTFy = "C2
+  \def\UTFviiiTmp{%
+    \gdef~{%
+        \ifpassthroughchars $\fi}}%
+  \UTFviiiLoop
+
+  \countUTFx = "C2
+  \countUTFy = "E0
+  \def\UTFviiiTmp{%
+    \gdef~{%
+        \ifpassthroughchars $%
+        \else\expandafter\UTFviiiTwoOctets\expandafter$\fi}}%
+  \UTFviiiLoop
+
+  \countUTFx = "E0
+  \countUTFy = "F0
+  \def\UTFviiiTmp{%
+    \gdef~{%
+        \ifpassthroughchars $%
+        \else\expandafter\UTFviiiThreeOctets\expandafter$\fi}}%
+  \UTFviiiLoop
+
+  \countUTFx = "F0
+  \countUTFy = "F4
+  \def\UTFviiiTmp{%
+    \gdef~{%
+        \ifpassthroughchars $%
+        \else\expandafter\UTFviiiFourOctets\expandafter$\fi
+        }}%
+  \UTFviiiLoop
+\endgroup
+
+\def\globallet{\global\let} % save some \expandafter's below
+
+% @U{xxxx} to produce U+xxxx, if we support it.
+\def\U#1{%
+  \expandafter\ifx\csname uni:#1\endcsname \relax
+    \iftxinativeunicodecapable
+      % All Unicode characters can be used if native Unicode handling is
+      % active.  However, if the font does not have the glyph,
+      % letters are missing.
+      \begingroup
+        \uccode`\.="#1\relax
+        \uppercase{.}
+      \endgroup
+    \else
+      \errhelp = \EMsimple
+      \errmessage{Unicode character U+#1 not supported, sorry}%
+    \fi
+  \else
+    \csname uni:#1\endcsname
+  \fi
+}
+
+% These macros are used here to construct the name of a control
+% sequence to be defined.
+\def\UTFviiiTwoOctetsName#1#2{%
+  \csname u8:#1\string #2\endcsname}%
+\def\UTFviiiThreeOctetsName#1#2#3{%
+  \csname u8:#1\string #2\string #3\endcsname}%
+\def\UTFviiiFourOctetsName#1#2#3#4{%
+  \csname u8:#1\string #2\string #3\string #4\endcsname}%
+
+% For UTF-8 byte sequences (TeX, e-TeX and pdfTeX),
+% provide a definition macro to replace a Unicode character;
+% this gets used by the @U command
+%
+\begingroup
+  \catcode`\"=12
+  \catcode`\<=12
+  \catcode`\.=12
+  \catcode`\,=12
+  \catcode`\;=12
+  \catcode`\!=12
+  \catcode`\~=13
+  \gdef\DeclareUnicodeCharacterUTFviii#1#2{%
+    \countUTFz = "#1\relax
+    \begingroup
+      \parseXMLCharref
+
+      % Give \u8:... its definition.  The sequence of seven \expandafter's
+      % expands after the \gdef three times, e.g.
+      %
+      % 1.  \UTFviiTwoOctetsName B1 B2
+      % 2.  \csname u8:B1 \string B2 \endcsname
+      % 3.  \u8: B1 B2  (a single control sequence token)
+      %
+      \expandafter\expandafter
+      \expandafter\expandafter
+      \expandafter\expandafter
+      \expandafter\gdef       \UTFviiiTmp{#2}%
+      %
+      \expandafter\ifx\csname uni:#1\endcsname \relax \else
+       \message{Internal error, already defined: #1}%
+      \fi
+      %
+      % define an additional control sequence for this code point.
+      \expandafter\globallet\csname uni:#1\endcsname \UTFviiiTmp
+    \endgroup}
+  %
+  % Given the value in \countUTFz as a Unicode code point, set \UTFviiiTmp
+  % to the corresponding UTF-8 sequence.
+  \gdef\parseXMLCharref{%
+    \ifnum\countUTFz < "A0\relax
+      \errhelp = \EMsimple
+      \errmessage{Cannot define Unicode char value < 00A0}%
+    \else\ifnum\countUTFz < "800\relax
+      \parseUTFviiiA,%
+      \parseUTFviiiB C\UTFviiiTwoOctetsName.,%
+    \else\ifnum\countUTFz < "10000\relax
+      \parseUTFviiiA;%
+      \parseUTFviiiA,%
+      \parseUTFviiiB E\UTFviiiThreeOctetsName.{,;}%
+    \else
+      \parseUTFviiiA;%
+      \parseUTFviiiA,%
+      \parseUTFviiiA!%
+      \parseUTFviiiB F\UTFviiiFourOctetsName.{!,;}%
+    \fi\fi\fi
+  }
+
+  % Extract a byte from the end of the UTF-8 representation of \countUTFx.
+  % It must be a non-initial byte in the sequence.
+  % Change \uccode of #1 for it to be used in \parseUTFviiiB as one
+  % of the bytes.
+  \gdef\parseUTFviiiA#1{%
+    \countUTFx = \countUTFz
+    \divide\countUTFz by 64
+    \countUTFy = \countUTFz  % Save to be the future value of \countUTFz.
+    \multiply\countUTFz by 64
+
+    % \countUTFz is now \countUTFx with the last 5 bits cleared.  Subtract
+    % in order to get the last five bits.
+    \advance\countUTFx by -\countUTFz
+
+    % Convert this to the byte in the UTF-8 sequence.
+    \advance\countUTFx by 128
+    \uccode `#1\countUTFx
+    \countUTFz = \countUTFy}
+
+  % Used to put a UTF-8 byte sequence into \UTFviiiTmp
+  % #1 is the increment for \countUTFz to yield a the first byte of the UTF-8
+  %    sequence.
+  % #2 is one of the \UTFviii*OctetsName macros.
+  % #3 is always a full stop (.)
+  % #4 is a template for the other bytes in the sequence.  The values for these
+  %    bytes is substituted in here with \uppercase using the \uccode's.
+  \gdef\parseUTFviiiB#1#2#3#4{%
+    \advance\countUTFz by "#10\relax
+    \uccode `#3\countUTFz
+    \uppercase{\gdef\UTFviiiTmp{#2#3#4}}}
+\endgroup
+
+% For native Unicode handling (XeTeX and LuaTeX),
+% provide a definition macro that sets a catcode to `other' non-globally
+%
+\def\DeclareUnicodeCharacterNativeOther#1#2{%
+  \catcode"#1=\other
+}
+
+% https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_M
+% U+0000..U+007F = https://en.wikipedia.org/wiki/Basic_Latin_(Unicode_block)
+% U+0080..U+00FF = https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)
+% U+0100..U+017F = https://en.wikipedia.org/wiki/Latin_Extended-A
+% U+0180..U+024F = https://en.wikipedia.org/wiki/Latin_Extended-B
+%
+% Many of our renditions are less than wonderful, and all the missing
+% characters are available somewhere.  Loading the necessary fonts
+% awaits user request.  We can't truly support Unicode without
+% reimplementing everything that's been done in LaTeX for many years,
+% plus probably using luatex or xetex, and who knows what else.
+% We won't be doing that here in this simple file.  But we can try to at
+% least make most of the characters not bomb out.
+%
+\def\unicodechardefs{%
+  \DeclareUnicodeCharacter{00A0}{\tie}%
+  \DeclareUnicodeCharacter{00A1}{\exclamdown}%
+  \DeclareUnicodeCharacter{00A2}{{\tcfont \char162}}% 0242=cent
+  \DeclareUnicodeCharacter{00A3}{\pounds{}}%
+  \DeclareUnicodeCharacter{00A4}{{\tcfont \char164}}% 0244=currency
+  \DeclareUnicodeCharacter{00A5}{{\tcfont \char165}}% 0245=yen
+  \DeclareUnicodeCharacter{00A6}{{\tcfont \char166}}% 0246=brokenbar
+  \DeclareUnicodeCharacter{00A7}{\S}%
+  \DeclareUnicodeCharacter{00A8}{\"{ }}%
+  \DeclareUnicodeCharacter{00A9}{\copyright{}}%
+  \DeclareUnicodeCharacter{00AA}{\ordf}%
+  \DeclareUnicodeCharacter{00AB}{\guillemetleft{}}%
+  \DeclareUnicodeCharacter{00AC}{\ensuremath\lnot}%
+  \DeclareUnicodeCharacter{00AD}{\-}%
+  \DeclareUnicodeCharacter{00AE}{\registeredsymbol{}}%
+  \DeclareUnicodeCharacter{00AF}{\={ }}%
+  %
+  \DeclareUnicodeCharacter{00B0}{\ringaccent{ }}%
+  \DeclareUnicodeCharacter{00B1}{\ensuremath\pm}%
+  \DeclareUnicodeCharacter{00B2}{$^2$}%
+  \DeclareUnicodeCharacter{00B3}{$^3$}%
+  \DeclareUnicodeCharacter{00B4}{\'{ }}%
+  \DeclareUnicodeCharacter{00B5}{$\mu$}%
+  \DeclareUnicodeCharacter{00B6}{\P}%
+  \DeclareUnicodeCharacter{00B7}{\ensuremath\cdot}%
+  \DeclareUnicodeCharacter{00B8}{\cedilla{ }}%
+  \DeclareUnicodeCharacter{00B9}{$^1$}%
+  \DeclareUnicodeCharacter{00BA}{\ordm}%
+  \DeclareUnicodeCharacter{00BB}{\guillemetright{}}%
+  \DeclareUnicodeCharacter{00BC}{$1\over4$}%
+  \DeclareUnicodeCharacter{00BD}{$1\over2$}%
+  \DeclareUnicodeCharacter{00BE}{$3\over4$}%
+  \DeclareUnicodeCharacter{00BF}{\questiondown}%
+  %
+  \DeclareUnicodeCharacter{00C0}{\`A}%
+  \DeclareUnicodeCharacter{00C1}{\'A}%
+  \DeclareUnicodeCharacter{00C2}{\^A}%
+  \DeclareUnicodeCharacter{00C3}{\~A}%
+  \DeclareUnicodeCharacter{00C4}{\"A}%
+  \DeclareUnicodeCharacter{00C5}{\AA}%
+  \DeclareUnicodeCharacter{00C6}{\AE}%
+  \DeclareUnicodeCharacter{00C7}{\cedilla{C}}%
+  \DeclareUnicodeCharacter{00C8}{\`E}%
+  \DeclareUnicodeCharacter{00C9}{\'E}%
+  \DeclareUnicodeCharacter{00CA}{\^E}%
+  \DeclareUnicodeCharacter{00CB}{\"E}%
+  \DeclareUnicodeCharacter{00CC}{\`I}%
+  \DeclareUnicodeCharacter{00CD}{\'I}%
+  \DeclareUnicodeCharacter{00CE}{\^I}%
+  \DeclareUnicodeCharacter{00CF}{\"I}%
+  %
+  \DeclareUnicodeCharacter{00D0}{\DH}%
+  \DeclareUnicodeCharacter{00D1}{\~N}%
+  \DeclareUnicodeCharacter{00D2}{\`O}%
+  \DeclareUnicodeCharacter{00D3}{\'O}%
+  \DeclareUnicodeCharacter{00D4}{\^O}%
+  \DeclareUnicodeCharacter{00D5}{\~O}%
+  \DeclareUnicodeCharacter{00D6}{\"O}%
+  \DeclareUnicodeCharacter{00D7}{\ensuremath\times}%
+  \DeclareUnicodeCharacter{00D8}{\O}%
+  \DeclareUnicodeCharacter{00D9}{\`U}%
+  \DeclareUnicodeCharacter{00DA}{\'U}%
+  \DeclareUnicodeCharacter{00DB}{\^U}%
+  \DeclareUnicodeCharacter{00DC}{\"U}%
+  \DeclareUnicodeCharacter{00DD}{\'Y}%
+  \DeclareUnicodeCharacter{00DE}{\TH}%
+  \DeclareUnicodeCharacter{00DF}{\ss}%
+  %
+  \DeclareUnicodeCharacter{00E0}{\`a}%
+  \DeclareUnicodeCharacter{00E1}{\'a}%
+  \DeclareUnicodeCharacter{00E2}{\^a}%
+  \DeclareUnicodeCharacter{00E3}{\~a}%
+  \DeclareUnicodeCharacter{00E4}{\"a}%
+  \DeclareUnicodeCharacter{00E5}{\aa}%
+  \DeclareUnicodeCharacter{00E6}{\ae}%
+  \DeclareUnicodeCharacter{00E7}{\cedilla{c}}%
+  \DeclareUnicodeCharacter{00E8}{\`e}%
+  \DeclareUnicodeCharacter{00E9}{\'e}%
+  \DeclareUnicodeCharacter{00EA}{\^e}%
+  \DeclareUnicodeCharacter{00EB}{\"e}%
+  \DeclareUnicodeCharacter{00EC}{\`{\dotless{i}}}%
+  \DeclareUnicodeCharacter{00ED}{\'{\dotless{i}}}%
+  \DeclareUnicodeCharacter{00EE}{\^{\dotless{i}}}%
+  \DeclareUnicodeCharacter{00EF}{\"{\dotless{i}}}%
+  %
+  \DeclareUnicodeCharacter{00F0}{\dh}%
+  \DeclareUnicodeCharacter{00F1}{\~n}%
+  \DeclareUnicodeCharacter{00F2}{\`o}%
+  \DeclareUnicodeCharacter{00F3}{\'o}%
+  \DeclareUnicodeCharacter{00F4}{\^o}%
+  \DeclareUnicodeCharacter{00F5}{\~o}%
+  \DeclareUnicodeCharacter{00F6}{\"o}%
+  \DeclareUnicodeCharacter{00F7}{\ensuremath\div}%
+  \DeclareUnicodeCharacter{00F8}{\o}%
+  \DeclareUnicodeCharacter{00F9}{\`u}%
+  \DeclareUnicodeCharacter{00FA}{\'u}%
+  \DeclareUnicodeCharacter{00FB}{\^u}%
+  \DeclareUnicodeCharacter{00FC}{\"u}%
+  \DeclareUnicodeCharacter{00FD}{\'y}%
+  \DeclareUnicodeCharacter{00FE}{\th}%
+  \DeclareUnicodeCharacter{00FF}{\"y}%
+  %
+  \DeclareUnicodeCharacter{0100}{\=A}%
+  \DeclareUnicodeCharacter{0101}{\=a}%
+  \DeclareUnicodeCharacter{0102}{\u{A}}%
+  \DeclareUnicodeCharacter{0103}{\u{a}}%
+  \DeclareUnicodeCharacter{0104}{\ogonek{A}}%
+  \DeclareUnicodeCharacter{0105}{\ogonek{a}}%
+  \DeclareUnicodeCharacter{0106}{\'C}%
+  \DeclareUnicodeCharacter{0107}{\'c}%
+  \DeclareUnicodeCharacter{0108}{\^C}%
+  \DeclareUnicodeCharacter{0109}{\^c}%
+  \DeclareUnicodeCharacter{010A}{\dotaccent{C}}%
+  \DeclareUnicodeCharacter{010B}{\dotaccent{c}}%
+  \DeclareUnicodeCharacter{010C}{\v{C}}%
+  \DeclareUnicodeCharacter{010D}{\v{c}}%
+  \DeclareUnicodeCharacter{010E}{\v{D}}%
+  \DeclareUnicodeCharacter{010F}{d'}%
+  %
+  \DeclareUnicodeCharacter{0110}{\DH}%
+  \DeclareUnicodeCharacter{0111}{\dh}%
+  \DeclareUnicodeCharacter{0112}{\=E}%
+  \DeclareUnicodeCharacter{0113}{\=e}%
+  \DeclareUnicodeCharacter{0114}{\u{E}}%
+  \DeclareUnicodeCharacter{0115}{\u{e}}%
+  \DeclareUnicodeCharacter{0116}{\dotaccent{E}}%
+  \DeclareUnicodeCharacter{0117}{\dotaccent{e}}%
+  \DeclareUnicodeCharacter{0118}{\ogonek{E}}%
+  \DeclareUnicodeCharacter{0119}{\ogonek{e}}%
+  \DeclareUnicodeCharacter{011A}{\v{E}}%
+  \DeclareUnicodeCharacter{011B}{\v{e}}%
+  \DeclareUnicodeCharacter{011C}{\^G}%
+  \DeclareUnicodeCharacter{011D}{\^g}%
+  \DeclareUnicodeCharacter{011E}{\u{G}}%
+  \DeclareUnicodeCharacter{011F}{\u{g}}%
+  %
+  \DeclareUnicodeCharacter{0120}{\dotaccent{G}}%
+  \DeclareUnicodeCharacter{0121}{\dotaccent{g}}%
+  \DeclareUnicodeCharacter{0122}{\cedilla{G}}%
+  \DeclareUnicodeCharacter{0123}{\cedilla{g}}%
+  \DeclareUnicodeCharacter{0124}{\^H}%
+  \DeclareUnicodeCharacter{0125}{\^h}%
+  \DeclareUnicodeCharacter{0126}{\missingcharmsg{H WITH STROKE}}%
+  \DeclareUnicodeCharacter{0127}{\missingcharmsg{h WITH STROKE}}%
+  \DeclareUnicodeCharacter{0128}{\~I}%
+  \DeclareUnicodeCharacter{0129}{\~{\dotless{i}}}%
+  \DeclareUnicodeCharacter{012A}{\=I}%
+  \DeclareUnicodeCharacter{012B}{\={\dotless{i}}}%
+  \DeclareUnicodeCharacter{012C}{\u{I}}%
+  \DeclareUnicodeCharacter{012D}{\u{\dotless{i}}}%
+  \DeclareUnicodeCharacter{012E}{\ogonek{I}}%
+  \DeclareUnicodeCharacter{012F}{\ogonek{i}}%
+  %
+  \DeclareUnicodeCharacter{0130}{\dotaccent{I}}%
+  \DeclareUnicodeCharacter{0131}{\dotless{i}}%
+  \DeclareUnicodeCharacter{0132}{IJ}%
+  \DeclareUnicodeCharacter{0133}{ij}%
+  \DeclareUnicodeCharacter{0134}{\^J}%
+  \DeclareUnicodeCharacter{0135}{\^{\dotless{j}}}%
+  \DeclareUnicodeCharacter{0136}{\cedilla{K}}%
+  \DeclareUnicodeCharacter{0137}{\cedilla{k}}%
+  \DeclareUnicodeCharacter{0138}{\ensuremath\kappa}%
+  \DeclareUnicodeCharacter{0139}{\'L}%
+  \DeclareUnicodeCharacter{013A}{\'l}%
+  \DeclareUnicodeCharacter{013B}{\cedilla{L}}%
+  \DeclareUnicodeCharacter{013C}{\cedilla{l}}%
+  \DeclareUnicodeCharacter{013D}{L'}% should kern
+  \DeclareUnicodeCharacter{013E}{l'}% should kern
+  \DeclareUnicodeCharacter{013F}{L\U{00B7}}%
+  %
+  \DeclareUnicodeCharacter{0140}{l\U{00B7}}%
+  \DeclareUnicodeCharacter{0141}{\L}%
+  \DeclareUnicodeCharacter{0142}{\l}%
+  \DeclareUnicodeCharacter{0143}{\'N}%
+  \DeclareUnicodeCharacter{0144}{\'n}%
+  \DeclareUnicodeCharacter{0145}{\cedilla{N}}%
+  \DeclareUnicodeCharacter{0146}{\cedilla{n}}%
+  \DeclareUnicodeCharacter{0147}{\v{N}}%
+  \DeclareUnicodeCharacter{0148}{\v{n}}%
+  \DeclareUnicodeCharacter{0149}{'n}%
+  \DeclareUnicodeCharacter{014A}{\missingcharmsg{ENG}}%
+  \DeclareUnicodeCharacter{014B}{\missingcharmsg{eng}}%
+  \DeclareUnicodeCharacter{014C}{\=O}%
+  \DeclareUnicodeCharacter{014D}{\=o}%
+  \DeclareUnicodeCharacter{014E}{\u{O}}%
+  \DeclareUnicodeCharacter{014F}{\u{o}}%
+  %
+  \DeclareUnicodeCharacter{0150}{\H{O}}%
+  \DeclareUnicodeCharacter{0151}{\H{o}}%
+  \DeclareUnicodeCharacter{0152}{\OE}%
+  \DeclareUnicodeCharacter{0153}{\oe}%
+  \DeclareUnicodeCharacter{0154}{\'R}%
+  \DeclareUnicodeCharacter{0155}{\'r}%
+  \DeclareUnicodeCharacter{0156}{\cedilla{R}}%
+  \DeclareUnicodeCharacter{0157}{\cedilla{r}}%
+  \DeclareUnicodeCharacter{0158}{\v{R}}%
+  \DeclareUnicodeCharacter{0159}{\v{r}}%
+  \DeclareUnicodeCharacter{015A}{\'S}%
+  \DeclareUnicodeCharacter{015B}{\'s}%
+  \DeclareUnicodeCharacter{015C}{\^S}%
+  \DeclareUnicodeCharacter{015D}{\^s}%
+  \DeclareUnicodeCharacter{015E}{\cedilla{S}}%
+  \DeclareUnicodeCharacter{015F}{\cedilla{s}}%
+  %
+  \DeclareUnicodeCharacter{0160}{\v{S}}%
+  \DeclareUnicodeCharacter{0161}{\v{s}}%
+  \DeclareUnicodeCharacter{0162}{\cedilla{T}}%
+  \DeclareUnicodeCharacter{0163}{\cedilla{t}}%
+  \DeclareUnicodeCharacter{0164}{\v{T}}%
+  \DeclareUnicodeCharacter{0165}{\v{t}}%
+  \DeclareUnicodeCharacter{0166}{\missingcharmsg{H WITH STROKE}}%
+  \DeclareUnicodeCharacter{0167}{\missingcharmsg{h WITH STROKE}}%
+  \DeclareUnicodeCharacter{0168}{\~U}%
+  \DeclareUnicodeCharacter{0169}{\~u}%
+  \DeclareUnicodeCharacter{016A}{\=U}%
+  \DeclareUnicodeCharacter{016B}{\=u}%
+  \DeclareUnicodeCharacter{016C}{\u{U}}%
+  \DeclareUnicodeCharacter{016D}{\u{u}}%
+  \DeclareUnicodeCharacter{016E}{\ringaccent{U}}%
+  \DeclareUnicodeCharacter{016F}{\ringaccent{u}}%
+  %
+  \DeclareUnicodeCharacter{0170}{\H{U}}%
+  \DeclareUnicodeCharacter{0171}{\H{u}}%
+  \DeclareUnicodeCharacter{0172}{\ogonek{U}}%
+  \DeclareUnicodeCharacter{0173}{\ogonek{u}}%
+  \DeclareUnicodeCharacter{0174}{\^W}%
+  \DeclareUnicodeCharacter{0175}{\^w}%
+  \DeclareUnicodeCharacter{0176}{\^Y}%
+  \DeclareUnicodeCharacter{0177}{\^y}%
+  \DeclareUnicodeCharacter{0178}{\"Y}%
+  \DeclareUnicodeCharacter{0179}{\'Z}%
+  \DeclareUnicodeCharacter{017A}{\'z}%
+  \DeclareUnicodeCharacter{017B}{\dotaccent{Z}}%
+  \DeclareUnicodeCharacter{017C}{\dotaccent{z}}%
+  \DeclareUnicodeCharacter{017D}{\v{Z}}%
+  \DeclareUnicodeCharacter{017E}{\v{z}}%
+  \DeclareUnicodeCharacter{017F}{\missingcharmsg{LONG S}}%
+  %
+  \DeclareUnicodeCharacter{01C4}{D\v{Z}}%
+  \DeclareUnicodeCharacter{01C5}{D\v{z}}%
+  \DeclareUnicodeCharacter{01C6}{d\v{z}}%
+  \DeclareUnicodeCharacter{01C7}{LJ}%
+  \DeclareUnicodeCharacter{01C8}{Lj}%
+  \DeclareUnicodeCharacter{01C9}{lj}%
+  \DeclareUnicodeCharacter{01CA}{NJ}%
+  \DeclareUnicodeCharacter{01CB}{Nj}%
+  \DeclareUnicodeCharacter{01CC}{nj}%
+  \DeclareUnicodeCharacter{01CD}{\v{A}}%
+  \DeclareUnicodeCharacter{01CE}{\v{a}}%
+  \DeclareUnicodeCharacter{01CF}{\v{I}}%
+  %
+  \DeclareUnicodeCharacter{01D0}{\v{\dotless{i}}}%
+  \DeclareUnicodeCharacter{01D1}{\v{O}}%
+  \DeclareUnicodeCharacter{01D2}{\v{o}}%
+  \DeclareUnicodeCharacter{01D3}{\v{U}}%
+  \DeclareUnicodeCharacter{01D4}{\v{u}}%
+  %
+  \DeclareUnicodeCharacter{01E2}{\={\AE}}%
+  \DeclareUnicodeCharacter{01E3}{\={\ae}}%
+  \DeclareUnicodeCharacter{01E6}{\v{G}}%
+  \DeclareUnicodeCharacter{01E7}{\v{g}}%
+  \DeclareUnicodeCharacter{01E8}{\v{K}}%
+  \DeclareUnicodeCharacter{01E9}{\v{k}}%
+  %
+  \DeclareUnicodeCharacter{01F0}{\v{\dotless{j}}}%
+  \DeclareUnicodeCharacter{01F1}{DZ}%
+  \DeclareUnicodeCharacter{01F2}{Dz}%
+  \DeclareUnicodeCharacter{01F3}{dz}%
+  \DeclareUnicodeCharacter{01F4}{\'G}%
+  \DeclareUnicodeCharacter{01F5}{\'g}%
+  \DeclareUnicodeCharacter{01F8}{\`N}%
+  \DeclareUnicodeCharacter{01F9}{\`n}%
+  \DeclareUnicodeCharacter{01FC}{\'{\AE}}%
+  \DeclareUnicodeCharacter{01FD}{\'{\ae}}%
+  \DeclareUnicodeCharacter{01FE}{\'{\O}}%
+  \DeclareUnicodeCharacter{01FF}{\'{\o}}%
+  %
+  \DeclareUnicodeCharacter{021E}{\v{H}}%
+  \DeclareUnicodeCharacter{021F}{\v{h}}%
+  %
+  \DeclareUnicodeCharacter{0226}{\dotaccent{A}}%
+  \DeclareUnicodeCharacter{0227}{\dotaccent{a}}%
+  \DeclareUnicodeCharacter{0228}{\cedilla{E}}%
+  \DeclareUnicodeCharacter{0229}{\cedilla{e}}%
+  \DeclareUnicodeCharacter{022E}{\dotaccent{O}}%
+  \DeclareUnicodeCharacter{022F}{\dotaccent{o}}%
+  %
+  \DeclareUnicodeCharacter{0232}{\=Y}%
+  \DeclareUnicodeCharacter{0233}{\=y}%
+  \DeclareUnicodeCharacter{0237}{\dotless{j}}%
+  %
+  \DeclareUnicodeCharacter{02BC}{'}%
+  %
+  \DeclareUnicodeCharacter{02DB}{\ogonek{ }}%
+  %
+  % Greek letters upper case
+  \DeclareUnicodeCharacter{0391}{{\it A}}%
+  \DeclareUnicodeCharacter{0392}{{\it B}}%
+  \DeclareUnicodeCharacter{0393}{\ensuremath{\mit\Gamma}}%
+  \DeclareUnicodeCharacter{0394}{\ensuremath{\mit\Delta}}%
+  \DeclareUnicodeCharacter{0395}{{\it E}}%
+  \DeclareUnicodeCharacter{0396}{{\it Z}}%
+  \DeclareUnicodeCharacter{0397}{{\it H}}%
+  \DeclareUnicodeCharacter{0398}{\ensuremath{\mit\Theta}}%
+  \DeclareUnicodeCharacter{0399}{{\it I}}%
+  \DeclareUnicodeCharacter{039A}{{\it K}}%
+  \DeclareUnicodeCharacter{039B}{\ensuremath{\mit\Lambda}}%
+  \DeclareUnicodeCharacter{039C}{{\it M}}%
+  \DeclareUnicodeCharacter{039D}{{\it N}}%
+  \DeclareUnicodeCharacter{039E}{\ensuremath{\mit\Xi}}%
+  \DeclareUnicodeCharacter{039F}{{\it O}}%
+  \DeclareUnicodeCharacter{03A0}{\ensuremath{\mit\Pi}}%
+  \DeclareUnicodeCharacter{03A1}{{\it P}}%
+  %\DeclareUnicodeCharacter{03A2}{} % none - corresponds to final sigma
+  \DeclareUnicodeCharacter{03A3}{\ensuremath{\mit\Sigma}}%
+  \DeclareUnicodeCharacter{03A4}{{\it T}}%
+  \DeclareUnicodeCharacter{03A5}{\ensuremath{\mit\Upsilon}}%
+  \DeclareUnicodeCharacter{03A6}{\ensuremath{\mit\Phi}}%
+  \DeclareUnicodeCharacter{03A7}{{\it X}}%
+  \DeclareUnicodeCharacter{03A8}{\ensuremath{\mit\Psi}}%
+  \DeclareUnicodeCharacter{03A9}{\ensuremath{\mit\Omega}}%
+  %
+  % Vowels with accents
+  \DeclareUnicodeCharacter{0390}{\ensuremath{\ddot{\acute\iota}}}%
+  \DeclareUnicodeCharacter{03AC}{\ensuremath{\acute\alpha}}%
+  \DeclareUnicodeCharacter{03AD}{\ensuremath{\acute\epsilon}}%
+  \DeclareUnicodeCharacter{03AE}{\ensuremath{\acute\eta}}%
+  \DeclareUnicodeCharacter{03AF}{\ensuremath{\acute\iota}}%
+  \DeclareUnicodeCharacter{03B0}{\ensuremath{\acute{\ddot\upsilon}}}%
+  %
+  % Standalone accent
+  \DeclareUnicodeCharacter{0384}{\ensuremath{\acute{\ }}}%
+  %
+  % Greek letters lower case
+  \DeclareUnicodeCharacter{03B1}{\ensuremath\alpha}%
+  \DeclareUnicodeCharacter{03B2}{\ensuremath\beta}%
+  \DeclareUnicodeCharacter{03B3}{\ensuremath\gamma}%
+  \DeclareUnicodeCharacter{03B4}{\ensuremath\delta}%
+  \DeclareUnicodeCharacter{03B5}{\ensuremath\epsilon}%
+  \DeclareUnicodeCharacter{03B6}{\ensuremath\zeta}%
+  \DeclareUnicodeCharacter{03B7}{\ensuremath\eta}%
+  \DeclareUnicodeCharacter{03B8}{\ensuremath\theta}%
+  \DeclareUnicodeCharacter{03B9}{\ensuremath\iota}%
+  \DeclareUnicodeCharacter{03BA}{\ensuremath\kappa}%
+  \DeclareUnicodeCharacter{03BB}{\ensuremath\lambda}%
+  \DeclareUnicodeCharacter{03BC}{\ensuremath\mu}%
+  \DeclareUnicodeCharacter{03BD}{\ensuremath\nu}%
+  \DeclareUnicodeCharacter{03BE}{\ensuremath\xi}%
+  \DeclareUnicodeCharacter{03BF}{{\it o}}% omicron
+  \DeclareUnicodeCharacter{03C0}{\ensuremath\pi}%
+  \DeclareUnicodeCharacter{03C1}{\ensuremath\rho}%
+  \DeclareUnicodeCharacter{03C2}{\ensuremath\varsigma}%
+  \DeclareUnicodeCharacter{03C3}{\ensuremath\sigma}%
+  \DeclareUnicodeCharacter{03C4}{\ensuremath\tau}%
+  \DeclareUnicodeCharacter{03C5}{\ensuremath\upsilon}%
+  \DeclareUnicodeCharacter{03C6}{\ensuremath\phi}%
+  \DeclareUnicodeCharacter{03C7}{\ensuremath\chi}%
+  \DeclareUnicodeCharacter{03C8}{\ensuremath\psi}%
+  \DeclareUnicodeCharacter{03C9}{\ensuremath\omega}%
+  %
+  % More Greek vowels with accents
+  \DeclareUnicodeCharacter{03CA}{\ensuremath{\ddot\iota}}%
+  \DeclareUnicodeCharacter{03CB}{\ensuremath{\ddot\upsilon}}%
+  \DeclareUnicodeCharacter{03CC}{\ensuremath{\acute o}}%
+  \DeclareUnicodeCharacter{03CD}{\ensuremath{\acute\upsilon}}%
+  \DeclareUnicodeCharacter{03CE}{\ensuremath{\acute\omega}}%
+  %
+  % Variant Greek letters
+  \DeclareUnicodeCharacter{03D1}{\ensuremath\vartheta}%
+  \DeclareUnicodeCharacter{03D6}{\ensuremath\varpi}%
+  \DeclareUnicodeCharacter{03F1}{\ensuremath\varrho}%
+  %
+  \DeclareUnicodeCharacter{1E02}{\dotaccent{B}}%
+  \DeclareUnicodeCharacter{1E03}{\dotaccent{b}}%
+  \DeclareUnicodeCharacter{1E04}{\udotaccent{B}}%
+  \DeclareUnicodeCharacter{1E05}{\udotaccent{b}}%
+  \DeclareUnicodeCharacter{1E06}{\ubaraccent{B}}%
+  \DeclareUnicodeCharacter{1E07}{\ubaraccent{b}}%
+  \DeclareUnicodeCharacter{1E0A}{\dotaccent{D}}%
+  \DeclareUnicodeCharacter{1E0B}{\dotaccent{d}}%
+  \DeclareUnicodeCharacter{1E0C}{\udotaccent{D}}%
+  \DeclareUnicodeCharacter{1E0D}{\udotaccent{d}}%
+  \DeclareUnicodeCharacter{1E0E}{\ubaraccent{D}}%
+  \DeclareUnicodeCharacter{1E0F}{\ubaraccent{d}}%
+  %
+  \DeclareUnicodeCharacter{1E1E}{\dotaccent{F}}%
+  \DeclareUnicodeCharacter{1E1F}{\dotaccent{f}}%
+  %
+  \DeclareUnicodeCharacter{1E20}{\=G}%
+  \DeclareUnicodeCharacter{1E21}{\=g}%
+  \DeclareUnicodeCharacter{1E22}{\dotaccent{H}}%
+  \DeclareUnicodeCharacter{1E23}{\dotaccent{h}}%
+  \DeclareUnicodeCharacter{1E24}{\udotaccent{H}}%
+  \DeclareUnicodeCharacter{1E25}{\udotaccent{h}}%
+  \DeclareUnicodeCharacter{1E26}{\"H}%
+  \DeclareUnicodeCharacter{1E27}{\"h}%
+  %
+  \DeclareUnicodeCharacter{1E30}{\'K}%
+  \DeclareUnicodeCharacter{1E31}{\'k}%
+  \DeclareUnicodeCharacter{1E32}{\udotaccent{K}}%
+  \DeclareUnicodeCharacter{1E33}{\udotaccent{k}}%
+  \DeclareUnicodeCharacter{1E34}{\ubaraccent{K}}%
+  \DeclareUnicodeCharacter{1E35}{\ubaraccent{k}}%
+  \DeclareUnicodeCharacter{1E36}{\udotaccent{L}}%
+  \DeclareUnicodeCharacter{1E37}{\udotaccent{l}}%
+  \DeclareUnicodeCharacter{1E3A}{\ubaraccent{L}}%
+  \DeclareUnicodeCharacter{1E3B}{\ubaraccent{l}}%
+  \DeclareUnicodeCharacter{1E3E}{\'M}%
+  \DeclareUnicodeCharacter{1E3F}{\'m}%
+  %
+  \DeclareUnicodeCharacter{1E40}{\dotaccent{M}}%
+  \DeclareUnicodeCharacter{1E41}{\dotaccent{m}}%
+  \DeclareUnicodeCharacter{1E42}{\udotaccent{M}}%
+  \DeclareUnicodeCharacter{1E43}{\udotaccent{m}}%
+  \DeclareUnicodeCharacter{1E44}{\dotaccent{N}}%
+  \DeclareUnicodeCharacter{1E45}{\dotaccent{n}}%
+  \DeclareUnicodeCharacter{1E46}{\udotaccent{N}}%
+  \DeclareUnicodeCharacter{1E47}{\udotaccent{n}}%
+  \DeclareUnicodeCharacter{1E48}{\ubaraccent{N}}%
+  \DeclareUnicodeCharacter{1E49}{\ubaraccent{n}}%
+  %
+  \DeclareUnicodeCharacter{1E54}{\'P}%
+  \DeclareUnicodeCharacter{1E55}{\'p}%
+  \DeclareUnicodeCharacter{1E56}{\dotaccent{P}}%
+  \DeclareUnicodeCharacter{1E57}{\dotaccent{p}}%
+  \DeclareUnicodeCharacter{1E58}{\dotaccent{R}}%
+  \DeclareUnicodeCharacter{1E59}{\dotaccent{r}}%
+  \DeclareUnicodeCharacter{1E5A}{\udotaccent{R}}%
+  \DeclareUnicodeCharacter{1E5B}{\udotaccent{r}}%
+  \DeclareUnicodeCharacter{1E5E}{\ubaraccent{R}}%
+  \DeclareUnicodeCharacter{1E5F}{\ubaraccent{r}}%
+  %
+  \DeclareUnicodeCharacter{1E60}{\dotaccent{S}}%
+  \DeclareUnicodeCharacter{1E61}{\dotaccent{s}}%
+  \DeclareUnicodeCharacter{1E62}{\udotaccent{S}}%
+  \DeclareUnicodeCharacter{1E63}{\udotaccent{s}}%
+  \DeclareUnicodeCharacter{1E6A}{\dotaccent{T}}%
+  \DeclareUnicodeCharacter{1E6B}{\dotaccent{t}}%
+  \DeclareUnicodeCharacter{1E6C}{\udotaccent{T}}%
+  \DeclareUnicodeCharacter{1E6D}{\udotaccent{t}}%
+  \DeclareUnicodeCharacter{1E6E}{\ubaraccent{T}}%
+  \DeclareUnicodeCharacter{1E6F}{\ubaraccent{t}}%
+  %
+  \DeclareUnicodeCharacter{1E7C}{\~V}%
+  \DeclareUnicodeCharacter{1E7D}{\~v}%
+  \DeclareUnicodeCharacter{1E7E}{\udotaccent{V}}%
+  \DeclareUnicodeCharacter{1E7F}{\udotaccent{v}}%
+  %
+  \DeclareUnicodeCharacter{1E80}{\`W}%
+  \DeclareUnicodeCharacter{1E81}{\`w}%
+  \DeclareUnicodeCharacter{1E82}{\'W}%
+  \DeclareUnicodeCharacter{1E83}{\'w}%
+  \DeclareUnicodeCharacter{1E84}{\"W}%
+  \DeclareUnicodeCharacter{1E85}{\"w}%
+  \DeclareUnicodeCharacter{1E86}{\dotaccent{W}}%
+  \DeclareUnicodeCharacter{1E87}{\dotaccent{w}}%
+  \DeclareUnicodeCharacter{1E88}{\udotaccent{W}}%
+  \DeclareUnicodeCharacter{1E89}{\udotaccent{w}}%
+  \DeclareUnicodeCharacter{1E8A}{\dotaccent{X}}%
+  \DeclareUnicodeCharacter{1E8B}{\dotaccent{x}}%
+  \DeclareUnicodeCharacter{1E8C}{\"X}%
+  \DeclareUnicodeCharacter{1E8D}{\"x}%
+  \DeclareUnicodeCharacter{1E8E}{\dotaccent{Y}}%
+  \DeclareUnicodeCharacter{1E8F}{\dotaccent{y}}%
+  %
+  \DeclareUnicodeCharacter{1E90}{\^Z}%
+  \DeclareUnicodeCharacter{1E91}{\^z}%
+  \DeclareUnicodeCharacter{1E92}{\udotaccent{Z}}%
+  \DeclareUnicodeCharacter{1E93}{\udotaccent{z}}%
+  \DeclareUnicodeCharacter{1E94}{\ubaraccent{Z}}%
+  \DeclareUnicodeCharacter{1E95}{\ubaraccent{z}}%
+  \DeclareUnicodeCharacter{1E96}{\ubaraccent{h}}%
+  \DeclareUnicodeCharacter{1E97}{\"t}%
+  \DeclareUnicodeCharacter{1E98}{\ringaccent{w}}%
+  \DeclareUnicodeCharacter{1E99}{\ringaccent{y}}%
+  %
+  \DeclareUnicodeCharacter{1EA0}{\udotaccent{A}}%
+  \DeclareUnicodeCharacter{1EA1}{\udotaccent{a}}%
+  %
+  \DeclareUnicodeCharacter{1EB8}{\udotaccent{E}}%
+  \DeclareUnicodeCharacter{1EB9}{\udotaccent{e}}%
+  \DeclareUnicodeCharacter{1EBC}{\~E}%
+  \DeclareUnicodeCharacter{1EBD}{\~e}%
+  %
+  \DeclareUnicodeCharacter{1ECA}{\udotaccent{I}}%
+  \DeclareUnicodeCharacter{1ECB}{\udotaccent{i}}%
+  \DeclareUnicodeCharacter{1ECC}{\udotaccent{O}}%
+  \DeclareUnicodeCharacter{1ECD}{\udotaccent{o}}%
+  %
+  \DeclareUnicodeCharacter{1EE4}{\udotaccent{U}}%
+  \DeclareUnicodeCharacter{1EE5}{\udotaccent{u}}%
+  %
+  \DeclareUnicodeCharacter{1EF2}{\`Y}%
+  \DeclareUnicodeCharacter{1EF3}{\`y}%
+  \DeclareUnicodeCharacter{1EF4}{\udotaccent{Y}}%
+  %
+  \DeclareUnicodeCharacter{1EF8}{\~Y}%
+  \DeclareUnicodeCharacter{1EF9}{\~y}%
+  %
+  % Punctuation
+  \DeclareUnicodeCharacter{2013}{--}%
+  \DeclareUnicodeCharacter{2014}{---}%
+  \DeclareUnicodeCharacter{2018}{\quoteleft{}}%
+  \DeclareUnicodeCharacter{2019}{\quoteright{}}%
+  \DeclareUnicodeCharacter{201A}{\quotesinglbase{}}%
+  \DeclareUnicodeCharacter{201C}{\quotedblleft{}}%
+  \DeclareUnicodeCharacter{201D}{\quotedblright{}}%
+  \DeclareUnicodeCharacter{201E}{\quotedblbase{}}%
+  \DeclareUnicodeCharacter{2020}{\ensuremath\dagger}%
+  \DeclareUnicodeCharacter{2021}{\ensuremath\ddagger}%
+  \DeclareUnicodeCharacter{2022}{\bullet{}}%
+  \DeclareUnicodeCharacter{202F}{\thinspace}%
+  \DeclareUnicodeCharacter{2026}{\dots{}}%
+  \DeclareUnicodeCharacter{2039}{\guilsinglleft{}}%
+  \DeclareUnicodeCharacter{203A}{\guilsinglright{}}%
+  %
+  \DeclareUnicodeCharacter{20AC}{\euro{}}%
+  %
+  \DeclareUnicodeCharacter{2192}{\expansion{}}%
+  \DeclareUnicodeCharacter{21D2}{\result{}}%
+  %
+  % Mathematical symbols
+  \DeclareUnicodeCharacter{2200}{\ensuremath\forall}%
+  \DeclareUnicodeCharacter{2203}{\ensuremath\exists}%
+  \DeclareUnicodeCharacter{2208}{\ensuremath\in}%
+  \DeclareUnicodeCharacter{2212}{\minus{}}%
+  \DeclareUnicodeCharacter{2217}{\ast}%
+  \DeclareUnicodeCharacter{221E}{\ensuremath\infty}%
+  \DeclareUnicodeCharacter{2225}{\ensuremath\parallel}%
+  \DeclareUnicodeCharacter{2227}{\ensuremath\wedge}%
+  \DeclareUnicodeCharacter{2229}{\ensuremath\cap}%
+  \DeclareUnicodeCharacter{2261}{\equiv{}}%
+  \DeclareUnicodeCharacter{2264}{\ensuremath\leq}%
+  \DeclareUnicodeCharacter{2265}{\ensuremath\geq}%
+  \DeclareUnicodeCharacter{2282}{\ensuremath\subset}%
+  \DeclareUnicodeCharacter{2287}{\ensuremath\supseteq}%
+  %
+  \DeclareUnicodeCharacter{2016}{\ensuremath\Vert}%
+  \DeclareUnicodeCharacter{2032}{\ensuremath\prime}%
+  \DeclareUnicodeCharacter{210F}{\ensuremath\hbar}%
+  \DeclareUnicodeCharacter{2111}{\ensuremath\Im}%
+  \DeclareUnicodeCharacter{2113}{\ensuremath\ell}%
+  \DeclareUnicodeCharacter{2118}{\ensuremath\wp}%
+  \DeclareUnicodeCharacter{211C}{\ensuremath\Re}%
+  \DeclareUnicodeCharacter{2135}{\ensuremath\aleph}%
+  \DeclareUnicodeCharacter{2190}{\ensuremath\leftarrow}%
+  \DeclareUnicodeCharacter{2191}{\ensuremath\uparrow}%
+  \DeclareUnicodeCharacter{2193}{\ensuremath\downarrow}%
+  \DeclareUnicodeCharacter{2194}{\ensuremath\leftrightarrow}%
+  \DeclareUnicodeCharacter{2195}{\ensuremath\updownarrow}%
+  \DeclareUnicodeCharacter{2196}{\ensuremath\nwarrow}%
+  \DeclareUnicodeCharacter{2197}{\ensuremath\nearrow}%
+  \DeclareUnicodeCharacter{2198}{\ensuremath\searrow}%
+  \DeclareUnicodeCharacter{2199}{\ensuremath\swarrow}%
+  \DeclareUnicodeCharacter{21A6}{\ensuremath\mapsto}%
+  \DeclareUnicodeCharacter{21A9}{\ensuremath\hookleftarrow}%
+  \DeclareUnicodeCharacter{21AA}{\ensuremath\hookrightarrow}%
+  \DeclareUnicodeCharacter{21BC}{\ensuremath\leftharpoonup}%
+  \DeclareUnicodeCharacter{21BD}{\ensuremath\leftharpoondown}%
+  \DeclareUnicodeCharacter{21C0}{\ensuremath\rightharpoonup}%
+  \DeclareUnicodeCharacter{21C1}{\ensuremath\rightharpoondown}%
+  \DeclareUnicodeCharacter{21CC}{\ensuremath\rightleftharpoons}%
+  \DeclareUnicodeCharacter{21D0}{\ensuremath\Leftarrow}%
+  \DeclareUnicodeCharacter{21D1}{\ensuremath\Uparrow}%
+  \DeclareUnicodeCharacter{21D3}{\ensuremath\Downarrow}%
+  \DeclareUnicodeCharacter{21D4}{\ensuremath\Leftrightarrow}%
+  \DeclareUnicodeCharacter{21D5}{\ensuremath\Updownarrow}%
+  \DeclareUnicodeCharacter{2202}{\ensuremath\partial}%
+  \DeclareUnicodeCharacter{2205}{\ensuremath\emptyset}%
+  \DeclareUnicodeCharacter{2207}{\ensuremath\nabla}%
+  \DeclareUnicodeCharacter{2209}{\ensuremath\notin}%
+  \DeclareUnicodeCharacter{220B}{\ensuremath\owns}%
+  \DeclareUnicodeCharacter{220F}{\ensuremath\prod}%
+  \DeclareUnicodeCharacter{2210}{\ensuremath\coprod}%
+  \DeclareUnicodeCharacter{2211}{\ensuremath\sum}%
+  \DeclareUnicodeCharacter{2213}{\ensuremath\mp}%
+  \DeclareUnicodeCharacter{2218}{\ensuremath\circ}%
+  \DeclareUnicodeCharacter{221A}{\ensuremath\surd}%
+  \DeclareUnicodeCharacter{221D}{\ensuremath\propto}%
+  \DeclareUnicodeCharacter{2220}{\ensuremath\angle}%
+  \DeclareUnicodeCharacter{2223}{\ensuremath\mid}%
+  \DeclareUnicodeCharacter{2228}{\ensuremath\vee}%
+  \DeclareUnicodeCharacter{222A}{\ensuremath\cup}%
+  \DeclareUnicodeCharacter{222B}{\ensuremath\smallint}%
+  \DeclareUnicodeCharacter{222E}{\ensuremath\oint}%
+  \DeclareUnicodeCharacter{223C}{\ensuremath\sim}%
+  \DeclareUnicodeCharacter{2240}{\ensuremath\wr}%
+  \DeclareUnicodeCharacter{2243}{\ensuremath\simeq}%
+  \DeclareUnicodeCharacter{2245}{\ensuremath\cong}%
+  \DeclareUnicodeCharacter{2248}{\ensuremath\approx}%
+  \DeclareUnicodeCharacter{224D}{\ensuremath\asymp}%
+  \DeclareUnicodeCharacter{2250}{\ensuremath\doteq}%
+  \DeclareUnicodeCharacter{2260}{\ensuremath\neq}%
+  \DeclareUnicodeCharacter{226A}{\ensuremath\ll}%
+  \DeclareUnicodeCharacter{226B}{\ensuremath\gg}%
+  \DeclareUnicodeCharacter{227A}{\ensuremath\prec}%
+  \DeclareUnicodeCharacter{227B}{\ensuremath\succ}%
+  \DeclareUnicodeCharacter{2283}{\ensuremath\supset}%
+  \DeclareUnicodeCharacter{2286}{\ensuremath\subseteq}%
+  \DeclareUnicodeCharacter{228E}{\ensuremath\uplus}%
+  \DeclareUnicodeCharacter{2291}{\ensuremath\sqsubseteq}%
+  \DeclareUnicodeCharacter{2292}{\ensuremath\sqsupseteq}%
+  \DeclareUnicodeCharacter{2293}{\ensuremath\sqcap}%
+  \DeclareUnicodeCharacter{2294}{\ensuremath\sqcup}%
+  \DeclareUnicodeCharacter{2295}{\ensuremath\oplus}%
+  \DeclareUnicodeCharacter{2296}{\ensuremath\ominus}%
+  \DeclareUnicodeCharacter{2297}{\ensuremath\otimes}%
+  \DeclareUnicodeCharacter{2298}{\ensuremath\oslash}%
+  \DeclareUnicodeCharacter{2299}{\ensuremath\odot}%
+  \DeclareUnicodeCharacter{22A2}{\ensuremath\vdash}%
+  \DeclareUnicodeCharacter{22A3}{\ensuremath\dashv}%
+  \DeclareUnicodeCharacter{22A4}{\ensuremath\ptextop}%
+  \DeclareUnicodeCharacter{22A5}{\ensuremath\bot}%
+  \DeclareUnicodeCharacter{22A8}{\ensuremath\models}%
+  \DeclareUnicodeCharacter{22C0}{\ensuremath\bigwedge}%
+  \DeclareUnicodeCharacter{22C1}{\ensuremath\bigvee}%
+  \DeclareUnicodeCharacter{22C2}{\ensuremath\bigcap}%
+  \DeclareUnicodeCharacter{22C3}{\ensuremath\bigcup}%
+  \DeclareUnicodeCharacter{22C4}{\ensuremath\diamond}%
+  \DeclareUnicodeCharacter{22C5}{\ensuremath\cdot}%
+  \DeclareUnicodeCharacter{22C6}{\ensuremath\star}%
+  \DeclareUnicodeCharacter{22C8}{\ensuremath\bowtie}%
+  \DeclareUnicodeCharacter{2308}{\ensuremath\lceil}%
+  \DeclareUnicodeCharacter{2309}{\ensuremath\rceil}%
+  \DeclareUnicodeCharacter{230A}{\ensuremath\lfloor}%
+  \DeclareUnicodeCharacter{230B}{\ensuremath\rfloor}%
+  \DeclareUnicodeCharacter{2322}{\ensuremath\frown}%
+  \DeclareUnicodeCharacter{2323}{\ensuremath\smile}%
+  %
+  \DeclareUnicodeCharacter{25B3}{\ensuremath\triangle}%
+  \DeclareUnicodeCharacter{25B7}{\ensuremath\triangleright}%
+  \DeclareUnicodeCharacter{25BD}{\ensuremath\bigtriangledown}%
+  \DeclareUnicodeCharacter{25C1}{\ensuremath\triangleleft}%
+  \DeclareUnicodeCharacter{25C7}{\ensuremath\diamond}%
+  \DeclareUnicodeCharacter{2660}{\ensuremath\spadesuit}%
+  \DeclareUnicodeCharacter{2661}{\ensuremath\heartsuit}%
+  \DeclareUnicodeCharacter{2662}{\ensuremath\diamondsuit}%
+  \DeclareUnicodeCharacter{2663}{\ensuremath\clubsuit}%
+  \DeclareUnicodeCharacter{266D}{\ensuremath\flat}%
+  \DeclareUnicodeCharacter{266E}{\ensuremath\natural}%
+  \DeclareUnicodeCharacter{266F}{\ensuremath\sharp}%
+  \DeclareUnicodeCharacter{26AA}{\ensuremath\bigcirc}%
+  \DeclareUnicodeCharacter{27B9}{\ensuremath\rangle}%
+  \DeclareUnicodeCharacter{27C2}{\ensuremath\perp}%
+  \DeclareUnicodeCharacter{27E8}{\ensuremath\langle}%
+  \DeclareUnicodeCharacter{27F5}{\ensuremath\longleftarrow}%
+  \DeclareUnicodeCharacter{27F6}{\ensuremath\longrightarrow}%
+  \DeclareUnicodeCharacter{27F7}{\ensuremath\longleftrightarrow}%
+  \DeclareUnicodeCharacter{27FC}{\ensuremath\longmapsto}%
+  \DeclareUnicodeCharacter{29F5}{\ensuremath\setminus}%
+  \DeclareUnicodeCharacter{2A00}{\ensuremath\bigodot}%
+  \DeclareUnicodeCharacter{2A01}{\ensuremath\bigoplus}%
+  \DeclareUnicodeCharacter{2A02}{\ensuremath\bigotimes}%
+  \DeclareUnicodeCharacter{2A04}{\ensuremath\biguplus}%
+  \DeclareUnicodeCharacter{2A06}{\ensuremath\bigsqcup}%
+  \DeclareUnicodeCharacter{2A3F}{\ensuremath\amalg}%
+  \DeclareUnicodeCharacter{2AAF}{\ensuremath\preceq}%
+  \DeclareUnicodeCharacter{2AB0}{\ensuremath\succeq}%
+  %
+  \global\mathchardef\checkmark="1370% actually the square root sign
+  \DeclareUnicodeCharacter{2713}{\ensuremath\checkmark}%
+}% end of \unicodechardefs
+
+% UTF-8 byte sequence (pdfTeX) definitions (replacing and @U command)
+% It makes the setting that replace UTF-8 byte sequence.
+\def\utfeightchardefs{%
+  \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterUTFviii
+  \unicodechardefs
+}
+
+% Whether the active definitions of non-ASCII characters expand to
+% non-active tokens with the same character code.  This is used to
+% write characters literally, instead of using active definitions for
+% printing the correct glyphs.
+\newif\ifpassthroughchars
+\passthroughcharsfalse
+
+% For native Unicode handling (XeTeX and LuaTeX),
+% provide a definition macro to replace/pass-through a Unicode character
+%
+\def\DeclareUnicodeCharacterNative#1#2{%
+  \catcode"#1=\active
+  \def\dodeclareunicodecharacternative##1##2##3{%
+    \begingroup
+      \uccode`\~="##2\relax
+      \uppercase{\gdef~}{%
+        \ifpassthroughchars
+          ##1%
+        \else
+          ##3%
+        \fi
+      }
+    \endgroup
+  }
+  \begingroup
+    \uccode`\.="#1\relax
+    \uppercase{\def\UTFNativeTmp{.}}%
+    \expandafter\dodeclareunicodecharacternative\UTFNativeTmp{#1}{#2}%
+  \endgroup
+}
+
+% Native Unicode handling (XeTeX and LuaTeX) character replacing definition.
+% It activates the setting that replaces Unicode characters.
+\def\nativeunicodechardefs{%
+  \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterNative
+  \unicodechardefs
+}
+
+% For native Unicode handling (XeTeX and LuaTeX),
+% make the character token expand
+% to the sequences given in \unicodechardefs for printing.
+\def\DeclareUnicodeCharacterNativeAtU#1#2{%
+  \def\UTFAtUTmp{#2}
+  \expandafter\globallet\csname uni:#1\endcsname \UTFAtUTmp
+}
+
+% @U command definitions for native Unicode handling (XeTeX and LuaTeX).
+\def\nativeunicodechardefsatu{%
+  \let\DeclareUnicodeCharacter\DeclareUnicodeCharacterNativeAtU
+  \unicodechardefs
+}
+
+% US-ASCII character definitions.
+\def\asciichardefs{% nothing need be done
+   \relax
+}
+
+% Define all Unicode characters we know about.  This makes UTF-8 the default
+% input encoding and allows @U to work.
+\iftxinativeunicodecapable
+  \nativeunicodechardefsatu
+\else
+  \utfeightchardefs
+\fi
+
+\message{formatting,}
+
+\newdimen\defaultparindent \defaultparindent = 15pt
+
+\chapheadingskip = 15pt plus 4pt minus 2pt
+\secheadingskip = 12pt plus 3pt minus 2pt
+\subsecheadingskip = 9pt plus 2pt minus 2pt
+
+% Prevent underfull vbox error messages.
+\vbadness = 10000
+
+% Don't be very finicky about underfull hboxes, either.
+\hbadness = 6666
+
+% Following George Bush, get rid of widows and orphans.
+\widowpenalty=10000
+\clubpenalty=10000
+
+% Use TeX 3.0's \emergencystretch to help line breaking, but if we're
+% using an old version of TeX, don't do anything.  We want the amount of
+% stretch added to depend on the line length, hence the dependence on
+% \hsize.  We call this whenever the paper size is set.
+%
+\def\setemergencystretch{%
+  \ifx\emergencystretch\thisisundefined
+    % Allow us to assign to \emergencystretch anyway.
+    \def\emergencystretch{\dimen0}%
+  \else
+    \emergencystretch = .15\hsize
+  \fi
+}
+
+% Parameters in order: 1) textheight; 2) textwidth;
+% 3) voffset; 4) hoffset; 5) binding offset; 6) topskip;
+% 7) physical page height; 8) physical page width.
+%
+% We also call \setleading{\textleading}, so the caller should define
+% \textleading.  The caller should also set \parskip.
+%
+\def\internalpagesizes#1#2#3#4#5#6#7#8{%
+  \voffset = #3\relax
+  \topskip = #6\relax
+  \splittopskip = \topskip
+  %
+  \vsize = #1\relax
+  \advance\vsize by \topskip
+  \outervsize = \vsize
+  \advance\outervsize by 2\topandbottommargin
+  \txipageheight = \vsize
+  %
+  \hsize = #2\relax
+  \outerhsize = \hsize
+  \advance\outerhsize by 0.5in
+  \txipagewidth = \hsize
+  %
+  \normaloffset = #4\relax
+  \bindingoffset = #5\relax
+  %
+  \ifpdf
+    \pdfpageheight #7\relax
+    \pdfpagewidth #8\relax
+    % if we don't reset these, they will remain at "1 true in" of
+    % whatever layout pdftex was dumped with.
+    \pdfhorigin = 1 true in
+    \pdfvorigin = 1 true in
+  \else
+    \ifx\XeTeXrevision\thisisundefined
+      \special{papersize=#8,#7}%
+    \else
+      \pdfpageheight #7\relax
+      \pdfpagewidth #8\relax
+      % XeTeX does not have \pdfhorigin and \pdfvorigin.
+    \fi
+  \fi
+  %
+  \setleading{\textleading}
+  %
+  \parindent = \defaultparindent
+  \setemergencystretch
+}
+
+% @letterpaper (the default).
+\def\letterpaper{{\globaldefs = 1
+  \parskip = 3pt plus 2pt minus 1pt
+  \textleading = 13.2pt
+  %
+  % If page is nothing but text, make it come out even.
+  \internalpagesizes{607.2pt}{6in}% that's 46 lines
+                    {\voffset}{.25in}%
+                    {\bindingoffset}{36pt}%
+                    {11in}{8.5in}%
+}}
+
+% Use @smallbook to reset parameters for 7x9.25 trim size.
+\def\smallbook{{\globaldefs = 1
+  \parskip = 2pt plus 1pt
+  \textleading = 12pt
+  %
+  \internalpagesizes{7.5in}{5in}%
+                    {-.2in}{0in}%
+                    {\bindingoffset}{16pt}%
+                    {9.25in}{7in}%
+  %
+  \lispnarrowing = 0.3in
+  \tolerance = 700
+  \contentsrightmargin = 0pt
+  \defbodyindent = .5cm
+}}
+
+% Use @smallerbook to reset parameters for 6x9 trim size.
+% (Just testing, parameters still in flux.)
+\def\smallerbook{{\globaldefs = 1
+  \parskip = 1.5pt plus 1pt
+  \textleading = 12pt
+  %
+  \internalpagesizes{7.4in}{4.8in}%
+                    {-.2in}{-.4in}%
+                    {0pt}{14pt}%
+                    {9in}{6in}%
+  %
+  \lispnarrowing = 0.25in
+  \tolerance = 700
+  \contentsrightmargin = 0pt
+  \defbodyindent = .4cm
+}}
+
+% Use @afourpaper to print on European A4 paper.
+\def\afourpaper{{\globaldefs = 1
+  \parskip = 3pt plus 2pt minus 1pt
+  \textleading = 13.2pt
+  %
+  % Double-side printing via postscript on Laserjet 4050
+  % prints double-sided nicely when \bindingoffset=10mm and \hoffset=-6mm.
+  % To change the settings for a different printer or situation, adjust
+  % \normaloffset until the front-side and back-side texts align.  Then
+  % do the same for \bindingoffset.  You can set these for testing in
+  % your texinfo source file like this:
+  % @tex
+  % \global\normaloffset = -6mm
+  % \global\bindingoffset = 10mm
+  % @end tex
+  \internalpagesizes{673.2pt}{160mm}% that's 51 lines
+                    {\voffset}{\hoffset}%
+                    {\bindingoffset}{44pt}%
+                    {297mm}{210mm}%
+  %
+  \tolerance = 700
+  \contentsrightmargin = 0pt
+  \defbodyindent = 5mm
+}}
+
+% Use @afivepaper to print on European A5 paper.
+% From romildo@urano.iceb.ufop.br, 2 July 2000.
+% He also recommends making @example and @lisp be small.
+\def\afivepaper{{\globaldefs = 1
+  \parskip = 2pt plus 1pt minus 0.1pt
+  \textleading = 12.5pt
+  %
+  \internalpagesizes{160mm}{120mm}%
+                    {\voffset}{\hoffset}%
+                    {\bindingoffset}{8pt}%
+                    {210mm}{148mm}%
+  %
+  \lispnarrowing = 0.2in
+  \tolerance = 800
+  \contentsrightmargin = 0pt
+  \defbodyindent = 2mm
+  \tableindent = 12mm
+}}
+
+% A specific text layout, 24x15cm overall, intended for A4 paper.
+\def\afourlatex{{\globaldefs = 1
+  \afourpaper
+  \internalpagesizes{237mm}{150mm}%
+                    {\voffset}{4.6mm}%
+                    {\bindingoffset}{7mm}%
+                    {297mm}{210mm}%
+  %
+  % Must explicitly reset to 0 because we call \afourpaper.
+  \globaldefs = 0
+}}
+
+% Use @afourwide to print on A4 paper in landscape format.
+\def\afourwide{{\globaldefs = 1
+  \afourpaper
+  \internalpagesizes{241mm}{165mm}%
+                    {\voffset}{-2.95mm}%
+                    {\bindingoffset}{7mm}%
+                    {297mm}{210mm}%
+  \globaldefs = 0
+}}
+
+\def\bsixpaper{{\globaldefs = 1
+  \afourpaper
+  \internalpagesizes{140mm}{100mm}%
+                    {-6.35mm}{-12.7mm}%
+                    {\bindingoffset}{14pt}%
+                    {176mm}{125mm}%
+  \let\SETdispenvsize=\smallword
+  \lispnarrowing = 0.2in
+  \globaldefs = 0
+}}
+
+
+% @pagesizes TEXTHEIGHT[,TEXTWIDTH]
+% Perhaps we should allow setting the margins, \topskip, \parskip,
+% and/or leading, also. Or perhaps we should compute them somehow.
+%
+\parseargdef\pagesizes{\pagesizesyyy #1,,\finish}
+\def\pagesizesyyy#1,#2,#3\finish{{%
+  \setbox0 = \hbox{\ignorespaces #2}\ifdim\wd0 > 0pt \hsize=#2\relax \fi
+  \globaldefs = 1
+  %
+  \parskip = 3pt plus 2pt minus 1pt
+  \setleading{\textleading}%
+  %
+  \dimen0 = #1\relax
+  \advance\dimen0 by 2.5in % default 1in margin above heading line
+                           % and 1.5in to include heading, footing and
+                           % bottom margin
+  %
+  \dimen2 = \hsize
+  \advance\dimen2 by 2in % default to 1 inch margin on each side
+  %
+  \internalpagesizes{#1}{\hsize}%
+                    {\voffset}{\normaloffset}%
+                    {\bindingoffset}{44pt}%
+                    {\dimen0}{\dimen2}%
+}}
+
+% Set default to letter.
+%
+\letterpaper
+
+% Default value of \hfuzz, for suppressing warnings about overfull hboxes.
+\hfuzz = 1pt
+
+
+\message{and turning on texinfo input format.}
+
+\def^^L{\par} % remove \outer, so ^L can appear in an @comment
+
+% DEL is a comment character, in case @c does not suffice.
+\catcode`\^^? = 14
+
+% Define macros to output various characters with catcode for normal text.
+\catcode`\"=\other \def\normaldoublequote{"}
+\catcode`\$=\other \def\normaldollar{$}%$ font-lock fix
+\catcode`\+=\other \def\normalplus{+}
+\catcode`\<=\other \def\normalless{<}
+\catcode`\>=\other \def\normalgreater{>}
+\catcode`\^=\other \def\normalcaret{^}
+\catcode`\_=\other \def\normalunderscore{_}
+\catcode`\|=\other \def\normalverticalbar{|}
+\catcode`\~=\other \def\normaltilde{~}
+
+% This macro is used to make a character print one way in \tt
+% (where it can probably be output as-is), and another way in other fonts,
+% where something hairier probably needs to be done.
+%
+% #1 is what to print if we are indeed using \tt; #2 is what to print
+% otherwise.  Since all the Computer Modern typewriter fonts have zero
+% interword stretch (and shrink), and it is reasonable to expect all
+% typewriter fonts to have this, we can check that font parameter.
+%
+\def\ifusingtt#1#2{\ifdim \fontdimen3\font=0pt #1\else #2\fi}
+
+% Same as above, but check for italic font.  Actually this also catches
+% non-italic slanted fonts since it is impossible to distinguish them from
+% italic fonts.  But since this is only used by $ and it uses \sl anyway
+% this is not a problem.
+\def\ifusingit#1#2{\ifdim \fontdimen1\font>0pt #1\else #2\fi}
+
+% Set catcodes for Texinfo file
+
+% Active characters for printing the wanted glyph.
+% Most of these we simply print from the \tt font, but for some, we can
+% use math or other variants that look better in normal text.
+%
+\catcode`\"=\active
+\def\activedoublequote{{\tt\char34}}
+\let"=\activedoublequote
+\catcode`\~=\active \def\activetilde{{\tt\char126}} \let~ = \activetilde
+\chardef\hatchar=`\^
+\catcode`\^=\active \def\activehat{{\tt \hatchar}} \let^ = \activehat
+
+\catcode`\_=\active
+\def_{\ifusingtt\normalunderscore\_}
+\def\_{\leavevmode \kern.07em \vbox{\hrule width.3em height.1ex}\kern .07em }
+\let\realunder=_
+
+\catcode`\|=\active \def|{{\tt\char124}}
+
+\chardef \less=`\<
+\catcode`\<=\active \def\activeless{{\tt \less}}\let< = \activeless
+\chardef \gtr=`\>
+\catcode`\>=\active \def\activegtr{{\tt \gtr}}\let> = \activegtr
+\catcode`\+=\active \def+{{\tt \char 43}}
+\catcode`\$=\active \def${\ifusingit{{\sl\$}}\normaldollar}%$ font-lock fix
+\catcode`\-=\active \let-=\normaldash
+
+
+% used for headline/footline in the output routine, in case the page
+% breaks in the middle of an @tex block.
+\def\texinfochars{%
+  \let< = \activeless
+  \let> = \activegtr
+  \let~ = \activetilde
+  \let^ = \activehat
+  \setregularquotes
+  \let\b = \strong
+  \let\i = \smartitalic
+  % in principle, all other definitions in \tex have to be undone too.
+}
+
+% Used sometimes to turn off (effectively) the active characters even after
+% parsing them.
+\def\turnoffactive{%
+  \normalturnoffactive
+  \otherbackslash
+}
+
+\catcode`\@=0
+
+% \backslashcurfont outputs one backslash character in current font,
+% as in \char`\\.
+\global\chardef\backslashcurfont=`\\
+
+% \realbackslash is an actual character `\' with catcode other.
+{\catcode`\\=\other @gdef@realbackslash{\}}
+
+% In Texinfo, backslash is an active character; it prints the backslash
+% in fixed width font.
+\catcode`\\=\active  % @ for escape char from now on.
+
+% Print a typewriter backslash.  For math mode, we can't simply use
+% \backslashcurfont: the story here is that in math mode, the \char
+% of \backslashcurfont ends up printing the roman \ from the math symbol
+% font (because \char in math mode uses the \mathcode, and plain.tex
+% sets \mathcode`\\="026E).  Hence we use an explicit \mathchar,
+% which is the decimal equivalent of "715c (class 7, e.g., use \fam;
+% ignored family value; char position "5C).  We can't use " for the
+% usual hex value because it has already been made active.
+
+@def@ttbackslash{{@tt @ifmmode @mathchar29020 @else @backslashcurfont @fi}}
+@let@backslashchar = @ttbackslash % @backslashchar{} is for user documents.
+
+% \otherbackslash defines an active \ to be a literal `\' character with
+% catcode other.
+@gdef@otherbackslash{@let\=@realbackslash}
+
+% Same as @turnoffactive except outputs \ as {\tt\char`\\} instead of
+% the literal character `\'.
+%
+{@catcode`- = @active
+ @gdef@normalturnoffactive{%
+   @passthroughcharstrue
+   @let-=@normaldash
+   @let"=@normaldoublequote
+   @let$=@normaldollar %$ font-lock fix
+   @let+=@normalplus
+   @let<=@normalless
+   @let>=@normalgreater
+   @let^=@normalcaret
+   @let_=@normalunderscore
+   @let|=@normalverticalbar
+   @let~=@normaltilde
+   @let\=@ttbackslash
+   @setregularquotes
+   @unsepspaces
+ }
+}
+
+% If a .fmt file is being used, characters that might appear in a file
+% name cannot be active until we have parsed the command line.
+% So turn them off again, and have @fixbackslash turn them back on.
+@catcode`+=@other @catcode`@_=@other
+
+% \enablebackslashhack - allow file to begin `\input texinfo'
+%
+% If a .fmt file is being used, we don't want the `\input texinfo' to show up.
+% That is what \eatinput is for; after that, the `\' should revert to printing
+% a backslash.
+% If the file did not have a `\input texinfo', then it is turned off after
+% the first line; otherwise the first `\' in the file would cause an error.
+% This is used on the very last line of this file, texinfo.tex.
+% We also use @c to call @fixbackslash, in case ends of lines are hidden.
+{
+@catcode`@^=7
+@catcode`@^^M=13@gdef@enablebackslashhack{%
+  @global@let\ = @eatinput%
+  @catcode`@^^M=13%
+  @def@c{@fixbackslash@c}%
+  % Definition for the newline at the end of this file.
+  @def ^^M{@let^^M@secondlinenl}%
+  % Definition for a newline in the main Texinfo file.
+  @gdef @secondlinenl{@fixbackslash}%
+  % In case the first line has a whole-line command on it
+  @let@originalparsearg@parsearg
+  @def@parsearg{@fixbackslash@originalparsearg}
+}}
+
+{@catcode`@^=7 @catcode`@^^M=13%
+@gdef@eatinput input texinfo#1^^M{@fixbackslash}}
+
+% Emergency active definition of newline, in case an active newline token
+% appears by mistake.
+{@catcode`@^=7 @catcode13=13%
+@gdef@enableemergencynewline{%
+  @gdef^^M{%
+    @par%
+    %<warning: active newline>@par%
+}}}
+
+
+@gdef@fixbackslash{%
+  @ifx\@eatinput @let\ = @ttbackslash @fi
+  @catcode13=5 % regular end of line
+  @enableemergencynewline
+  @let@c=@comment
+  @let@parsearg@originalparsearg
+  % Also turn back on active characters that might appear in the input
+  % file name, in case not using a pre-dumped format.
+  @catcode`+=@active
+  @catcode`@_=@active
+  %
+  % If texinfo.cnf is present on the system, read it.
+  % Useful for site-wide @afourpaper, etc.  This macro, @fixbackslash, gets
+  % called at the beginning of every Texinfo file.  Not opening texinfo.cnf
+  % directly in this file, texinfo.tex, makes it possible to make a format
+  % file for Texinfo.
+  %
+  @openin 1 texinfo.cnf
+  @ifeof 1 @else @input texinfo.cnf @fi
+  @closein 1
+}
+
+
+% Say @foo, not \foo, in error messages.
+@escapechar = `@@
+
+% These (along with & and #) are made active for url-breaking, so need
+% active definitions as the normal characters.
+@def@normaldot{.}
+@def@normalquest{?}
+@def@normalslash{/}
+
+% These look ok in all fonts, so just make them not special.
+% @hashchar{} gets its own user-level command, because of #line.
+@catcode`@& = @other @def@normalamp{&}
+@catcode`@# = @other @def@normalhash{#}
+@catcode`@% = @other @def@normalpercent{%}
+
+@let @hashchar = @normalhash
+
+@c Finally, make ` and ' active, so that txicodequoteundirected and
+@c txicodequotebacktick work right in, e.g., @w{@code{`foo'}}.  If we
+@c don't make ` and ' active, @code will not get them as active chars.
+@c Do this last of all since we use ` in the previous @catcode assignments.
+@catcode`@'=@active
+@catcode`@`=@active
+@setregularquotes
+
+@c Local variables:
+@c eval: (add-hook 'before-save-hook 'time-stamp)
+@c page-delimiter: "^\\\\message\\|emacs-page"
+@c time-stamp-start: "def\\\\texinfoversion{"
+@c time-stamp-format: "%:y-%02m-%02d.%02H"
+@c time-stamp-end: "}"
+@c End:
+
+@c vim:sw=2:
+
+@enablebackslashhack
diff --git a/gprofng/doc/version.texi b/gprofng/doc/version.texi
new file mode 100644 (file)
index 0000000..d282161
--- /dev/null
@@ -0,0 +1,4 @@
+@set EDITION 1.0
+@set VERSION 1.0
+@set UPDATED 22 February 2022
+@set UPDATED-MONTH February 2022
diff --git a/gprofng/gp-display-html/Makefile.am b/gprofng/gp-display-html/Makefile.am
new file mode 100644 (file)
index 0000000..7fc27d1
--- /dev/null
@@ -0,0 +1,60 @@
+## 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 .. -I ../.. 
+
+dist_man_MANS = gp-display-html.1
+bin_SCRIPTS   = gp-display-html
+CLEANFILES    = $(bin_SCRIPTS)
+MAINTAINERCLEANFILES = $(dist_man_MANS)
+
+do_subst = sed -e 's/BINUTILS_VERSION/$(VERSION)/'
+
+gp-display-html: gp-display-html.in Makefile
+       $(do_subst) < $(srcdir)/gp-display-html.in > $@
+       chmod +x $@
+
+if BUILD_MAN
+
+# Use this if the man pages depend on the version number. 
+# common_mandeps = $(top_srcdir)/../bfd/version.m4
+#
+# Also change the dependence line below to this:
+# gp-display-html.1: $(common_mandeps) gp-display-html
+#
+# Currently, the version number shown in the man page is derived from
+# the output printed with --version.
+
+# These variables are used by help2man to generate the man pages.
+
+INFO_PAGE             = "gprofng"
+MANUAL                = "User Commands"
+TEXT_GP_DISPLAY_HTML  = "generate an HTML based directory structure to browse the profiles"
+
+HELP2MAN_OPT = --libtool --no-info --info-page=$(INFO_PAGE) --manual=$(MANUAL)
+H2M_FILTER = | sed 's/\.TP/\.TP\n.B/' | sed 's/Commands:/\.SH COMMANDS/' \
+  | sed 's/See also:/\.SH SEE ALSO/' | sed 's/Documentation:/.SH DOCUMENTATION/' \
+  | sed 's/Limitations:/.SH LIMITATIONS/'
+
+gp-display-html.1: gp-display-html
+       $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+         --name=$(TEXT_GP_DISPLAY_HTML) ./gp-display-html $(H2M_FILTER) > $@
+
+endif
+
diff --git a/gprofng/gp-display-html/Makefile.in b/gprofng/gp-display-html/Makefile.in
new file mode 100644 (file)
index 0000000..10f59ee
--- /dev/null
@@ -0,0 +1,630 @@
+# 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 = gp-display-html
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../libtool.m4 \
+       $(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
+       $(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+       $(top_srcdir)/acinclude.m4 $(top_srcdir)/../config/warnings.m4 \
+       $(top_srcdir)/../config/enable.m4 \
+       $(top_srcdir)/../config/ax_pthread.m4 \
+       $(top_srcdir)/config/bison.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 $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/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)$(bindir)" "$(DESTDIR)$(man1dir)"
+SCRIPTS = $(bin_SCRIPTS)
+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 = 
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+man1dir = $(mandir)/man1
+NROFF = nroff
+MANS = $(dist_man_MANS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+am__DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.in \
+       $(top_srcdir)/../mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_SUBDIRS = @BUILD_SUBDIRS@
+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@
+EXPECT = @EXPECT@
+FGREP = @FGREP@
+GPROFNG_CFLAGS = @GPROFNG_CFLAGS@
+GPROFNG_CPPFLAGS = @GPROFNG_CPPFLAGS@
+GPROFNG_LIBADD = @GPROFNG_LIBADD@
+GPROFNG_LIBDIR = @GPROFNG_LIBDIR@
+GREP = @GREP@
+HELP2MAN = @HELP2MAN@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA = @JAVA@
+JAVAC = @JAVAC@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LD_NO_AS_NEEDED = @LD_NO_AS_NEEDED@
+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@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WERROR = @WERROR@
+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@
+ax_pthread_config = @ax_pthread_config@
+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@
+gprofng_cflags = @gprofng_cflags@
+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@
+jdk_inc = @jdk_inc@
+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@
+subdirs = @subdirs@
+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 .. -I ../.. 
+dist_man_MANS = gp-display-html.1
+bin_SCRIPTS = gp-display-html
+CLEANFILES = $(bin_SCRIPTS)
+MAINTAINERCLEANFILES = $(dist_man_MANS)
+do_subst = sed -e 's/BINUTILS_VERSION/$(VERSION)/'
+
+# Use this if the man pages depend on the version number. 
+# common_mandeps = $(top_srcdir)/../bfd/version.m4
+#
+# Also change the dependence line below to this:
+# gp-display-html.1: $(common_mandeps) gp-display-html
+#
+# Currently, the version number shown in the man page is derived from
+# the output printed with --version.
+
+# These variables are used by help2man to generate the man pages.
+@BUILD_MAN_TRUE@INFO_PAGE = "gprofng"
+@BUILD_MAN_TRUE@MANUAL = "User Commands"
+@BUILD_MAN_TRUE@TEXT_GP_DISPLAY_HTML = "generate an HTML based directory structure to browse the profiles"
+@BUILD_MAN_TRUE@HELP2MAN_OPT = --libtool --no-info --info-page=$(INFO_PAGE) --manual=$(MANUAL)
+@BUILD_MAN_TRUE@H2M_FILTER = | sed 's/\.TP/\.TP\n.B/' | sed 's/Commands:/\.SH COMMANDS/' \
+@BUILD_MAN_TRUE@  | sed 's/See also:/\.SH SEE ALSO/' | sed 's/Documentation:/.SH DOCUMENTATION/' \
+@BUILD_MAN_TRUE@  | sed 's/Limitations:/.SH LIMITATIONS/'
+
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gp-display-html/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign gp-display-html/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-binSCRIPTS: $(bin_SCRIPTS)
+       @$(NORMAL_INSTALL)
+       @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+       fi; \
+       for p in $$list; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
+       done | \
+       sed -e 'p;s,.*/,,;n' \
+           -e 'h;s|.*|.|' \
+           -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \
+       $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \
+         { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+           if ($$2 == $$4) { files[d] = files[d] " " $$1; \
+             if (++n[d] == $(am__install_max)) { \
+               print "f", d, files[d]; n[d] = 0; files[d] = "" } } \
+           else { print "f", d "/" $$4, $$1 } } \
+         END { for (d in files) print "f", d, files[d] }' | \
+       while read type dir files; do \
+            if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+            test -z "$$files" || { \
+              echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+              $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+            } \
+       ; done
+
+uninstall-binSCRIPTS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \
+       files=`for p in $$list; do echo "$$p"; done | \
+              sed -e 's,.*/,,;$(transform)'`; \
+       dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir)
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+install-man1: $(dist_man_MANS)
+       @$(NORMAL_INSTALL)
+       @list1=''; \
+       list2='$(dist_man_MANS)'; \
+       test -n "$(man1dir)" \
+         && test -n "`echo $$list1$$list2`" \
+         || exit 0; \
+       echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
+       $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
+       { for i in $$list1; do echo "$$i"; done;  \
+       if test -n "$$list2"; then \
+         for i in $$list2; do echo "$$i"; done \
+           | sed -n '/\.1[a-z]*$$/p'; \
+       fi; \
+       } | while read p; do \
+         if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; echo "$$p"; \
+       done | \
+       sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+       sed 'N;N;s,\n, ,g' | { \
+       list=; while read file base inst; do \
+         if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+           echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+           $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+         fi; \
+       done; \
+       for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+       while read files; do \
+         test -z "$$files" || { \
+           echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+           $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+       done; }
+
+uninstall-man1:
+       @$(NORMAL_UNINSTALL)
+       @list=''; test -n "$(man1dir)" || exit 0; \
+       files=`{ for i in $$list; do echo "$$i"; done; \
+       l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+         sed -n '/\.1[a-z]*$$/p'; \
+       } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+       dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile $(SCRIPTS) $(MANS)
+installdirs:
+       for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; 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:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+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."
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binSCRIPTS
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man1
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binSCRIPTS uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+       cscopelist-am ctags-am distclean distclean-generic \
+       distclean-libtool distdir dvi dvi-am html html-am info info-am \
+       install install-am install-binSCRIPTS 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-man install-man1 install-pdf \
+       install-pdf-am install-ps install-ps-am install-strip \
+       installcheck installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-generic \
+       mostlyclean-libtool pdf pdf-am ps ps-am tags-am uninstall \
+       uninstall-am uninstall-binSCRIPTS uninstall-man uninstall-man1
+
+.PRECIOUS: Makefile
+
+
+gp-display-html: gp-display-html.in Makefile
+       $(do_subst) < $(srcdir)/gp-display-html.in > $@
+       chmod +x $@
+
+@BUILD_MAN_TRUE@gp-display-html.1: gp-display-html
+@BUILD_MAN_TRUE@       $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+@BUILD_MAN_TRUE@         --name=$(TEXT_GP_DISPLAY_HTML) ./gp-display-html $(H2M_FILTER) > $@
+
+# 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/gp-display-html/gp-display-html.in b/gprofng/gp-display-html/gp-display-html.in
new file mode 100644 (file)
index 0000000..f8fbc24
--- /dev/null
@@ -0,0 +1,256 @@
+#!/usr/bin/perl
+
+#   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.
+#------------------------------------------------------------------------------
+# gp-display-html, last updated July 2021
+#
+# NOTE: This is a skeleton version. The real code will follow as an update.
+#------------------------------------------------------------------------------
+
+use strict;
+use warnings;
+
+#------------------------------------------------------------------------------
+# Poor man's version of a boolean.
+#------------------------------------------------------------------------------
+my $TRUE    = 1;
+my $FALSE   = 0;
+
+#-------------------------------------------------------------------------------
+# Define the driver command, tool name and version number.
+#-------------------------------------------------------------------------------
+my $driver_cmd       = "gprofng display html";
+my $tool_name        = "gp-display-html";
+my $binutils_version = "BINUTILS_VERSION";
+my $version_info     = $tool_name . " GNU binutils version " . $binutils_version;
+
+#------------------------------------------------------------------------------
+# This is cosmetic, but helps with the scoping of variables.
+#------------------------------------------------------------------------------
+
+  main ();
+
+  exit (0);
+
+#------------------------------------------------------------------------------
+#                             THE SUBROUTINES
+#------------------------------------------------------------------------------
+
+#------------------------------------------------------------------------------
+# This is the driver part of the program.
+#------------------------------------------------------------------------------
+sub
+main
+{
+  my $subr_name = "main";
+  my $ignore_value; 
+
+#------------------------------------------------------------------------------
+# If no options are given, print the help info and exit.
+#------------------------------------------------------------------------------
+  $ignore_value = early_scan_specific_options();
+
+  $ignore_value = be_patient (); 
+
+  return (0);
+
+} #-- End of subroutine main
+
+sub
+be_patient
+{
+  print "Functionality not implemented yet - please stay tuned for updates\n";
+
+} #-- End of subroutine be_patient
+
+#------------------------------------------------------------------------------
+# Prints the version number and license information.
+#------------------------------------------------------------------------------
+sub 
+print_version_info 
+{
+  print "$version_info\n";
+  print "Copyright (C) 2021 Free Software Foundation, Inc.\n";
+  print "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.\n";
+  print "This is free software: you are free to change and redistribute it.\n";
+  print "There is NO WARRANTY, to the extent permitted by law.\n";
+
+  return (0);
+
+} #-- End of subroutine print_version_info
+
+#-------------------------------------------------------------------------------
+# Print the help overview
+#-------------------------------------------------------------------------------
+sub 
+print_help_info 
+{
+  print
+    "Usage: $driver_cmd [OPTION(S)] EXPERIMENT(S)\n".
+    "\n".
+    "Process one or more experiments to generate a directory containing an index.html\n".
+    "file that can be used to browse the experiment data\n".
+    "\n".
+    "Options:\n".
+    "\n".
+    " --help              print usage information and exit.\n".
+    " --version           print the version number and exit.\n".
+    " --verbose {on|off}  enable (on) or disable (off) verbose mode; the default is \"off\".\n".
+    "\n".
+    "\n".
+    " -o, --output <dir-name>  use <dir-name> to store the results in; the default\n".
+    "                           name is ./display.<n>.html with <n> the first number\n".
+    "                           not in use; an existing directory is not overwritten.\n".
+    "\n".
+    " -O, --overwrite <dir-name>  use <dir-name> to store the results in and overwrite\n".
+    "                              any existing directory with the same name; make sure\n".
+    "                              that umask is set to the correct access permissions.\n".
+    "\n".
+    " -fl, --func_limit <limit>  impose a limit on the number of functions processed;\n".
+    "                             this is an integer number; set to 0 to process all\n".
+    "                             functions; the default value is 100.\n".
+    "\n".
+    "  -ct, --calltree {on|off}  enable or disable an html page with a call tree linked\n".
+    "                             from the bottom of the first page; default is off.\n".
+    "\n".
+    "  -tp, --threshold_percentage <percentage>  provide a percentage of metric accountability; the\n".
+    "                                             inclusion of functions for each metric will take\n".
+    "                                             place in sort order until the percentage has been\n".
+    "                                             reached.\n".
+    "\n".
+    "  -dm, --default_metrics {on|off}  enable or disable automatic selection of metrics\n".
+    "                                   and use a default set of metrics; the default is off.\n".
+    "\n".
+    "  -im, --ignore_metrics <metric-list>  ignore the metrics from <metric-list>.\n".
+    "\n".
+    "  -db, --debug {on|off}  enable/disable debug mode; print detailed information to assist with troubleshooting\n".
+    "                          or further development of this tool; default is off.\n".
+    "\n".
+    "  -q, --quiet {on|off}  disable/enable the display of warnings; default is off.\n".
+    "\n".
+    "Environment:\n".
+    "\n".
+    "The options can be set in a configuration file called .gp-display-html.rc. This\n".
+    "file needs to be either in the current directory, or in the home directory of the user.\n".
+    "The long name of the option without the leading dashes is supported. For example calltree\n".
+    "to enable or disable the call tree. Note that some options take a value. In case the same option\n".
+    "occurs multiple times in this file, only the last setting encountered is preserved.\n".
+    "\n".
+    "Documentation:\n".
+    "\n".
+    "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n".
+    "gprofng programs are properly installed at your site, the command \"info gprofng\"\n".
+    "should give you access to this document.\n".
+    "\n".
+    "See also:\n".
+    "\n".
+    "gprofng(1), gp-archive(1), gp-collect-app(1), gp-display-src(1), gp-display-text(1)\n";
+
+    return (0);
+
+} #-- End of subroutine print_help_info
+
+#------------------------------------------------------------------------------
+# Scan the command line for specific options.
+#------------------------------------------------------------------------------
+sub
+early_scan_specific_options
+{
+  my $subr_name = "early_scan_specific_options";
+
+  my $ignore_value;
+  my $found_option;
+  my $option_has_value;
+  my $option_value;
+
+  my $verbose_setting = $FALSE;
+  my $debug_setting   = $FALSE;
+  my $quiet_setting   = $FALSE;
+
+  $option_has_value = $FALSE;
+  ($found_option, $option_value) = find_target_option (\@ARGV, $option_has_value, "--version");
+  if ($found_option)
+    {
+      $ignore_value = print_version_info ();
+      exit(0);
+    }
+  $option_has_value = $FALSE;
+  ($found_option, $option_value) = find_target_option (\@ARGV, $option_has_value, "--help");
+  if ($found_option)
+    {
+      $ignore_value = print_help_info ();
+      exit(0);
+    }
+
+  return (0);
+
+} #-- End of subroutine early_scan_specific_options
+
+#------------------------------------------------------------------------------
+# Scan the command line to see if the specified option is present.
+#
+# Two types of options are supported: options without value (e.g. --help) or
+# those that are set to "on" or "off".
+#------------------------------------------------------------------------------
+sub
+find_target_option
+{
+  my ($command_line_ref, $has_value, $target_option) = @_;
+
+  my @command_line = @{ $command_line_ref };
+
+  my ($command_line_string) = join(" ", @command_line);
+
+  my $option_value = "not set";
+  my $found_option = $FALSE;
+
+  if ($command_line_string =~ /\s*($target_option)\s*(on|off)*\s*/)
+    {
+      if ($has_value)
+        {
+#------------------------------------------------------------------------------
+# We are looking for this kind if substring: "--verbose on"
+#------------------------------------------------------------------------------
+          if (defined($1) and defined($2))
+            {
+              if ( ($2 eq "on") or ($2 eq "off") )
+                {
+                  $found_option = $TRUE;
+                  $option_value = $2;
+                }
+            }
+        }
+      else
+        {
+#------------------------------------------------------------------------------
+# We are looking for this kind if substring: "--help"
+#------------------------------------------------------------------------------
+          if (defined($1))
+            {
+              $found_option = $TRUE;
+            }
+        }
+    }
+
+  return($found_option, $option_value);
+
+} #-- End of subroutine find_target_option
diff --git a/gprofng/libcollector/CHK_LIBC_OBJ b/gprofng/libcollector/CHK_LIBC_OBJ
new file mode 100755 (executable)
index 0000000..dbeb9cb
--- /dev/null
@@ -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 (file)
index 0000000..bd86e97
--- /dev/null
@@ -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 (file)
index 0000000..920c7a7
--- /dev/null
@@ -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 (file)
index 0000000..b269c73
--- /dev/null
@@ -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 (file)
index 0000000..93c9d33
--- /dev/null
@@ -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, &param, 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, &param, 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 (file)
index 0000000..c54568d
--- /dev/null
@@ -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 (file)
index 0000000..8c9b920
--- /dev/null
@@ -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 (executable)
index 0000000..ed23350
--- /dev/null
@@ -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 = "\a"
+
+}
+{
+  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 = "\a"
+}
+/^[\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 (file)
index 0000000..8acd66f
--- /dev/null
@@ -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 (file)
index 0000000..8fa18c8
--- /dev/null
@@ -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 (file)
index 0000000..f9a7de1
--- /dev/null
@@ -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 (file)
index 0000000..b4418d6
--- /dev/null
@@ -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 (file)
index 0000000..f369cdc
--- /dev/null
@@ -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 (file)
index 0000000..470a269
--- /dev/null
@@ -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 (file)
index 0000000..6fdaf1b
--- /dev/null
@@ -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 (file)
index 0000000..4d01bf1
--- /dev/null
@@ -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 (file)
index 0000000..6881f02
--- /dev/null
@@ -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 (file)
index 0000000..462ccf2
--- /dev/null
@@ -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 (file)
index 0000000..9daaa5a
--- /dev/null
@@ -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 (file)
index 0000000..9b3882a
--- /dev/null
@@ -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 (file)
index 0000000..f3bd932
--- /dev/null
@@ -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 (file)
index 0000000..1f5ad68
--- /dev/null
@@ -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 (file)
index 0000000..c709b3c
--- /dev/null
@@ -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 == '"')
+                         {//&quot;
+                           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 == '\'')
+                         {//&apos;
+                           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 == '&')
+                         {//&amp;
+                           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 == '<')
+                         {//&lt;
+                           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 == '>')
+                         {//&gt;
+                           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 == '"')
+                             {//&quot;
+                               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 == '\'')
+                             {//&apos;
+                               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 == '&')
+                             {//&amp;
+                               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 == '<')
+                             {//&lt;
+                               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 == '>')
+                             {//&gt;
+                               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 (file)
index 0000000..4384d47
--- /dev/null
@@ -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 (file)
index 0000000..970d68c
--- /dev/null
@@ -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 (&regex_desc, follow_spec, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+  if (ercode)
+    {
+      // syntax error in parsing string
+#ifdef DEBUG
+      char errbuf[256];
+      regerror (ercode, &regex_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 (&regex_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 (&regex_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 (file)
index 0000000..84d6bbc
--- /dev/null
@@ -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 (file)
index 0000000..213061f
--- /dev/null
@@ -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 (file)
index 0000000..97482d2
--- /dev/null
@@ -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 (file)
index 0000000..30d3953
--- /dev/null
@@ -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 (file)
index 0000000..db79766
--- /dev/null
@@ -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 (file)
index 0000000..5ada421
--- /dev/null
@@ -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 (file)
index 0000000..78231c2
--- /dev/null
@@ -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 (file)
index 0000000..ac5c997
--- /dev/null
@@ -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 (file)
index 0000000..996d3f0
--- /dev/null
@@ -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 (file)
index 0000000..401c8f2
--- /dev/null
@@ -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 (file)
index 0000000..416c3e7
--- /dev/null
@@ -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 (file)
index 0000000..38b3d53
--- /dev/null
@@ -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 (file)
index 0000000..ffb06f9
--- /dev/null
@@ -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() */
diff --git a/gprofng/src/ABS.h b/gprofng/src/ABS.h
new file mode 100644 (file)
index 0000000..a5bcbea
--- /dev/null
@@ -0,0 +1,62 @@
+/* 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 _ABS_H
+#define _ABS_H
+
+/*
+ * Apropos Backtracking Scheme definitions.
+ * Class: com_sun_forte_st_mpmt_timeline_HWCEvent
+ */
+
+/* ABS failure codes */
+typedef enum
+{
+  ABS_NULL          = 0x00,     /* undefined/disabled/inactive */
+  ABS_UNSUPPORTED   = 0x01,     /* inappropriate HWC event type */
+  ABS_BLOCKED       = 0x02,     /* runtime backtrack blocker reached */
+  ABS_INCOMPLETE    = 0x03,     /* runtime backtrack limit reached */
+  ABS_REG_LOSS      = 0x04,     /* address register contaminated */
+  ABS_INVALID_EA    = 0x05,     /* invalid effective address value */
+  ABS_NO_CTI_INFO   = 0x10,     /* no AnalyzerInfo for validation */
+  ABS_INFO_FAILED   = 0x20,     /* info failed to validate backtrack */
+  ABS_CTI_TARGET    = 0x30,     /* CTI target invalidated backtrack */
+  ABS_CODE_RANGE    = 0xFF      /* reserved ABS code range in Vaddr */
+} ABS_code;
+
+enum {
+  NUM_ABS_RT_CODES = 7,
+  NUM_ABS_PP_CODES = 5
+};
+
+extern const char *ABS_RT_CODES[NUM_ABS_RT_CODES];
+extern char *ABS_PP_CODES[NUM_ABS_PP_CODES];
+
+/* libcollector will mark HWC overflow values that appear to be invalid */
+/* dbe should check HWC values for errors */
+#define HWCVAL_ERR_FLAG         (1ULL<<63)
+#define HWCVAL_SET_ERR(ctr)     ((ctr) | HWCVAL_ERR_FLAG)
+#define HWCVAL_HAS_ERR(ctr)     ((ctr) & HWCVAL_ERR_FLAG ? 1 : 0)
+#define HWCVAL_CLR_ERR(ctr)     ((ctr) & ~HWCVAL_ERR_FLAG)
+
+#define ABS_GET_RT_CODE(EA)     ((EA) & 0x0FLL)
+#define ABS_GET_PP_CODE(EA)     (((EA) & 0xF0LL) / 0xF)
+
+#endif /* _ABS_H */
diff --git a/gprofng/src/Application.cc b/gprofng/src/Application.cc
new file mode 100644 (file)
index 0000000..e28956c
--- /dev/null
@@ -0,0 +1,259 @@
+/* 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 <stdlib.h>
+#include <strings.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "Application.h"
+#include "Settings.h"
+#include "i18n.h"
+#include "util.h"
+
+Application::ProgressFunc Application::progress_func = NULL;
+Application *theApplication;
+
+Application::Application (int argc, char *argv[], char *fdhome)
+{
+  theApplication = this;
+  cur_dir = NULL;
+  prog_version = dbe_strdup (VERSION);
+  set_name (strchr (argv[0], '/') ? argv[0] : NULL);
+  whoami = get_basename (get_name ());
+
+  // set up a queue for comments
+  commentq = new Emsgqueue (NTXT ("app_commentq"));
+
+  // Locate where the binaries are installed
+  set_run_dir (fdhome);
+
+  // Initialize I18N
+  init_locale (run_dir);
+
+  // Initialize licensing data
+  lic_found = 0;
+  lic_err = NULL;
+
+  // Initialize worker threads
+  number_of_worker_threads = 1;
+#if DEBUG
+  char *use_worker_threads = getenv (NTXT ("SP_USE_WORKER_THREADS"));
+  if ((NULL != use_worker_threads) && (0 == strcasecmp (use_worker_threads, NTXT ("no"))))
+    {
+      number_of_worker_threads = 0;
+    }
+#endif /* DEBUG */
+  settings = new Settings (this);
+}
+
+Application::~Application ()
+{
+  delete commentq;
+  delete settings;
+  free (prog_version);
+  free (cur_dir);
+  free (prog_name);
+  free (run_dir);
+}
+
+// Set the name of the application (for messages)
+void
+Application::set_name (const char *_name)
+{
+  prog_name = get_realpath (_name);
+}
+
+char *
+Application::get_realpath (const char *_name)
+{
+  if (_name == NULL)
+    _name = "/proc/self/exe";
+  char *exe_name = realpath (_name, NULL);
+  if (exe_name)
+    return exe_name;
+  if (strchr (_name, '/') == NULL)
+    {
+      char *path = getenv ("PATH");
+      if (path)
+       for (char *s = path;; s++)
+         if (*s == ':' || *s == 0)
+           {
+             if (path != s)
+               {
+                 char *nm = dbe_sprintf (NTXT ("%.*s/%s"), (int) (path - s - 1), path, _name);
+                 exe_name = realpath (nm, NULL);
+                 free (nm);
+                 if (exe_name)
+                   return exe_name;
+               }
+             if (*s == 0)
+               break;
+             path = s + 1;
+           }
+    }
+  return strdup (_name);
+}
+
+// Set the directory where all binaries are found
+void
+Application::set_run_dir (char *fdhome)
+{
+  run_dir_with_spaces = NULL;
+  if (fdhome)
+    {
+      char *path = dbe_sprintf ("%s/bin", fdhome);
+      struct stat sbuf;
+      if (stat (path, &sbuf) != -1)
+       run_dir = path;
+      else
+       {
+         free (path);
+         run_dir = dbe_strdup (fdhome);
+       }
+    }
+  else
+    {
+      run_dir = realpath (prog_name, NULL);
+      if (run_dir == NULL)
+       {
+         fprintf (stderr, // I18N won't work here -- not catopen yet.
+                  GTXT ("Can't find location of %s\n"), prog_name);
+         run_dir = dbe_strdup (get_cur_dir ());
+       }
+      else
+       {
+         char *d = strrchr (run_dir, '/');
+         if (d)
+           *d = 0;
+         // Check if the installation path contains spaces
+         if (strchr (run_dir, ' ') != NULL)
+           {
+             // Create a symbolic link without spaces
+             const char *dir = NTXT ("/tmp/.gprofngLinks");
+             char *symbolic_link = dbe_create_symlink_to_path (run_dir, dir);
+             if (NULL != symbolic_link)
+               {
+                 // Save old path to avoid memory leak
+                 run_dir_with_spaces = run_dir;
+                 // Use the path through symbolic link
+                 run_dir = symbolic_link;
+               }
+           }
+       }
+    }
+}
+
+char *
+Application::get_cur_dir ()
+{
+  if (cur_dir == NULL)
+    {
+      char cwd[MAXPATHLEN];
+      if (getcwd (cwd, sizeof (cwd)) == NULL)
+       {
+         perror (prog_name);
+         exit (1);
+       }
+      cur_dir = dbe_strdup (canonical_path (cwd));
+    }
+  return cur_dir;
+}
+
+/**
+ * Get number of worker threads
+ * This is used to decide if it is ok to use worker threads for stat()
+ * and other actions that can hang for a long time
+ * @return number_of_worker_threads
+ */
+int
+Application::get_number_of_worker_threads ()
+{
+  return number_of_worker_threads;
+}
+
+int
+Application::check_args (int argc, char *argv[])
+{
+  int opt;
+  // Parsing the command line
+  opterr = 0;
+  while ((opt = getopt (argc, argv, "V")) != EOF)
+    switch (opt)
+      {
+      case 'V':
+// Ruud
+       Application::print_version_info ();
+/*
+       printf (NTXT ("GNU %s version %s\n"), get_basename (prog_name), VERSION);
+*/
+       exit (0);
+      default:
+       usage ();
+      }
+  return optind;
+}
+
+Emsg *
+Application::fetch_comments ()
+{
+  if (commentq == NULL)
+    return NULL;
+  return commentq->fetch ();
+}
+
+void
+Application::queue_comment (Emsg *m)
+{
+  commentq->append (m);
+}
+
+void
+Application::delete_comments ()
+{
+  if (commentq != NULL)
+    {
+      delete commentq;
+      commentq = new Emsgqueue (NTXT ("app_commentq"));
+    }
+}
+
+int
+Application::set_progress (int percentage, const char *proc_str)
+{
+  if (progress_func != NULL)
+    return progress_func (percentage, proc_str);
+  return 0;
+}
+
+// Ruud
+void
+Application::print_version_info ()
+{
+  printf ( GTXT (
+    "GNU %s binutils version %s\n"
+    "Copyright (C) 2021 Free Software Foundation, Inc.\n"
+    "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.\n"
+    "This is free software: you are free to change and redistribute it.\n"
+    "There is NO WARRANTY, to the extent permitted by law.\n"),
+    get_basename (prog_name), VERSION);
+}
diff --git a/gprofng/src/Application.h b/gprofng/src/Application.h
new file mode 100644 (file)
index 0000000..404383b
--- /dev/null
@@ -0,0 +1,108 @@
+/* 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.  */
+
+/*
+ * The Application class is the base class for all C++ executables
+ *     in the Performance Tools Suite
+ *
+ *     It determines the directory from which the running binary came,
+ *     sets up the I18N catalog, the program name, and initializes
+ *     an instance of the Settings class to manage all user preferences
+ *     and settings.  It also manages usage tracking.
+ *
+ *     Applications which read experiments are derived from a subclass
+ *     named DbeApplication (q.v.)
+ */
+
+#ifndef _APPLICATION_H
+#define _APPLICATION_H
+
+#include "dbe_types.h"
+
+class Settings;
+class Emsg;
+class Emsgqueue;
+
+// Application object
+class Application
+{
+public:
+  Application (int argc, char *argv[], char *_run_dir = NULL);
+  virtual ~Application ();
+  void set_name (const char *_name);
+  char *get_cur_dir ();
+
+  // Control the settings of a progress bar, used for GUI applications
+  // this function also detects cancel requests and returns 1
+  // if yes, 0 otherwise
+  static int set_progress (int percentage, const char *proc_str);
+  static char *get_realpath (const char *_name);
+
+  // queue for messages (from reading er.rc files, ...)
+  void queue_comment (Emsg *m); // queue for messages
+  Emsg *fetch_comments (void);  // fetch the queue of comment messages
+  void delete_comments (void);  // delete the queue of comment messages
+
+  // worker threads (currently used in dbe_stat() for stat() calls)
+  int get_number_of_worker_threads ();
+
+  char *get_version ()              { return prog_version; }
+  char *get_name ()                 { return prog_name; }
+  char *get_run_dir ()              { return run_dir; }
+  Emsgqueue *get_comments_queue ()  { return commentq; };
+
+protected: // methods
+  void set_run_dir (char *fdhome = NULL);
+  typedef int (*ProgressFunc)(int, const char *);
+
+  // Write a usage message; to be defined in derived class
+  virtual void usage () = 0;
+
+// Ruud
+  // Write a version message; to be defined in derived class
+  void print_version_info ();
+
+  // Can be overridden in derived class
+  virtual int check_args (int argc, char *argv[]);
+
+  void read_rc ();
+  static void set_progress_func (ProgressFunc func) { progress_func = func; }
+
+protected:
+  Emsgqueue *commentq;
+  Settings *settings;
+  char *prog_version;
+  char *prog_name;
+  char *whoami;
+  char *run_dir;
+  char *run_dir_with_spaces; // used in case there are spaces
+  char *cur_dir;
+  int lic_found;
+  char *lic_err;
+
+private:
+  void set_ut_email (int argc, char *argv[]);
+  int number_of_worker_threads;
+  static ProgressFunc progress_func;
+};
+
+extern Application *theApplication;
+
+#endif /* _APPLICATION_H */
diff --git a/gprofng/src/ArchiveExp.cc b/gprofng/src/ArchiveExp.cc
new file mode 100644 (file)
index 0000000..e7ebfa9
--- /dev/null
@@ -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 <stdio.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "LoadObject.h"
+#include "ArchiveExp.h"
+#include "DbeFile.h"
+#include "CallStack.h"
+#include "gp-archive.h"
+#include "Function.h"
+#include "Module.h"
+
+ArchiveExp::ArchiveExp (char *path) : Experiment ()
+{
+  force_flag = false;
+  copyso_flag = false;
+  use_fndr_archives = true;
+  status = find_expdir (path);
+  if (status == SUCCESS)
+    read_log_file ();
+}
+
+ArchiveExp::~ArchiveExp () { }
+
+void
+ArchiveExp::read_data (int s_option)
+{
+  read_archives ();
+  read_map_file ();
+  if (read_java_classes_file () == SUCCESS)
+    {
+      for (int i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
+       {
+         LoadObject *lo = loadObjs->get (i);
+         Dprintf (DEBUG_ARCHIVE, NTXT ("%s:%d loadObjs[%d]=%-25s %s\n"),
+                  get_basename (__FILE__), (int) __LINE__, i,
+                  STR (lo->get_name ()), STR (lo->get_pathname ()));
+         if ((lo->dbeFile->filetype & DbeFile::F_JAVACLASS) == 0)
+           continue;
+         lo->isUsed = true;
+         if ((s_option & ARCH_EXE_ONLY) != 0)
+           continue;
+         lo->sync_read_stabs ();
+       }
+    }
+  if ((s_option & (ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY)) != 0)
+    {
+      read_frameinfo_file ();
+      resolveFrameInfo = true;
+      Vector<DataDescriptor*> *ddscr = getDataDescriptors ();
+      delete ddscr; // getDataDescriptors() forces reading of experiment data
+      CallStack *callStack = callTree ();
+      if (callStack)
+       {
+         if (DEBUG_ARCHIVE)
+           {
+             Dprintf (DEBUG_ARCHIVE, NTXT ("stacks=%p\n"), callStack);
+             callStack->print (NULL);
+           }
+         for (int n = 0;; n++)
+           {
+             CallStackNode *node = callStack->get_node (n);
+             if (node == NULL)
+               break;
+             do
+               {
+                 Histable *h = node->get_instr ();
+                 Histable::Type t = h->get_type ();
+                 if (t == Histable::INSTR)
+                   {
+                     DbeInstr *dbeInstr = (DbeInstr *) h;
+                     if (!dbeInstr->isUsed)
+                       {
+                         Function *func = (Function *) dbeInstr->convertto (Histable::FUNCTION);
+                         if (!func->isUsed)
+                           {
+                             func->isUsed = true;
+                             func->module->isUsed = true;
+                             func->module->loadobject->isUsed = true;
+                           }
+                         DbeLine *dbeLine = (DbeLine *) dbeInstr->convertto (Histable::LINE);
+                         if (dbeLine)
+                           dbeLine->sourceFile->isUsed = true;
+                       }
+                   }
+                 else if (t == Histable::LINE)
+                   {
+                     DbeLine * dbeLine = (DbeLine *) h;
+                     dbeLine->sourceFile->isUsed = true;
+                   }
+                 node = node->ancestor;
+               }
+             while (node);
+           }
+       }
+    }
+}
+
+char *
+ArchiveExp::createLinkToFndrArchive (LoadObject *lo, int /* hide_msg */)
+{
+  // For example, archives of libc.so will be:
+  //  <exp>/archives/<libc.so_check_sum>
+  //  <exp>/M_r0.er/archives/libc.so_<hash> -> ../../archives/<libc.so_check_sum>
+  if (!create_dir (get_fndr_arch_name ()))
+    {
+      fprintf (stderr, GTXT ("Unable to create directory `%s'\n"), get_fndr_arch_name ());
+      return NULL;
+    }
+  uint32_t checksum = lo->get_checksum ();
+  char *linkName = dbe_sprintf (NTXT ("../../%s/%u"), SP_ARCHIVES_DIR, checksum);
+  char *nm = lo->get_pathname ();
+  char *symLinkName = getNameInArchive (nm, false);
+  if (symlink (linkName, symLinkName) != 0)
+    {
+      fprintf (stderr, GTXT ("Unable to create link `%s' -> `%s'\n"),
+              symLinkName, linkName);
+      free (linkName);
+      free (symLinkName);
+      return NULL;
+    }
+  free (linkName);
+  free (symLinkName);
+
+  // Return a full path inside founder archive:
+  return dbe_sprintf (NTXT ("%s/%u"), get_fndr_arch_name (), checksum);
+}
diff --git a/gprofng/src/ArchiveExp.h b/gprofng/src/ArchiveExp.h
new file mode 100644 (file)
index 0000000..809ed58
--- /dev/null
@@ -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.  */
+
+#ifndef _ARCHIVE_EXP_H
+#define _ARCHIVE_EXP_H
+
+#include "Experiment.h"
+class LoadObject;
+
+class ArchiveExp : public Experiment
+{
+public:
+  ArchiveExp (char *path);
+  ~ArchiveExp ();
+  char *createLinkToFndrArchive (LoadObject *lo, int hide_msg);
+  void read_data (int s_option);
+
+private:
+  bool force_flag;
+  bool copyso_flag;
+  bool use_fndr_archives;
+};
+
+#endif /* _ARCHIVE_EXP_H */
diff --git a/gprofng/src/BaseMetric.cc b/gprofng/src/BaseMetric.cc
new file mode 100644 (file)
index 0000000..bb51ddf
--- /dev/null
@@ -0,0 +1,975 @@
+/* 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 <strings.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "BaseMetric.h"
+#include "DbeSession.h"
+#include "Expression.h"
+
+int BaseMetric::last_id = 0;
+
+void
+BaseMetric::init (Type t)
+{
+  id = last_id++;
+  type = t;
+  aux = NULL;
+  cmd = NULL;
+  username = NULL;
+  hw_ctr = NULL;
+  cond = NULL;
+  val = NULL;
+  expr = NULL;
+  cond_spec = NULL;
+  val_spec = NULL;
+  expr_spec = NULL;
+  legend = NULL;
+  definition = NULL;
+  dependent_bm = NULL;
+  zeroThreshold = 0;
+  clock_unit = (Presentation_clock_unit) 0;
+  for (int ii = 0; ii < NSUBTYPES; ii++)
+    default_visbits[ii] = VAL_NA;
+  valtype = VT_DOUBLE;
+  precision = METRIC_HR_PRECISION;
+  flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+  value_styles = VAL_TIMEVAL | VAL_PERCENT;
+}
+
+BaseMetric::BaseMetric (Type t)
+{
+  init (t);
+  switch (t)
+    {
+    case CP_LMS_USER:
+    case CP_LMS_SYSTEM:
+    case CP_LMS_WAIT_CPU:
+    case CP_LMS_USER_LOCK:
+    case CP_LMS_TFAULT:
+    case CP_LMS_DFAULT:
+    case OMP_MASTER_THREAD:
+    case CP_TOTAL:
+    case CP_TOTAL_CPU:
+    case CP_LMS_TRAP:
+    case CP_LMS_KFAULT:
+    case CP_LMS_SLEEP:
+    case CP_LMS_STOPPED:
+    case OMP_NONE:
+    case OMP_OVHD:
+    case OMP_WORK:
+    case OMP_IBAR:
+    case OMP_EBAR:
+    case OMP_WAIT:
+    case OMP_SERL:
+    case OMP_RDUC:
+    case OMP_LKWT:
+    case OMP_CTWT:
+    case OMP_ODWT:
+    case OMP_MSTR:
+    case OMP_SNGL:
+    case OMP_ORDD:
+    case CP_KERNEL_CPU:
+      // all of these are floating point, precision = clock profile tick
+      valtype = VT_DOUBLE;
+      precision = METRIC_SIG_PRECISION;
+      flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+      value_styles = VAL_TIMEVAL | VAL_PERCENT;
+      break;
+    case SYNC_WAIT_TIME:
+    case IO_READ_TIME:
+    case IO_WRITE_TIME:
+    case IO_OTHER_TIME:
+    case IO_ERROR_TIME:
+      // all of these are floating point, precision = hrtime tick
+      valtype = VT_DOUBLE;
+      precision = METRIC_HR_PRECISION;
+      flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+      value_styles = VAL_TIMEVAL | VAL_PERCENT;
+      break;
+    case SYNC_WAIT_COUNT:
+    case HEAP_ALLOC_CNT:
+    case HEAP_LEAK_CNT:
+    case IO_READ_CNT:
+    case IO_WRITE_CNT:
+    case IO_OTHER_CNT:
+    case IO_ERROR_CNT:
+      valtype = VT_LLONG;
+      precision = 1;
+      flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+      value_styles = VAL_VALUE | VAL_PERCENT;
+      break;
+    case RACCESS:
+    case DEADLOCKS:
+      // all of these are integer
+      valtype = VT_LLONG;
+      precision = 1;
+      flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+      value_styles = VAL_VALUE | VAL_PERCENT;
+      zeroThreshold = 1;
+      break;
+    case HEAP_ALLOC_BYTES:
+    case HEAP_LEAK_BYTES:
+    case IO_READ_BYTES:
+    case IO_WRITE_BYTES:
+      // all of these are longlong
+      valtype = VT_ULLONG;
+      precision = 1;
+      flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+      value_styles = VAL_VALUE | VAL_PERCENT;
+      break;
+    case SIZES:
+      valtype = VT_LLONG;
+      precision = 1;
+      flavors = STATIC;
+      value_styles = VAL_VALUE;
+      break;
+    case ADDRESS:
+      valtype = VT_ADDRESS;
+      precision = 1;
+      flavors = STATIC;
+      value_styles = VAL_VALUE;
+      break;
+    case ONAME:
+      valtype = VT_LABEL;
+      precision = 0;
+      flavors = STATIC;
+      value_styles = VAL_VALUE;
+      break;
+    case HWCNTR: // We should call the other constructor for hwc metric
+    default:
+      abort ();
+    }
+  specify ();
+}
+
+// Constructor for linked HW counters (base counter)
+BaseMetric::BaseMetric (Hwcentry *ctr, const char* _aux, const char* _username,
+                       int v_styles, BaseMetric* _dependent_bm)
+{
+  hwc_init (ctr, _aux, _aux, _username, v_styles);
+  dependent_bm = _dependent_bm;
+}
+
+// Constructor for linked HW counters (derived counter)
+
+BaseMetric::BaseMetric (Hwcentry *ctr, const char *_aux, const char *_cmdname,
+                       const char *_username, int v_styles)
+{
+  hwc_init (ctr, _aux, _cmdname, _username, v_styles);
+}
+
+void
+BaseMetric::hwc_init (Hwcentry *ctr, const char* _aux, const char* _cmdname,
+                     const char* _username, int v_styles)
+{
+  init (HWCNTR);
+  aux = dbe_strdup (_aux);      // HWC identifier
+  cmd = dbe_strdup (_cmdname);  // may differ from _aux for cycles->time hwcs
+  username = dbe_strdup (_username);
+  flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+  value_styles = v_styles | VAL_PERCENT;
+  if ((value_styles & (VAL_TIMEVAL | VAL_VALUE)) == VAL_TIMEVAL)
+    valtype = VT_DOUBLE;
+  else
+    valtype = VT_ULLONG;
+  if (ABST_MEMSPACE_ENABLED (ctr->memop))
+    flavors |= DATASPACE; // only for ctrs with memop definitions
+  hw_ctr = ctr;
+  specify ();
+}
+
+// Constructor for derived metrics
+BaseMetric::BaseMetric (const char *_cmd, const char *_username,
+                       Definition *def)
+{
+  init (DERIVED);
+  cmd = dbe_strdup (_cmd);
+  username = dbe_strdup (_username);
+  aux = dbe_strdup (_cmd);
+  definition = def;
+  flavors = EXCLUSIVE | INCLUSIVE | ATTRIBUTED;
+  clock_unit = CUNIT_NULL; // should it be CUNIT_TIME or 0 or something?
+
+  /* we're not going to process packets for derived metrics */
+  packet_type = (ProfData_type) (-1);
+  value_styles = VAL_VALUE;
+  valtype = VT_DOUBLE;
+  precision = 1000;
+}
+
+// Copy constructor
+BaseMetric::BaseMetric (const BaseMetric& m)
+{
+  id = m.id;
+  type = m.type;
+  aux = dbe_strdup (m.aux);
+  cmd = dbe_strdup (m.cmd);
+  username = dbe_strdup (m.username);
+  flavors = m.flavors;
+  value_styles = m.value_styles;
+  valtype = m.valtype;
+  precision = m.precision;
+  hw_ctr = m.hw_ctr;
+  packet_type = m.packet_type;
+  zeroThreshold = m.zeroThreshold;
+  clock_unit = m.clock_unit;
+  for (int ii = 0; ii < NSUBTYPES; ii++)
+    default_visbits[ii] = m.default_visbits[ii];
+  if (m.cond_spec)
+    {
+      cond_spec = strdup (m.cond_spec);
+      cond = m.cond->copy ();
+    }
+  else
+    {
+      cond = NULL;
+      cond_spec = NULL;
+    }
+  if (m.val_spec)
+    {
+      val_spec = strdup (m.val_spec);
+      val = m.val->copy ();
+    }
+  else
+    {
+      val = NULL;
+      val_spec = NULL;
+    }
+  if (m.expr_spec)
+    {
+      expr_spec = strdup (m.expr_spec);
+      expr = m.expr->copy ();
+    }
+  else
+    {
+      expr = NULL;
+      expr_spec = NULL;
+    }
+  legend = dbe_strdup (m.legend);
+  definition = NULL;
+  if (m.definition)
+    definition = Definition::add_definition (m.definition->def);
+  dependent_bm = m.dependent_bm;
+}
+
+BaseMetric::~BaseMetric ()
+{
+  free (aux);
+  free (cmd);
+  free (cond_spec);
+  free (val_spec);
+  free (expr_spec);
+  free (legend);
+  free (username);
+  delete cond;
+  delete val;
+  delete expr;
+  delete definition;
+}
+
+bool
+BaseMetric::is_internal ()
+{
+  return (get_value_styles () & VAL_INTERNAL) != 0;
+}
+
+int
+BaseMetric::get_default_visbits (SubType subtype)
+{
+  int rc = VAL_NA;
+  switch (subtype)
+    {
+    case STATIC:
+    case EXCLUSIVE:
+      rc = default_visbits[0];
+      break;
+    case INCLUSIVE:
+      rc = default_visbits[1];
+      break;
+    default:
+      break;
+    }
+  return rc;
+}
+
+void
+BaseMetric::set_default_visbits (SubType subtype, int _visbits)
+{
+  switch (subtype)
+    {
+    case STATIC:
+    case EXCLUSIVE:
+      default_visbits[0] = _visbits;
+      break;
+    case INCLUSIVE:
+      default_visbits[1] = _visbits;
+      break;
+    default:
+      break;
+    }
+}
+
+void
+BaseMetric::set_cond_spec (char *_cond_spec)
+{
+  if (cond_spec)
+    {
+      free (cond_spec);
+      delete cond;
+      cond_spec = NULL;
+      cond = NULL;
+    }
+  if (_cond_spec)
+    {
+      cond = dbeSession->ql_parse (_cond_spec);
+      if (cond == NULL)
+       {
+         fprintf (stderr, GTXT ("Invalid expression in metric specification `%s'\n"), _cond_spec);
+         abort ();
+       }
+      cond_spec = dbe_strdup (_cond_spec);
+    }
+}
+
+void
+BaseMetric::set_val_spec (char *_val_spec)
+{
+  if (val_spec)
+    {
+      free (val_spec);
+      delete val;
+      val_spec = NULL;
+      val = NULL;
+    }
+  if (_val_spec)
+    {
+      val = dbeSession->ql_parse (_val_spec);
+      if (val == NULL)
+       {
+         fprintf (stderr, GTXT ("Invalid expression in metric specification `%s'\n"), _val_spec);
+         abort ();
+       }
+      val_spec = dbe_strdup (_val_spec);
+    }
+}
+
+void
+BaseMetric::set_expr_spec (char *_expr_spec)
+{
+  id = last_id++;
+  if (expr_spec)
+    {
+      free (expr_spec);
+      delete expr;
+      expr_spec = NULL;
+      expr = NULL;
+    }
+  if (_expr_spec)
+    {
+      expr = dbeSession->ql_parse (_expr_spec);
+      if (expr == NULL)
+       {
+         fprintf (stderr, GTXT ("Invalid expression in metric specification `%s'\n"), _expr_spec);
+         return;
+       }
+      expr_spec = dbe_strdup (_expr_spec);
+    }
+}
+
+void
+BaseMetric::specify_mstate_metric (int st)
+{
+  char buf[128];
+  snprintf (buf, sizeof (buf), NTXT ("MSTATE==%d"), st);
+  specify_prof_metric (buf);
+}
+
+void
+BaseMetric::specify_ompstate_metric (int st)
+{
+  char buf[128];
+  snprintf (buf, sizeof (buf), NTXT ("OMPSTATE==%d"), st);
+  specify_prof_metric (buf);
+}
+
+void
+BaseMetric::specify_prof_metric (char *_cond_spec)
+{
+  packet_type = DATA_CLOCK;
+  specify_metric (_cond_spec, NTXT ("NTICK_USEC")); // microseconds
+}
+
+void
+BaseMetric::specify_metric (char *_cond_spec, char *_val_spec)
+{
+  set_cond_spec (_cond_spec);
+  set_val_spec (_val_spec);
+}
+
+void
+BaseMetric::specify ()
+{
+  enum
+  {
+    IDLE_STATE_BITS =
+       (1 << OMP_IDLE_STATE) | (1 << OMP_IBAR_STATE) | (1 << OMP_EBAR_STATE) |
+       (1 << OMP_LKWT_STATE) | (1 << OMP_CTWT_STATE) | (1 << OMP_ODWT_STATE) |
+       (1 << OMP_ATWT_STATE) | (1 << OMP_TSKWT_STATE),
+    LMS_USER_BITS =
+       (1 << OMP_NO_STATE) | (1 << OMP_WORK_STATE) | (1 << OMP_SERL_STATE) |
+       (1 << OMP_RDUC_STATE)
+  };
+
+  char buf[256];
+  char buf2[256];
+  packet_type = (ProfData_type) - 1; // illegal value
+  clock_unit = CUNIT_TIME;
+  switch (type)
+    {
+    case SIZES:
+      username = dbe_strdup (GTXT ("Size"));
+      clock_unit = CUNIT_BYTES;
+      cmd = dbe_strdup (NTXT ("size"));
+      break;
+    case ADDRESS:
+      username = dbe_strdup (GTXT ("PC Address"));
+      cmd = dbe_strdup (NTXT ("address"));
+      break;
+    case ONAME:
+      username = dbe_strdup (GTXT ("Name"));
+      cmd = dbe_strdup (NTXT ("name"));
+      break;
+    case CP_LMS_SYSTEM:
+      username = dbe_strdup (GTXT ("System CPU Time"));
+      specify_mstate_metric (LMS_SYSTEM);
+      cmd = dbe_strdup (NTXT ("system"));
+      break;
+    case CP_TOTAL_CPU:
+      username = dbe_strdup (GTXT ("Total CPU Time"));
+      snprintf (buf, sizeof (buf),
+               "(MSTATE==%d)||(MSTATE==%d)||(MSTATE==%d)||(MSTATE==%d)",
+               LMS_USER, LMS_SYSTEM, LMS_TRAP, LMS_LINUX_CPU);
+      specify_prof_metric (buf);
+      cmd = dbe_strdup (NTXT ("totalcpu"));
+      break;
+    case CP_TOTAL:
+      username = dbe_strdup (GTXT ("Total Thread Time"));
+      snprintf (buf, sizeof (buf), NTXT ("(MSTATE!=%d)&&(MSTATE!=%d)"),
+               LMS_KERNEL_CPU, LMS_LINUX_CPU);
+      specify_prof_metric (buf);
+      cmd = dbe_strdup (NTXT ("total"));
+      break;
+    case CP_KERNEL_CPU:
+      username = dbe_strdup (GTXT ("Kernel CPU Time"));
+      specify_mstate_metric (LMS_KERNEL_CPU);
+      cmd = dbe_strdup (NTXT ("kcpu"));
+      break;
+    case OMP_MASTER_THREAD:
+      username = dbe_strdup (GTXT ("Master Thread Time"));
+      specify_prof_metric (NTXT ("LWPID==1"));
+      cmd = dbe_strdup (NTXT ("masterthread"));
+      break;
+    case CP_LMS_USER:
+      username = dbe_strdup (GTXT ("User CPU Time"));
+      specify_mstate_metric (LMS_USER);
+      cmd = dbe_strdup (NTXT ("user"));
+      break;
+    case CP_LMS_WAIT_CPU:
+      username = dbe_strdup (GTXT ("Wait CPU Time"));
+      specify_mstate_metric (LMS_WAIT_CPU);
+      cmd = dbe_strdup (NTXT ("wait"));
+      break;
+    case CP_LMS_USER_LOCK:
+      username = dbe_strdup (GTXT ("User Lock Time"));
+      specify_mstate_metric (LMS_USER_LOCK);
+      cmd = dbe_strdup (NTXT ("lock"));
+      break;
+    case CP_LMS_TFAULT:
+      username = dbe_strdup (GTXT ("Text Page Fault Time"));
+      specify_mstate_metric (LMS_TFAULT);
+      cmd = dbe_strdup (NTXT ("textpfault"));
+      break;
+    case CP_LMS_DFAULT:
+      username = dbe_strdup (GTXT ("Data Page Fault Time"));
+      specify_mstate_metric (LMS_DFAULT);
+      cmd = dbe_strdup (NTXT ("datapfault"));
+      break;
+    case CP_LMS_TRAP:
+      username = dbe_strdup (GTXT ("Trap CPU Time"));
+      specify_mstate_metric (LMS_TRAP);
+      cmd = dbe_strdup (NTXT ("trap"));
+      break;
+    case CP_LMS_KFAULT:
+      username = dbe_strdup (GTXT ("Kernel Page Fault Time"));
+      specify_mstate_metric (LMS_KFAULT);
+      cmd = dbe_strdup (NTXT ("kernelpfault"));
+      break;
+    case CP_LMS_SLEEP:
+      username = dbe_strdup (GTXT ("Sleep Time"));
+      specify_mstate_metric (LMS_SLEEP);
+      cmd = dbe_strdup (NTXT ("sleep"));
+      break;
+    case CP_LMS_STOPPED:
+      username = dbe_strdup (GTXT ("Stopped Time"));
+      specify_mstate_metric (LMS_STOPPED);
+      cmd = dbe_strdup (NTXT ("stop"));
+      break;
+    case OMP_OVHD:
+      username = dbe_strdup (GTXT ("OpenMP Overhead Time"));
+      specify_ompstate_metric (OMP_OVHD_STATE);
+      cmd = dbe_strdup (NTXT ("ompovhd"));
+      break;
+    case OMP_WORK:
+      username = dbe_strdup (GTXT ("OpenMP Work Time"));
+      snprintf (buf, sizeof (buf),
+               NTXT ("(OMPSTATE>=0) && (MSTATE==%d) && ((1<<OMPSTATE) & %d)"),
+               LMS_USER, LMS_USER_BITS);
+      specify_prof_metric (buf);
+      cmd = dbe_strdup (NTXT ("ompwork"));
+      break;
+    case OMP_WAIT:
+      username = dbe_strdup (GTXT ("OpenMP Wait Time"));
+      snprintf (buf, sizeof (buf),
+               "OMPSTATE>=0 && ((1<<OMPSTATE) & ((MSTATE!=%d) ? %d : %d))",
+               LMS_USER, (LMS_USER_BITS | IDLE_STATE_BITS), IDLE_STATE_BITS);
+      specify_prof_metric (buf);
+      cmd = dbe_strdup (NTXT ("ompwait"));
+      break;
+    case OMP_IBAR:
+      username = dbe_strdup (GTXT ("OpenMP Implicit Barrier Time"));
+      specify_ompstate_metric (OMP_IBAR_STATE);
+      cmd = dbe_strdup (NTXT ("ompibar"));
+      break;
+    case OMP_EBAR:
+      username = dbe_strdup (GTXT ("OpenMP Explicit Barrier Time"));
+      specify_ompstate_metric (OMP_EBAR_STATE);
+      cmd = dbe_strdup (NTXT ("ompebar"));
+      break;
+    case OMP_SERL:
+      username = dbe_strdup (GTXT ("OpenMP Serial Time"));
+      specify_ompstate_metric (OMP_SERL_STATE);
+      cmd = dbe_strdup (NTXT ("ompserl"));
+      break;
+    case OMP_RDUC:
+      username = dbe_strdup (GTXT ("OpenMP Reduction Time"));
+      specify_ompstate_metric (OMP_RDUC_STATE);
+      cmd = dbe_strdup (NTXT ("omprduc"));
+      break;
+    case OMP_LKWT:
+      username = dbe_strdup (GTXT ("OpenMP Lock Wait Time"));
+      specify_ompstate_metric (OMP_LKWT_STATE);
+      cmd = dbe_strdup (NTXT ("omplkwt"));
+      break;
+    case OMP_CTWT:
+      username = dbe_strdup (GTXT ("OpenMP Critical Section Wait Time"));
+      specify_ompstate_metric (OMP_CTWT_STATE);
+      cmd = dbe_strdup (NTXT ("ompctwt"));
+      break;
+    case OMP_ODWT:
+      username = dbe_strdup (GTXT ("OpenMP Ordered Section Wait Time"));
+      specify_ompstate_metric (OMP_ODWT_STATE);
+      cmd = dbe_strdup (NTXT ("ompodwt"));
+      break;
+    case SYNC_WAIT_TIME:
+      packet_type = DATA_SYNCH;
+      username = dbe_strdup (GTXT ("Sync Wait Time"));
+      snprintf (buf, sizeof (buf), NTXT ("(EVT_TIME)/%lld"),
+               (long long) (NANOSEC / METRIC_HR_PRECISION));
+      specify_metric (NULL, buf);
+      cmd = dbe_strdup (NTXT ("sync"));
+      break;
+    case SYNC_WAIT_COUNT:
+      packet_type = DATA_SYNCH;
+      username = dbe_strdup (GTXT ("Sync Wait Count"));
+      specify_metric (NULL, NTXT ("1"));
+      cmd = dbe_strdup (NTXT ("syncn"));
+      break;
+    case HEAP_ALLOC_CNT:
+      packet_type = DATA_HEAP;
+      username = dbe_strdup (GTXT ("Allocations"));
+      snprintf (buf, sizeof (buf), NTXT ("(HTYPE!=%d)&&(HTYPE!=%d)&&HVADDR"),
+               FREE_TRACE, MUNMAP_TRACE);
+      specify_metric (buf, NTXT ("1"));
+      cmd = dbe_strdup (NTXT ("heapalloccnt"));
+      break;
+    case HEAP_ALLOC_BYTES:
+      packet_type = DATA_HEAP;
+      username = dbe_strdup (GTXT ("Bytes Allocated"));
+      snprintf (buf, sizeof (buf), NTXT ("(HTYPE!=%d)&&(HTYPE!=%d)&&HVADDR"),
+               FREE_TRACE, MUNMAP_TRACE);
+      specify_metric (buf, NTXT ("HSIZE"));
+      cmd = dbe_strdup (NTXT ("heapallocbytes"));
+      break;
+    case HEAP_LEAK_CNT:
+      packet_type = DATA_HEAP;
+      username = dbe_strdup (GTXT ("Leaks"));
+      snprintf (buf, sizeof (buf), "(HTYPE!=%d)&&(HTYPE!=%d)&&HVADDR&&HLEAKED",
+               FREE_TRACE, MUNMAP_TRACE);
+      specify_metric (buf, NTXT ("1"));
+      cmd = dbe_strdup (NTXT ("heapleakcnt"));
+      break;
+    case HEAP_LEAK_BYTES:
+      packet_type = DATA_HEAP;
+      username = dbe_strdup (GTXT ("Bytes Leaked"));
+      snprintf (buf, sizeof (buf), NTXT ("(HTYPE!=%d)&&(HTYPE!=%d)&&HVADDR"),
+               FREE_TRACE, MUNMAP_TRACE);
+      specify_metric (buf, NTXT ("HLEAKED"));
+      cmd = dbe_strdup (NTXT ("heapleakbytes"));
+      break;
+
+    case IO_READ_CNT:
+      packet_type = DATA_IOTRACE;
+      username = dbe_strdup (GTXT ("Read Count"));
+      snprintf (buf, sizeof (buf), "(IOTYPE==%d)", READ_TRACE);
+      specify_metric (buf, NTXT ("1"));
+      cmd = dbe_strdup (NTXT ("ioreadcnt"));
+      break;
+    case IO_WRITE_CNT:
+      packet_type = DATA_IOTRACE;
+      username = dbe_strdup (GTXT ("Write Count"));
+      snprintf (buf, sizeof (buf), "(IOTYPE==%d)", WRITE_TRACE);
+      specify_metric (buf, NTXT ("1"));
+      cmd = dbe_strdup (NTXT ("iowritecnt"));
+      break;
+    case IO_OTHER_CNT:
+      packet_type = DATA_IOTRACE;
+      username = dbe_strdup (GTXT ("Other I/O Count"));
+      snprintf (buf, sizeof (buf), "(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)",
+               OPEN_TRACE, CLOSE_TRACE, OTHERIO_TRACE);
+      specify_metric (buf, NTXT ("1"));
+      cmd = dbe_strdup (NTXT ("ioothercnt"));
+      break;
+    case IO_ERROR_CNT:
+      packet_type = DATA_IOTRACE;
+      username = dbe_strdup (GTXT ("I/O Error Count"));
+      snprintf (buf, sizeof (buf),
+        "(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)",
+        READ_TRACE_ERROR, WRITE_TRACE_ERROR, OPEN_TRACE_ERROR,
+        CLOSE_TRACE_ERROR, OTHERIO_TRACE_ERROR);
+      specify_metric (buf, NTXT ("1"));
+      cmd = dbe_strdup (NTXT ("ioerrorcnt"));
+      break;
+    case IO_READ_BYTES:
+      packet_type = DATA_IOTRACE;
+      username = dbe_strdup (GTXT ("Read Bytes"));
+      snprintf (buf, sizeof (buf), NTXT ("(IOTYPE==%d)&&IONBYTE"),
+               READ_TRACE);
+      specify_metric (buf, NTXT ("IONBYTE"));
+      cmd = dbe_strdup (NTXT ("ioreadbytes"));
+      break;
+    case IO_WRITE_BYTES:
+      packet_type = DATA_IOTRACE;
+      username = dbe_strdup (GTXT ("Write Bytes"));
+      snprintf (buf, sizeof (buf), "(IOTYPE==%d)&&IONBYTE", WRITE_TRACE);
+      specify_metric (buf, NTXT ("IONBYTE"));
+      cmd = dbe_strdup (NTXT ("iowritebytes"));
+      break;
+    case IO_READ_TIME:
+      packet_type = DATA_IOTRACE;
+      username = dbe_strdup (GTXT ("Read Time"));
+      snprintf (buf, sizeof (buf), "(IOTYPE==%d)&&EVT_TIME", READ_TRACE);
+      snprintf (buf2, sizeof (buf2), NTXT ("(EVT_TIME)/%lld"),
+               (long long) (NANOSEC / METRIC_HR_PRECISION));
+      specify_metric (buf, buf2);
+      cmd = dbe_strdup (NTXT ("ioreadtime"));
+      break;
+    case IO_WRITE_TIME:
+      packet_type = DATA_IOTRACE;
+      username = dbe_strdup (GTXT ("Write Time"));
+      snprintf (buf, sizeof (buf), NTXT ("(IOTYPE==%d)&&EVT_TIME"),
+               WRITE_TRACE);
+      snprintf (buf2, sizeof (buf2), NTXT ("(EVT_TIME)/%lld"),
+               (long long) (NANOSEC / METRIC_HR_PRECISION));
+      specify_metric (buf, buf2);
+      cmd = dbe_strdup (NTXT ("iowritetime"));
+      break;
+    case IO_OTHER_TIME:
+      packet_type = DATA_IOTRACE;
+      username = dbe_strdup (GTXT ("Other I/O Time"));
+      snprintf (buf, sizeof (buf),
+               "(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)&&EVT_TIME",
+               OPEN_TRACE, CLOSE_TRACE, OTHERIO_TRACE);
+      snprintf (buf2, sizeof (buf2), NTXT ("(EVT_TIME)/%lld"),
+               (long long) (NANOSEC / METRIC_HR_PRECISION));
+      specify_metric (buf, buf2);
+      cmd = dbe_strdup (NTXT ("ioothertime"));
+      break;
+    case IO_ERROR_TIME:
+      packet_type = DATA_IOTRACE;
+      username = dbe_strdup (GTXT ("I/O Error Time"));
+      snprintf (buf, sizeof (buf),
+               "(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)||(IOTYPE==%d)&&EVT_TIME",
+               READ_TRACE_ERROR, WRITE_TRACE_ERROR, OPEN_TRACE_ERROR,
+               CLOSE_TRACE_ERROR, OTHERIO_TRACE_ERROR);
+      snprintf (buf2, sizeof (buf2), NTXT ("(EVT_TIME)/%lld"),
+               (long long) (NANOSEC / METRIC_HR_PRECISION));
+      specify_metric (buf, buf2);
+      cmd = dbe_strdup (NTXT ("ioerrortime"));
+      break;
+    case RACCESS:
+      packet_type = DATA_RACE;
+      username = dbe_strdup (GTXT ("Race Accesses"));
+      specify_metric (NULL, NTXT ("RCNT"));
+      cmd = dbe_strdup (NTXT ("raccess"));
+      break;
+    case DEADLOCKS:
+      packet_type = DATA_DLCK;
+      username = dbe_strdup (GTXT ("Deadlocks"));
+      specify_metric (NULL, NTXT ("1"));
+      cmd = dbe_strdup (NTXT ("deadlocks"));
+      break;
+    case HWCNTR:
+      packet_type = DATA_HWC;
+      // username, cmd, and aux set by hwc constructor
+      if (valtype == VT_DOUBLE)
+       {
+         if (hw_ctr->timecvt > 0)  // CPU cycles
+           specify_metric (NULL, NTXT ("((HWCINT*1000000)/FREQ_MHZ)"));
+         else if (hw_ctr->timecvt < 0)
+           { // reference clock (frequency is -timecvt MHz)
+             snprintf (buf, sizeof (buf), NTXT ("((HWCINT*1000000)/%d)"), -hw_ctr->timecvt);
+             specify_metric (NULL, buf);
+           }
+         else  // shouldn't happen
+           specify_metric (NULL, NTXT ("0"));
+         // resulting unit: seconds * 1e12
+         precision = 1000000LL * 1000000LL; // Seconds * 1e12
+       }
+      else
+       {
+         specify_metric (NULL, NTXT ("HWCINT"));
+         precision = 1;
+       }
+      break;
+    case OMP_MSTR:
+    case OMP_SNGL:
+    case OMP_ORDD:
+    case OMP_NONE:
+    default:
+      username = dbe_strdup (GTXT ("****"));
+      fprintf (stderr, "BaseMetric::init Undefined basemetric %s\n",
+              get_basetype_name ());
+    }
+}
+
+#define CASE_S(x)   case x: s = (char *) #x; break
+char *
+BaseMetric::get_basetype_name ()
+{
+  static char buf[128];
+  char *s;
+  switch (type)
+    {
+      CASE_S (CP_LMS_SYSTEM);
+      CASE_S (CP_TOTAL_CPU);
+      CASE_S (CP_TOTAL);
+      CASE_S (OMP_MASTER_THREAD);
+      CASE_S (CP_LMS_USER);
+      CASE_S (CP_LMS_WAIT_CPU);
+      CASE_S (CP_LMS_USER_LOCK);
+      CASE_S (CP_LMS_TFAULT);
+      CASE_S (CP_LMS_DFAULT);
+      CASE_S (CP_LMS_TRAP);
+      CASE_S (CP_LMS_KFAULT);
+      CASE_S (CP_LMS_SLEEP);
+      CASE_S (CP_LMS_STOPPED);
+      CASE_S (OMP_NONE);
+      CASE_S (OMP_OVHD);
+      CASE_S (OMP_WORK);
+      CASE_S (OMP_IBAR);
+      CASE_S (OMP_EBAR);
+      CASE_S (OMP_WAIT);
+      CASE_S (OMP_SERL);
+      CASE_S (OMP_RDUC);
+      CASE_S (OMP_LKWT);
+      CASE_S (OMP_CTWT);
+      CASE_S (OMP_ODWT);
+      CASE_S (OMP_MSTR);
+      CASE_S (OMP_SNGL);
+      CASE_S (OMP_ORDD);
+      CASE_S (CP_KERNEL_CPU);
+      CASE_S (SYNC_WAIT_TIME);
+      CASE_S (IO_READ_TIME);
+      CASE_S (IO_WRITE_TIME);
+      CASE_S (IO_OTHER_TIME);
+      CASE_S (IO_ERROR_TIME);
+      CASE_S (HWCNTR);
+      CASE_S (SYNC_WAIT_COUNT);
+      CASE_S (HEAP_ALLOC_CNT);
+      CASE_S (HEAP_LEAK_CNT);
+      CASE_S (IO_READ_CNT);
+      CASE_S (IO_WRITE_CNT);
+      CASE_S (IO_OTHER_CNT);
+      CASE_S (IO_ERROR_CNT);
+      CASE_S (RACCESS);
+      CASE_S (DEADLOCKS);
+      CASE_S (HEAP_ALLOC_BYTES);
+      CASE_S (HEAP_LEAK_BYTES);
+      CASE_S (IO_READ_BYTES);
+      CASE_S (IO_WRITE_BYTES);
+      CASE_S (SIZES);
+      CASE_S (ADDRESS);
+      CASE_S (ONAME);
+      CASE_S (DERIVED);
+    default:
+      s = NTXT ("???");
+      break;
+    }
+  snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, type);
+  buf[sizeof (buf) - 1] = 0;
+  return buf;
+}
+
+char *
+BaseMetric::dump ()
+{
+  int len = 4;
+  char *msg = dbe_sprintf (NTXT ("id=%d %s aux='%s' cmd='%s' user_name='%s' expr_spec='%s'\n"
+                                "%*c cond_spec='%s' val_spec='%s'"),
+                          id, get_basetype_name (), STR (aux), STR (cmd),
+                          STR (username), STR (expr_spec),
+                          len, ' ', STR (cond_spec), STR (val_spec));
+  return msg;
+}
+
+Histable *
+BaseMetric::get_comparable_obj (Histable *obj)
+{
+  if (obj == NULL || expr == NULL)
+    return obj;
+  if (strncmp (expr_spec, NTXT ("EXPGRID=="), 9) == 0)
+    {
+      int n = atoi (expr_spec + 9);
+      Vector<Histable *> *cmpObjs = obj->get_comparable_objs ();
+      if (cmpObjs && cmpObjs->size () >= n)
+       return cmpObjs->get (n - 1);
+      return NULL;
+    }
+  return obj;
+}
+
+Definition::Definition (opType _op)
+{
+  op = _op;
+  bm = NULL;
+  arg1 = NULL;
+  arg2 = NULL;
+  def = NULL;
+  dependencies = NULL;
+  map = NULL;
+  index = 0;
+}
+
+Definition::~Definition ()
+{
+  delete arg1;
+  delete arg2;
+  delete dependencies;
+  delete[] map;
+}
+
+Vector<BaseMetric *> *
+Definition::get_dependencies ()
+{
+  if (dependencies == NULL)
+    {
+      if (arg1 && arg1->bm && arg2 && arg2->bm)
+       {
+         dependencies = new Vector<BaseMetric *>(2);
+         arg1->index = dependencies->size ();
+         dependencies->append (arg1->bm);
+         arg2->index = dependencies->size ();
+         dependencies->append (arg2->bm);
+         map = new long[2];
+       }
+    }
+  return dependencies;
+}
+
+long *
+Definition::get_map ()
+{
+  get_dependencies ();
+  return map;
+}
+
+Definition *
+Definition::add_definition (char *_def)
+{
+  // parse the definition
+  char *op_ptr = strchr (_def, '/');
+  if (op_ptr == NULL)
+    {
+      // it's a primitive metric
+      BaseMetric *bm = dbeSession->find_base_reg_metric (_def);
+      if (bm)
+       {
+         Definition *p = new Definition (opPrimitive);
+         p->bm = bm;
+         return p;
+       }
+      return NULL; // BaseMetric is not yet specified
+    }
+  Definition *p2 = add_definition (op_ptr + 1);
+  if (p2 == NULL)
+    return NULL;
+  _def = dbe_strdup (_def);
+  op_ptr = strchr (_def, '/');
+  *op_ptr = 0;
+  Definition *p1 = add_definition (_def);
+  if (p1)
+    {
+      *op_ptr = '/';
+      Definition *p = new Definition (opDivide);
+      p->arg1 = p1;
+      p->arg2 = p2;
+      p->def = _def;
+      return p;
+    }
+  free (_def);
+  delete p1;
+  delete p2;
+  return NULL;
+}
+
+double
+Definition::eval (long *indexes, TValue *values)
+{
+  switch (op)
+    {
+    case opPrimitive:
+      return values[indexes[index]].to_double ();
+    case opDivide:
+      {
+       double x2 = arg2->eval (indexes, values);
+       if (x2 == 0)
+         return 0.;
+       double x1 = arg1->eval (indexes, values);
+       return x1 / x2;
+      }
+    default:
+      fprintf (stderr, GTXT ("unknown expression\n"));
+      return 0.;
+    }
+}
diff --git a/gprofng/src/BaseMetric.h b/gprofng/src/BaseMetric.h
new file mode 100644 (file)
index 0000000..e056993
--- /dev/null
@@ -0,0 +1,246 @@
+/* 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 _BASEMETRIC_H
+#define _BASEMETRIC_H
+
+#include "dbe_structs.h"
+#include "hwcentry.h"
+#include "Table.h"
+
+// METRIC_*_PRECISION determine the least threshold value
+// for time measured metrics. Any event that counts for less
+// than 1sec/METRIC_PRECISION is discarded.
+#define METRIC_SIG_PRECISION    MICROSEC
+#define METRIC_HR_PRECISION     MICROSEC
+
+class Expression;
+class Definition;
+class Histable;
+template <class ITEM> class Vector;
+
+class BaseMetric
+{
+public:
+  // sync enum changes with AnMetric.java
+  enum Type
+  { // Subtype==STATIC metrics:
+    ONAME = 1,  //ONAME must be 1
+    SIZES,
+    ADDRESS,
+    // Clock Profiling, Derived Metrics:
+    CP_TOTAL,
+    CP_TOTAL_CPU,
+    // Clock profiling, Solaris Microstates (LMS_* defines)
+    CP_LMS_USER,
+    CP_LMS_SYSTEM,
+    CP_LMS_TRAP,
+    CP_LMS_TFAULT,
+    CP_LMS_DFAULT,
+    CP_LMS_KFAULT,
+    CP_LMS_USER_LOCK,
+    CP_LMS_SLEEP,
+    CP_LMS_WAIT_CPU,
+    CP_LMS_STOPPED,
+    // Kernel clock profiling
+    CP_KERNEL_CPU,
+    // Sync Tracing
+    SYNC_WAIT_TIME,
+    SYNC_WAIT_COUNT,
+    // HWC
+    HWCNTR,
+    // Heap Tracing:
+    HEAP_ALLOC_CNT,
+    HEAP_ALLOC_BYTES,
+    HEAP_LEAK_CNT,
+    HEAP_LEAK_BYTES,
+    // I/O Tracing:
+    IO_READ_BYTES,
+    IO_READ_CNT,
+    IO_READ_TIME,
+    IO_WRITE_BYTES,
+    IO_WRITE_CNT,
+    IO_WRITE_TIME,
+    IO_OTHER_CNT,
+    IO_OTHER_TIME,
+    IO_ERROR_CNT,
+    IO_ERROR_TIME,
+    // MPI Tracing:
+    MPI_TIME,
+    MPI_SEND,
+    MPI_BYTES_SENT,
+    MPI_RCV,
+    MPI_BYTES_RCVD,
+    MPI_OTHER,
+    // OMP states:
+    OMP_NONE,
+    OMP_OVHD,
+    OMP_WORK,
+    OMP_IBAR,
+    OMP_EBAR,
+    OMP_WAIT,
+    OMP_SERL,
+    OMP_RDUC,
+    OMP_LKWT,
+    OMP_CTWT,
+    OMP_ODWT,
+    OMP_MSTR,
+    OMP_SNGL,
+    OMP_ORDD,
+    OMP_MASTER_THREAD,
+    // MPI states:
+    MPI_WORK,
+    MPI_WAIT,
+    // Races and Deadlocks
+    RACCESS,
+    DEADLOCKS,
+    // Derived Metrics
+    DERIVED
+  };
+
+  // sync enum changes with AnMetric.java
+  enum SubType
+  {
+    STATIC      = 1, // Type==SIZES, ADDRESS, ONAME
+    EXCLUSIVE   = 2,
+    INCLUSIVE   = 4,
+    ATTRIBUTED  = 8,
+    DATASPACE   = 16 // Can be accessed in dataspace views
+  };
+
+  BaseMetric (Type t);
+  BaseMetric (Hwcentry *ctr, const char* _aux, const char* _cmdname,
+             const char* _username, int v_styles); // depended bm
+  BaseMetric (Hwcentry *ctr, const char* _aux, const char* _username,
+             int v_styles, BaseMetric* _depended_bm = NULL); // master bm
+  BaseMetric (const char *_cmd, const char *_username, Definition *def); // derived metrics
+  BaseMetric (const BaseMetric& m);
+  virtual ~BaseMetric ();
+
+  int get_id ()                     { return id; }
+  Type get_type ()                  { return type; }
+  Hwcentry *get_hw_ctr ()           { return hw_ctr; }
+  char *get_aux ()                  { return aux; }
+  char *get_username ()             { return username; }
+  char *get_cmd ()                  { return cmd; }
+  int get_flavors ()                { return flavors; }
+  int get_clock_unit ()             { return clock_unit; }
+  long long get_precision ()        { return precision; }
+  ValueTag get_vtype ()             { return valtype; }
+  int get_value_styles ()           { return value_styles; }
+  bool is_zeroThreshold ()          { return zeroThreshold; }
+  ProfData_type get_packet_type ()  { return packet_type; }
+  Expression *get_cond ()           { return cond; }
+  Expression *get_val ()            { return val; }
+  Expression *get_expr ()           { return expr; }
+  char *get_expr_spec ()            { return expr_spec; }
+  Definition *get_definition ()     { return definition; };
+  BaseMetric *get_dependent_bm ()   { return dependent_bm; };
+
+  bool
+  comparable ()
+  {
+    return val_spec != NULL || type == DERIVED || type == SIZES || type == ADDRESS;
+  }
+
+  // setters..
+  void set_default_visbits (SubType subtype, int _visbits);
+  void set_id (int _id)         { id = _id; }   //TBR, if possible
+  // For comparison, set which packets to eval:
+  void set_expr_spec (char *_expr_spec);
+  void set_cond_spec (char *_cond_spec);
+  int get_default_visbits (SubType subtype);
+  char *dump ();
+  Histable *get_comparable_obj (Histable *obj);
+  bool is_internal ();          // Invisible for users
+
+  char *legend;                 // for comparison: add'l column text
+
+private:
+  BaseMetric *dependent_bm;     // for HWCs only: a link to the timecvt metric
+  Expression *cond;             // determines which packets to evaluate
+  char *cond_spec;              // used to generate "cond"
+  Expression *val;              // determines the numeric value for packet
+  char *val_spec;               // used to generate "val"
+  Expression *expr; // for comparison: an additional expression to determine
+                   // which packets to eval. Should be NULL otherwise.
+  char *expr_spec;                  // used to generate "expr"
+  int id;                           // unique id (assigned to last_id @ "new")
+  Type type;                        // e.g. HWCNTR
+  char *aux;                        // for HWCs only: Hwcentry ctr->name
+  char *cmd;                        // the .rc metric command, e.g. "total"
+  char *username;                   // e.g. "GTXT("Total Wait Time")"
+  int flavors;                      // bitmask of SubType capabilities
+  int value_styles;                 // bitmask of ValueType capabilities
+  static const int NSUBTYPES = 2;   // STATIC/EXCLUSIVE, INCLUSIVE
+  int default_visbits[NSUBTYPES];   // ValueType, e.g. VAL_VALUE|VAL_TIMEVAL
+  ValueTag valtype;                 // e.g. VT_LLONG
+  long long precision;              // e.g. METRIC_SIG_PRECISION, 1, etc.
+  Hwcentry *hw_ctr;                 // HWC definition
+  ProfData_type packet_type;        // e.g. DATA_HWC, or -1 for N/A
+  bool zeroThreshold;               // deadlock stuff
+  Presentation_clock_unit clock_unit;
+
+  static int last_id;           // incremented by 1 w/ every "new". Not MT-safe
+  Definition *definition;
+
+  void hwc_init (Hwcentry *ctr, const char* _aux, const char* _cmdname, const char* _username, int v_styles);
+  void init (Type t);
+  char *get_basetype_name ();
+  void specify ();
+  void specify_metric (char *_cond_spec, char *_val_spec);
+  void set_val_spec (char *_val_spec);
+  void specify_mstate_metric (int st);
+  void specify_ompstate_metric (int st);
+  void specify_prof_metric (char *_cond_spec);
+};
+
+class Definition
+{
+public:
+
+  enum opType
+  {
+    opNULL,
+    opPrimitive,
+    opDivide
+  };
+
+  Definition (opType _op);
+  ~Definition ();
+  static Definition *add_definition (char *_def);
+  Vector<BaseMetric *> *get_dependencies ();
+  long *get_map ();
+  double eval (long *indexes, TValue *values);
+
+  opType op;
+  Definition *arg1;
+  Definition *arg2;
+  char *def;
+
+private:
+  BaseMetric *bm;
+  long *map;
+  Vector<BaseMetric *> *dependencies;
+  long index;
+};
+
+#endif  /* _BASEMETRIC_H */
+
diff --git a/gprofng/src/BaseMetricTreeNode.cc b/gprofng/src/BaseMetricTreeNode.cc
new file mode 100644 (file)
index 0000000..2d1db99
--- /dev/null
@@ -0,0 +1,329 @@
+/* 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 <stdio.h>
+#include <strings.h>
+#include <limits.h>
+#include <sys/param.h>
+
+#include "hwcentry.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "Expression.h"
+#include "Metric.h"
+#include "Table.h"
+#include "i18n.h"
+#include "debug.h"
+
+BaseMetricTreeNode::BaseMetricTreeNode ()
+{
+  init_vars ();
+  build_basic_tree ();
+}
+
+BaseMetricTreeNode::BaseMetricTreeNode (BaseMetric *item)
+{
+  init_vars ();
+  bm = item;
+  name = dbe_strdup (bm->get_cmd ());
+  uname = dbe_strdup (bm->get_username ());
+  unit = NULL; //YXXX populate from base_metric (requires updating base_metric)
+  unit_uname = NULL;
+}
+
+BaseMetricTreeNode::BaseMetricTreeNode (const char *_name, const char *_uname,
+                                   const char *_unit, const char *_unit_uname)
+{
+  init_vars ();
+  name = dbe_strdup (_name);
+  uname = dbe_strdup (_uname);
+  unit = dbe_strdup (_unit);
+  unit_uname = dbe_strdup (_unit_uname);
+}
+
+void
+BaseMetricTreeNode::init_vars ()
+{
+  name = NULL;
+  uname = NULL;
+  unit = NULL;
+  unit_uname = NULL;
+  root = this;
+  parent = NULL;
+  children = new Vector<BaseMetricTreeNode*>;
+  isCompositeMetric = false;
+  bm = NULL;
+  registered = false;
+  num_registered_descendents = 0;
+}
+
+BaseMetricTreeNode::~BaseMetricTreeNode ()
+{
+  children->destroy ();
+  delete children;
+  free (name);
+  free (uname);
+  free (unit);
+  free (unit_uname);
+}
+
+BaseMetricTreeNode *
+BaseMetricTreeNode::register_metric (BaseMetric *item)
+{
+  BaseMetricTreeNode *found = root->find (item->get_cmd ());
+  if (!found)
+    {
+      switch (item->get_type ())
+       {
+       case BaseMetric::CP_TOTAL:
+         found = root->find (L_CP_TOTAL);
+         break;
+       case BaseMetric::CP_TOTAL_CPU:
+         found = root->find (L_CP_TOTAL_CPU);
+         break;
+       }
+      if (found && found->bm == NULL)
+       found->bm = item;
+    }
+  if (!found)
+    {
+      switch (item->get_type ())
+       {
+       case BaseMetric::HEAP_ALLOC_BYTES:
+       case BaseMetric::HEAP_ALLOC_CNT:
+       case BaseMetric::HEAP_LEAK_BYTES:
+       case BaseMetric::HEAP_LEAK_CNT:
+         found = root->find (get_prof_data_type_name (DATA_HEAP));
+         break;
+       case BaseMetric::CP_KERNEL_CPU:
+       case BaseMetric::CP_TOTAL:
+         found = root->find (get_prof_data_type_name (DATA_CLOCK));
+         break;
+       case BaseMetric::CP_LMS_DFAULT:
+       case BaseMetric::CP_LMS_TFAULT:
+       case BaseMetric::CP_LMS_KFAULT:
+       case BaseMetric::CP_LMS_STOPPED:
+       case BaseMetric::CP_LMS_WAIT_CPU:
+       case BaseMetric::CP_LMS_SLEEP:
+       case BaseMetric::CP_LMS_USER_LOCK:
+       case BaseMetric::CP_TOTAL_CPU:
+         found = root->find (L_CP_TOTAL);
+         break;
+       case BaseMetric::CP_LMS_USER:
+       case BaseMetric::CP_LMS_SYSTEM:
+       case BaseMetric::CP_LMS_TRAP:
+         found = root->find (L_CP_TOTAL_CPU);
+         break;
+       case BaseMetric::HWCNTR:
+         found = root->find ((item->get_flavors () & BaseMetric::DATASPACE) != 0 ?
+                             L2_HWC_DSPACE : L2_HWC_GENERAL);
+         break;
+       case BaseMetric::SYNC_WAIT_TIME:
+       case BaseMetric::SYNC_WAIT_COUNT:
+         found = root->find (get_prof_data_type_name (DATA_SYNCH));
+         break;
+       case BaseMetric::OMP_WORK:
+       case BaseMetric::OMP_WAIT:
+       case BaseMetric::OMP_OVHD:
+         found = root->find (get_prof_data_type_name (DATA_OMP));
+         break;
+       case BaseMetric::IO_READ_TIME:
+       case BaseMetric::IO_READ_BYTES:
+       case BaseMetric::IO_READ_CNT:
+       case BaseMetric::IO_WRITE_TIME:
+       case BaseMetric::IO_WRITE_BYTES:
+       case BaseMetric::IO_WRITE_CNT:
+       case BaseMetric::IO_OTHER_TIME:
+       case BaseMetric::IO_OTHER_CNT:
+       case BaseMetric::IO_ERROR_TIME:
+       case BaseMetric::IO_ERROR_CNT:
+         found = root->find (get_prof_data_type_name (DATA_IOTRACE));
+         break;
+       case BaseMetric::ONAME:
+       case BaseMetric::SIZES:
+       case BaseMetric::ADDRESS:
+         found = root->find (L1_STATIC);
+         break;
+       default:
+         found = root->find (L1_OTHER);
+         break;
+       }
+      assert (found != NULL);
+      switch (item->get_type ())
+       {
+       case BaseMetric::CP_TOTAL:
+       case BaseMetric::CP_TOTAL_CPU:
+         found->isCompositeMetric = true;
+         break;
+       }
+      found = found->add_child (item);
+    }
+  register_node (found);
+  return found;
+}
+
+void
+BaseMetricTreeNode::register_node (BaseMetricTreeNode *node)
+{
+  if (!node->registered)
+    {
+      node->registered = true;
+      BaseMetricTreeNode *tmp = node->parent;
+      while (tmp)
+       {
+         tmp->num_registered_descendents++;
+         tmp = tmp->parent;
+       }
+    }
+}
+
+BaseMetricTreeNode *
+BaseMetricTreeNode::find (const char *_name)
+{
+  BaseMetricTreeNode *found = NULL;
+  if (dbe_strcmp (get_name (), _name) == 0)
+    return this;
+  if (bm && dbe_strcmp (bm->get_cmd (), _name) == 0)
+    return this;
+  BaseMetricTreeNode *child;
+  int index;
+
+  Vec_loop (BaseMetricTreeNode*, children, index, child)
+  {
+    found = child->find (_name);
+    if (found)
+      return found;
+  }
+  return NULL;
+}
+
+static void
+int_get_registered_descendents (BaseMetricTreeNode* curr,
+                         Vector<BaseMetricTreeNode*> *dest, bool nearest_only)
+{
+  if (!curr)
+    return;
+  if (curr->is_registered ())
+    {
+      dest->append (curr);
+      if (nearest_only)
+       return; // soon as we hit a live node, stop following branch
+    }
+  int index;
+  BaseMetricTreeNode *child;
+
+  Vec_loop (BaseMetricTreeNode*, curr->get_children (), index, child)
+  {
+    int_get_registered_descendents (child, dest, nearest_only);
+  }
+}
+
+void
+BaseMetricTreeNode::get_nearest_registered_descendents (Vector<BaseMetricTreeNode*> *dest)
+{
+  if (!dest || dest->size () != 0)
+    abort ();
+  bool nearest_only = true;
+  int_get_registered_descendents (this, dest, nearest_only);
+}
+
+void
+BaseMetricTreeNode::get_all_registered_descendents (Vector<BaseMetricTreeNode*> *dest)
+{
+  if (!dest || dest->size () != 0)
+    abort ();
+  bool nearest_only = false;
+  int_get_registered_descendents (this, dest, nearest_only);
+}
+
+char *
+BaseMetricTreeNode::get_description ()
+{
+  if (bm)
+    {
+      Hwcentry* hw_ctr = bm->get_hw_ctr ();
+      if (hw_ctr)
+       return hw_ctr->short_desc;
+    }
+  return NULL;
+}
+
+void
+BaseMetricTreeNode::build_basic_tree ()
+{
+#define TREE_INSERT_DATA_TYPE(t) add_child(get_prof_data_type_name (t), get_prof_data_type_uname (t))
+  BaseMetricTreeNode *level1, *level2;
+  // register L1_DURATION here because it has a value but is not a true metric
+  register_node (add_child (L1_DURATION, L1_DURATION_UNAME, UNIT_SECONDS,
+                           UNIT_SECONDS_UNAME));
+  register_node (add_child (L1_GCDURATION, L1_GCDURATION_UNAME, UNIT_SECONDS,
+                           UNIT_SECONDS_UNAME));
+  TREE_INSERT_DATA_TYPE (DATA_HEAP);
+  level1 = TREE_INSERT_DATA_TYPE (DATA_CLOCK);
+  level1 = level1->add_child (L_CP_TOTAL, GTXT ("XXX Total Thread Time"));
+  level1->isCompositeMetric = true;
+  level2 = level1->add_child (L_CP_TOTAL_CPU, GTXT ("XXX Total CPU Time"));
+  level2->isCompositeMetric = true;
+
+  add_child (L1_OTHER, L1_OTHER_UNAME);
+  level1 = TREE_INSERT_DATA_TYPE (DATA_HWC);
+  level1->add_child (L2_HWC_DSPACE, L2_HWC_DSPACE_UNAME);
+  level1->add_child (L2_HWC_GENERAL, L2_HWC_GENERAL_UNAME);
+  TREE_INSERT_DATA_TYPE (DATA_SYNCH);
+  TREE_INSERT_DATA_TYPE (DATA_OMP);
+  TREE_INSERT_DATA_TYPE (DATA_IOTRACE);
+  add_child (L1_STATIC, L1_STATIC_UNAME);
+}
+
+BaseMetricTreeNode *
+BaseMetricTreeNode::add_child (BaseMetric *item)
+{
+  return add_child (new BaseMetricTreeNode (item));
+}
+
+BaseMetricTreeNode *
+BaseMetricTreeNode::add_child (const char * _name, const char *_uname,
+                              const char * _unit, const char * _unit_uname)
+{
+  return add_child (new BaseMetricTreeNode (_name, _uname, _unit, _unit_uname));
+}
+
+BaseMetricTreeNode *
+BaseMetricTreeNode::add_child (BaseMetricTreeNode *new_node)
+{
+  new_node->parent = this;
+  new_node->root = root;
+  children->append (new_node);
+  return new_node;
+}
+
+char *
+BaseMetricTreeNode::dump ()
+{
+  int len = 4;
+  char *s = bm ? bm->dump () : dbe_strdup ("<no base metric>");
+  char *msg = dbe_sprintf ("%s\n%*c %*c unit='%s' unit_uname='%s' uname='%s' name='%s'\n",
+                          STR (s), len, ' ', len, ' ',
+                          STR (get_unit_uname ()), STR (get_unit ()),
+                          STR (get_user_name ()), STR (get_name ()));
+  free (s);
+  return msg;
+}
diff --git a/gprofng/src/BaseMetricTreeNode.h b/gprofng/src/BaseMetricTreeNode.h
new file mode 100644 (file)
index 0000000..0076dff
--- /dev/null
@@ -0,0 +1,100 @@
+/* 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 _BASEMETRICTREENODE_H
+#define _BASEMETRICTREENODE_H
+
+#include "BaseMetric.h"
+
+// Unit values
+#define UNIT_SECONDS            "SECONDS"
+#define UNIT_SECONDS_UNAME      GTXT("secs.")
+#define UNIT_BYTES              "BYTES"
+#define UNIT_BYTES_UNAME        GTXT("bytes")
+
+// Name values for intermediate parent nodes that aren't defined elsewhere
+#define L1_DURATION             "PROFDATA_TYPE_DURATION"
+#define L1_DURATION_UNAME       GTXT("Experiment Duration")
+#define L1_GCDURATION           "PROFDATA_TYPE_GCDURATION"
+#define L1_GCDURATION_UNAME     GTXT("Java Garbage Collection Duration")
+#define L2_HWC_DSPACE           "PROFDATA_TYPE_HWC_DSPACE"
+#define L2_HWC_DSPACE_UNAME     GTXT("Memoryspace Hardware Counters")
+#define L2_HWC_GENERAL          "PROFDATA_TYPE_HWC_GENERAL"
+#define L2_HWC_GENERAL_UNAME    GTXT("General Hardware Counters")
+#define L1_MPI_STATES           "PROFDATA_TYPE_MPI_STATES"
+#define L1_MPI_STATES_UNAME     GTXT("MPI States")
+#define L1_OTHER                "PROFDATA_TYPE_OTHER"
+#define L1_OTHER_UNAME          GTXT("Derived and Other Metrics")
+#define L1_STATIC               "PROFDATA_TYPE_STATIC"
+#define L1_STATIC_UNAME         GTXT("Static")
+#define L_CP_TOTAL              "L_CP_TOTAL"
+#define L_CP_TOTAL_CPU          "L_CP_TOTAL_CPU"
+
+class BaseMetricTreeNode
+{
+public:
+  BaseMetricTreeNode (); // builds basic metric tree (not including HWCs)
+  virtual ~BaseMetricTreeNode ();
+  BaseMetricTreeNode *register_metric (BaseMetric *item);
+  BaseMetricTreeNode *find (const char *name);
+  void get_nearest_registered_descendents (Vector<BaseMetricTreeNode*> *new_vec);
+  void get_all_registered_descendents (Vector<BaseMetricTreeNode*> *new_vec);
+  char *get_description();
+  char *dump();
+
+  BaseMetricTreeNode *get_root ()       { return root; }
+  BaseMetricTreeNode *get_parent ()     { return parent; }
+  Vector<BaseMetricTreeNode*> *get_children () { return children; }
+  bool is_registered ()                 { return registered; }
+  int get_num_registered_descendents () { return num_registered_descendents; }
+  bool is_composite_metric ()           { return isCompositeMetric; }
+  BaseMetric *get_BaseMetric ()         { return bm; }
+  char *get_name ()                     { return name; }
+  char *get_user_name ()                { return uname; }
+  char *get_unit ()                     { return unit; }
+  char *get_unit_uname ()               { return unit_uname; }
+
+private:
+  BaseMetricTreeNode (BaseMetric *item);
+  BaseMetricTreeNode (const char *name, const char *uname,
+                     const char *_unit, const char *_unit_uname);
+  void init_vars ();
+  void build_basic_tree ();
+  BaseMetricTreeNode *add_child (BaseMetric *item);
+  BaseMetricTreeNode *add_child (const char *name, const char *uname,
+                                 const char *unit = NULL, const char *unit_uname = NULL);
+  BaseMetricTreeNode *add_child (BaseMetricTreeNode *new_node);
+  void register_node (BaseMetricTreeNode *);
+
+  BaseMetricTreeNode *root;     // root of tree
+  BaseMetricTreeNode *parent;   // my parent
+  bool aggregation;             // value is based on children's values
+  char *name;           // bm->get_cmd() for metrics, unique string otherwise
+  char *uname;                  // user-visible text
+  char *unit;                   // see UNIT_* defines
+  char *unit_uname;             // see UNIT_*_UNAME defines
+  Vector<BaseMetricTreeNode*> *children;    // my children
+  bool isCompositeMetric;       // value is sum of children
+  BaseMetric *bm;               // metric for this node, or null
+  bool registered;              // metric has been officially registered
+  int num_registered_descendents;   // does not include self
+};
+
+#endif  /* _BASEMETRICTREENODE_H */
diff --git a/gprofng/src/CacheMap.h b/gprofng/src/CacheMap.h
new file mode 100644 (file)
index 0000000..a575749
--- /dev/null
@@ -0,0 +1,186 @@
+/* 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.  */
+
+/*
+ *  Cache Map implementation.
+ *
+ *  Cache Map makes the following assumptions:
+ *    - Cache Map is used for very fast but not guaranteed mapping;
+ *    - only REL_EQ Relation can be used;
+ *    - all objects used as keys or values has to be managed
+ *      outside CacheMap (f.e. deletion);
+ *    - (Key_t)0 is invalid key;
+ *    - (Value_t)0 is invalid value;
+ *    - <TBC>
+ */
+
+#ifndef _DBE_CACHEMAP_H
+#define _DBE_CACHEMAP_H
+
+#include <assert.h>
+#include <vec.h>
+#include <Map.h>
+
+template <typename Key_t, typename Value_t>
+class CacheMap : public Map<Key_t, Value_t>
+{
+public:
+
+  CacheMap ();
+  ~CacheMap ();
+  void put (Key_t key, Value_t val);
+  Value_t get (Key_t key);
+  Value_t get (Key_t key, typename Map<Key_t, Value_t>::Relation rel);
+  Value_t
+  remove (Key_t key);
+
+private:
+
+  struct Entry
+  {
+    Key_t key;
+    Value_t val;
+
+    Entry ()
+    {
+      key = (Key_t) 0;
+    }
+  };
+
+  static const int INIT_SIZE;
+  static const int MAX_SIZE;
+
+  static unsigned hash (Key_t key);
+  Entry *getEntry (Key_t key);
+
+  int cursize;
+  int nputs;
+  int nchunks;
+  Entry **chunks;
+};
+
+template <typename Key_t, typename Value_t>
+const int CacheMap<Key_t, Value_t>::INIT_SIZE = 1 << 14;
+template <typename Key_t, typename Value_t>
+const int CacheMap<Key_t, Value_t>::MAX_SIZE = 1 << 20;
+
+template <typename Key_t, typename Value_t>CacheMap<Key_t, Value_t>
+::CacheMap ()
+{
+  cursize = INIT_SIZE;
+  chunks = new Entry*[32];
+  nchunks = 0;
+  chunks[nchunks++] = new Entry[cursize];
+  nputs = 0;
+}
+
+template <typename Key_t, typename Value_t>
+CacheMap<Key_t, Value_t>::~CacheMap ()
+{
+  for (int i = 0; i < nchunks; i++)
+    delete[] chunks[i];
+  delete[] chunks;
+}
+
+template <typename Key_t, typename Value_t>
+unsigned
+CacheMap<Key_t, Value_t>::hash (Key_t key)
+{
+  unsigned h = (unsigned) key ^ (unsigned) (key >> 32);
+  h ^= (h >> 20) ^ (h >> 12);
+  return h ^ (h >> 7) ^ (h >> 4);
+}
+
+template <typename Key_t, typename Value_t>
+void
+CacheMap<Key_t, Value_t>::put (Key_t key, Value_t val)
+{
+  if (nputs >= cursize && cursize < MAX_SIZE)
+    {
+      // Allocate new chunk for entries.
+      chunks[nchunks++] = new Entry[cursize];
+      cursize *= 2;
+
+      // Copy all old entries to the newly allocated chunk
+      Entry *newchunk = chunks[nchunks - 1];
+      int prevsz = 0;
+      int nextsz = INIT_SIZE;
+      for (int i = 0; i < nchunks - 1; i++)
+       {
+         Entry *oldchunk = chunks[i];
+         for (int j = prevsz; j < nextsz; j++)
+           newchunk[j] = oldchunk[j - prevsz];
+         prevsz = nextsz;
+         nextsz *= 2;
+       }
+    }
+  Entry *entry = getEntry (key);
+  entry->key = key;
+  entry->val = val;
+  nputs++;
+}
+
+template <typename Key_t, typename Value_t>
+typename CacheMap<Key_t, Value_t>::Entry *
+CacheMap<Key_t, Value_t>::getEntry (Key_t key)
+{
+  unsigned idx = hash (key);
+  int i = nchunks - 1;
+  int j = cursize / 2;
+  for (; i > 0; i -= 1, j /= 2)
+    if (idx & j)
+      break;
+  if (i == 0)
+    j *= 2;
+  return &chunks[i][idx & (j - 1)];
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+CacheMap<Key_t, Value_t>::get (Key_t key)
+{
+  Entry *entry = getEntry (key);
+  return entry->key == key ? entry->val : (Value_t) 0;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+CacheMap<Key_t, Value_t>::get (Key_t key, typename Map<Key_t, Value_t>::Relation rel)
+{
+  if (rel != Map<Key_t, Value_t>::REL_EQ)
+    return (Value_t) 0;
+  return get (key);
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+CacheMap<Key_t, Value_t>::remove (Key_t key)
+{
+  Entry *entry = getEntry (key);
+  Value_t res = (Value_t) 0;
+  if (entry->key == key)
+    {
+      res = entry->val;
+      entry->val = (Value_t) 0;
+    }
+  return res;
+}
+
+#endif
diff --git a/gprofng/src/CallStack.cc b/gprofng/src/CallStack.cc
new file mode 100644 (file)
index 0000000..7671f9f
--- /dev/null
@@ -0,0 +1,1250 @@
+/* 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 <new>
+
+#include "util.h"
+#include "CacheMap.h"
+#include "CallStack.h"
+#include "DbeSession.h"
+#include "DbeView.h"
+#include "DbeLinkList.h"
+#include "Experiment.h"
+#include "Exp_Layout.h"
+#include "Function.h"
+#include "LoadObject.h"
+#include "Module.h"
+
+Descendants::Descendants ()
+{
+  count = 0;
+  limit = sizeof (first_data) / sizeof (CallStackNode *);
+  data = first_data;
+}
+
+Descendants::~Descendants ()
+{
+  if (data != first_data)
+    free (data);
+}
+
+CallStackNode *
+Descendants::find (Histable *hi, int *index)
+{
+  int cnt = count;
+  int left = 0;
+  for (int right = cnt - 1; left <= right;)
+    {
+      int ind = (left + right) / 2;
+      CallStackNode *node = data[ind];
+      Histable *instr = node->get_instr ();
+      if (instr == hi)
+       {
+         if (index)
+           *index = ind;
+         return node;
+       }
+      if (instr->id < hi->id)
+       right = ind - 1;
+      else
+       left = ind + 1;
+    }
+  if (index)
+    *index = left;
+  return NULL;
+}
+
+void
+Descendants::append (CallStackNode* item)
+{
+  if (count < limit)
+    data[count++] = item;
+  else
+    insert (count, item);
+}
+
+void
+Descendants::insert (int ind, CallStackNode* item)
+{
+  CallStackNode **old_data = data;
+  int old_cnt = count;
+  if (old_cnt + 1 >= limit)
+    {
+      int new_limit = (limit == 0) ? DELTA : limit * 2;
+      CallStackNode **new_data = (CallStackNode **) malloc (new_limit * sizeof (CallStackNode *));
+      for (int i = 0; i < ind; i++)
+       new_data[i] = old_data[i];
+      new_data[ind] = item;
+      for (int i = ind; i < old_cnt; i++)
+       new_data[i + 1] = old_data[i];
+      limit = new_limit;
+      data = new_data;
+      if (old_data != first_data)
+       free (old_data);
+    }
+  else
+    {
+      for (int i = ind; i < old_cnt; i++)
+       old_data[i + 1] = old_data[i];
+      old_data[ind] = item;
+    }
+  count++;
+}
+
+/*
+ *    Private implementation of CallStack interface
+ */
+
+// When performing pipeline optimization on resolve_frame_info + add_stack
+// cstk_ctx structure contains the state (or context) for one iteration to pass on
+// from Phase 2 to Phase 3 (More details in Experiment.cc)
+class CallStackP : public CallStack
+{
+public:
+  CallStackP (Experiment *exp);
+
+  virtual ~CallStackP ();
+
+  virtual void add_stack (DataDescriptor *dDscr, long idx, FramePacket *frp, cstk_ctx_chunk *cstCtxChunk);
+  virtual void *add_stack (Vector<Histable*> *objs);
+  virtual CallStackNode *get_node (int n);
+  virtual void print (FILE *);
+
+private:
+
+  static const int CHUNKSZ = 16384;
+
+  Experiment *experiment;
+  CallStackNode *root;
+  CallStackNode *jvm_node;
+  int nodes;
+  int nchunks;
+  CallStackNode **chunks;
+  Map<uint64_t, CallStackNode *> *cstackMap;
+  DbeLock *cstackLock;
+
+  CallStackNode *add_stack (long start, long end, Vector<Histable*> *objs, CallStackNode *myRoot);
+  CallStackNode *new_Node (CallStackNode*, Histable*);
+  CallStackNode *find_preg_stack (uint64_t);
+  // objs are in the root..leaf order
+  void *add_stack_d (Vector<Histable*> *objs);
+  void add_stack_java (DataDescriptor *dDscr, long idx, FramePacket *frp, hrtime_t tstamp, uint32_t thrid, Vector<DbeInstr*>* natpcs, bool natpc_added, cstk_ctx_chunk *cstCtxChunk);
+  void add_stack_java_epilogue (DataDescriptor *dDscr, long idx, FramePacket *frp, hrtime_t tstamp, uint32_t thrid, Vector<DbeInstr*>* natpcs, Vector<Histable*>* jpcs, bool natpc_added);
+
+  // Adjust HW counter event to find better trigger PC, etc.
+  DbeInstr *adjustEvent (DbeInstr *leafPC, DbeInstr * candPC,
+                        Vaddr &eventEA, int abst_type);
+  Vector<DbeInstr*> *natpcsP;
+  Vector<Histable*> *jpcsP;
+};
+
+CallStackP::CallStackP (Experiment *exp)
+{
+  experiment = exp;
+  nchunks = 0;
+  chunks = NULL;
+  nodes = 0;
+  cstackMap = new CacheMap<uint64_t, CallStackNode *>;
+  cstackLock = new DbeLock ();
+  Function *total = dbeSession->get_Total_Function ();
+  root = new_Node (0, total->find_dbeinstr (0, 0));
+  jvm_node = NULL;
+  natpcsP = NULL;
+  jpcsP = NULL;
+}
+
+CallStackP::~CallStackP ()
+{
+  delete cstackLock;
+  if (chunks)
+    {
+      for (int i = 0; i < nodes; i++)
+       {
+         CallStackNode *node = get_node (i);
+         node->~CallStackNode ();
+       }
+      for (int i = 0; i < nchunks; i++)
+       free (chunks[i]);
+      free (chunks);
+    }
+  delete natpcsP;
+  delete jpcsP;
+  destroy_map (CallStackNode *, cstackMap);
+}
+
+CallStackNode *
+CallStackP::new_Node (CallStackNode *anc, Histable *pcval)
+{
+  // cstackLock->aquireLock(); // Caller already locked it
+  if (nodes >= nchunks * CHUNKSZ)
+    {
+      CallStackNode **old_chunks = chunks;
+      nchunks++;
+
+      // Reallocate Node chunk array
+      chunks = (CallStackNode **) malloc (nchunks * sizeof (CallStackNode *));
+      for (int i = 0; i < nchunks - 1; i++)
+       chunks[i] = old_chunks[i];
+      free (old_chunks);
+      // Allocate new chunk for nodes.
+      chunks[nchunks - 1] = (CallStackNode *) malloc (CHUNKSZ * sizeof (CallStackNode));
+    }
+  nodes++;
+  CallStackNode *node = get_node (nodes - 1);
+  new (node) CallStackNode (anc, pcval);
+  // cstackLock->releaseLock();
+  return node;
+}
+
+CallStackNode *
+CallStackP::find_preg_stack (uint64_t prid)
+{
+  DataView *dview = experiment->getOpenMPdata ();
+  dview->sort (PROP_CPRID);
+  Datum tval;
+  tval.setUINT64 (prid);
+  long idx = dview->getIdxByVals (&tval, DataView::REL_EQ);
+  if (idx < 0)
+    return root;
+  CallStackNode *node = (CallStackNode*) dview->getObjValue (PROP_USTACK, idx);
+  if (node != NULL)
+    return node;
+  uint64_t pprid = dview->getLongValue (PROP_PPRID, idx);
+  if (pprid == prid)
+    return root;
+  void *nat_stack = dview->getObjValue (PROP_MSTACK, idx);
+  Vector<Histable*> *pcs = getStackPCs (nat_stack);
+
+  // Find the bottom frame
+  int btm;
+  bool inOMP = false;
+  DbeInstr *instr;
+  Histable *hist;
+  for (btm = 0; btm < pcs->size (); btm++)
+    {
+      hist = pcs->fetch (btm);
+      if (hist->get_type () == Histable::INSTR)
+       instr = (DbeInstr *) hist;
+      else    // DBELINE
+       instr = (DbeInstr *) hist->convertto (Histable::INSTR);
+      LoadObject *lo = instr->func->module->loadobject;
+      if (!inOMP)
+       {
+         if (lo->flags & SEG_FLAG_OMP)
+           inOMP = true;
+       }
+      else if (!(lo->flags & SEG_FLAG_OMP))
+       break;
+    }
+
+  // Find the top frame
+  dview->sort (PROP_CPRID);
+  int top;
+  tval.setUINT64 (pprid);
+  long pidx = dview->getIdxByVals (&tval, DataView::REL_EQ);
+  if (pidx < 0)     // No parent. Process the entire nat_stack
+    top = pcs->size () - 1;
+  else
+    {
+      uint32_t thrid = (uint32_t) dview->getIntValue (PROP_THRID, idx);
+      uint32_t pthrid = (uint32_t) dview->getIntValue (PROP_THRID, pidx);
+      if (thrid != pthrid)
+       {
+         // Parent is on a different stack.
+         // Process the entire nat_stack. Skip libthread.
+         for (top = pcs->size () - 1; top >= 0; top--)
+           {
+             hist = pcs->fetch (top);
+             if (hist->get_type () == Histable::INSTR)
+               instr = (DbeInstr *) hist;
+             else // DBELINE
+               instr = (DbeInstr *) hist->convertto (Histable::INSTR);
+             if (instr->func->module->loadobject->flags & SEG_FLAG_OMP)
+               break;
+           }
+         if (top < 0)  // None found. May be incomplete call stack (x86)
+           top = pcs->size () - 1;
+       }
+      else
+       {
+         // Parent is on the same stack. Find match.
+         top = pcs->size () - 1;
+         void *pnat_stack = dview->getObjValue (PROP_MSTACK, pidx);
+         Vector<Histable*> *ppcs = getStackPCs (pnat_stack);
+         for (int ptop = ppcs->size () - 1; top >= 0 && ptop >= 0;
+                 top--, ptop--)
+           {
+             if (pcs->fetch (top) != ppcs->fetch (ptop))
+               break;
+           }
+         delete ppcs;
+       }
+    }
+
+  // Process the found range
+  Vector<Histable*> *upcs = new Vector<Histable*>(128);
+  for (int i = btm; i <= top; ++i)
+    {
+      hist = (DbeInstr*) pcs->fetch (i);
+      if (hist->get_type () == Histable::INSTR)
+       instr = (DbeInstr *) hist;
+      else // DBELINE
+       instr = (DbeInstr *) hist->convertto (Histable::INSTR);
+
+      if (instr->func->module->loadobject->flags & SEG_FLAG_OMP)
+       // Skip all frames from libmtsk
+       continue;
+      upcs->append (instr);
+    }
+  delete pcs;
+  node = find_preg_stack (pprid);
+  while (node != root)
+    {
+      upcs->append (node->instr);
+      node = node->ancestor;
+    }
+  node = (CallStackNode *) add_stack (upcs);
+  dview->setObjValue (PROP_USTACK, idx, node);
+  delete upcs;
+  return node;
+}
+
+#define JNI_MARKER -3
+
+// This is one iteration if the third stage of
+// resolve_frame_info + add_stack pipeline. Works on building the java
+// stacks
+void
+CallStackP::add_stack_java (DataDescriptor *dDscr, long idx, FramePacket *frp,
+                           hrtime_t tstamp, uint32_t thrid,
+                           Vector<DbeInstr*>* natpcs, bool natpc_added,
+                           cstk_ctx_chunk *cstCtxChunk)
+{
+  Vector<Histable*> *jpcs = NULL;
+  cstk_ctx *cstctx = NULL;
+  if (cstCtxChunk != NULL)
+    {
+      cstctx = cstCtxChunk->cstCtxAr[idx % CSTCTX_CHUNK_SZ];
+      jpcs = cstctx->jpcs;
+      jpcs->reset ();
+    }
+  if (jpcs == NULL)
+    {
+      // this is when we are not doing the pipeline optimization
+      // Temporary array for resolved addresses
+      // [leaf_pc .. root_pc] == [0..stack_size-1]
+      // Leave room for a possible "truncated" frame
+      if (jpcsP == NULL)
+       jpcsP = new Vector<Histable*>;
+      jpcs = jpcsP;
+      jpcs->reset ();
+    }
+
+  //
+  // Construct the user stack
+  //
+  // Construct Java user stack
+  int jstack_size = frp->stackSize (true);
+  if (jstack_size)
+    {
+      // jpcs = new Vector<Histable*>( jstack_size );
+      if (frp->isTruncatedStack (true))
+       {
+         Function *truncf = dbeSession->getSpecialFunction (DbeSession::TruncatedStackFunc);
+         jpcs->append (truncf->find_dbeinstr (0, 0));
+       }
+
+      int nind = natpcs->size () - 1; // first native frame
+      for (int jind = jstack_size - 1; jind >= 0; jind--)
+       {
+         bool jleaf = (jind == 0); // is current java frame a leaf?
+         Vaddr mid = frp->getMthdFromStack (jind);
+         int bci = frp->getBciFromStack (jind);
+         DbeInstr *cur_instr = experiment->map_jmid_to_PC (mid, bci, tstamp);
+         jpcs->append (cur_instr);
+         if (bci == JNI_MARKER)
+           {
+             JMethod *j_method = (JMethod*) cur_instr->func;
+             // Find matching native function on the native stack
+             bool found = false;
+             for (; nind >= 0; nind--)
+               {
+                 DbeInstr *nat_addr = natpcs->fetch (nind);
+                 if (0 == nat_addr)
+                   continue;
+                 Function *nat_func = nat_addr->func;
+                 if (!found && j_method->jni_match (nat_func))
+                   found = true;
+                 if (found)
+                   {
+                     // XXX omazur: the following will skip JNI native method
+                     // implemented in JVM itself.
+                     // If we are back in JVM switch to processing Java
+                     // frames if there are any.
+                     if ((nat_func->module->loadobject->flags & SEG_FLAG_JVM) && !jleaf)
+                       break;
+                     jpcs->append (nat_addr);
+                   }
+               }
+           }
+       }
+    }
+  add_stack_java_epilogue (dDscr, idx, frp, tstamp, thrid, natpcs, jpcs, natpc_added);
+}
+
+// This is one iteration if the fourth stage of
+// resolve_frame_info + add_stack pipeline.
+// It adds the native and java stacks to the stackmap
+
+void
+CallStackP::add_stack_java_epilogue (DataDescriptor *dDscr, long idx, FramePacket *frp, hrtime_t tstamp, uint32_t thrid, Vector<DbeInstr*>* natpcs, Vector<Histable*> *jpcs, bool natpc_added)
+{
+  CallStackNode *node = NULL;
+  if (!natpc_added)
+    {
+      node = (CallStackNode *) add_stack ((Vector<Histable*>*)natpcs);
+      dDscr->setObjValue (PROP_MSTACK, idx, node);
+      dDscr->setObjValue (PROP_XSTACK, idx, node);
+      dDscr->setObjValue (PROP_USTACK, idx, node);
+    }
+
+  int jstack_size = frp->stackSize (true);
+  if (jstack_size)
+    {
+      if (jpcs != NULL)
+       node = (CallStackNode *) add_stack_d (jpcs);
+      if (node == NULL)
+       node = (CallStackNode*) dDscr->getObjValue (PROP_USTACK, idx);
+      dDscr->setObjValue (PROP_USTACK, idx, node);
+      Function *func = (Function*) node->instr->convertto (Histable::FUNCTION);
+      if (func != dbeSession->get_JUnknown_Function ())
+       dDscr->setObjValue (PROP_XSTACK, idx, node);
+    }
+
+  JThread *jthread = experiment->map_pckt_to_Jthread (thrid, tstamp);
+  if (jthread == JTHREAD_NONE && jstack_size != 0 && node != NULL)
+    {
+      Function *func = (Function*) node->instr->convertto (Histable::FUNCTION);
+      if (func != dbeSession->get_JUnknown_Function ())
+       jthread = JTHREAD_DEFAULT;
+    }
+  dDscr->setObjValue (PROP_JTHREAD, idx, jthread);
+  if (jthread == JTHREAD_NONE || (jthread != JTHREAD_DEFAULT && jthread->is_system ()))
+    {
+      if (jvm_node == NULL)
+       {
+         Function *jvm = dbeSession->get_jvm_Function ();
+         if (jvm)
+           {
+             jvm_node = new_Node (root, jvm->find_dbeinstr (0, 0));
+             CommonPacket::jvm_overhead = jvm_node;
+           }
+       }
+      dDscr->setObjValue (PROP_USTACK, idx, jvm_node);
+    }
+}
+
+// This is one iteration of the 2nd stage of
+// resolve_frame_info + add_stack() pipeline. Builds the stack for a given framepacket.
+// When pipeline optimization is turnd off, cstctxchunk passed is NULL
+void
+CallStackP::add_stack (DataDescriptor *dDscr, long idx, FramePacket *frp,
+                      cstk_ctx_chunk* cstCtxChunk)
+{
+  Vector<DbeInstr*> *natpcs = NULL;
+  cstk_ctx *cstctx = NULL;
+  int stack_size = frp->stackSize ();
+  if (cstCtxChunk != NULL)
+    {
+      cstctx = cstCtxChunk->cstCtxAr[idx % CSTCTX_CHUNK_SZ];
+      natpcs = cstctx->natpcs;
+      natpcs->reset ();
+    }
+  if (natpcs == NULL)
+    {
+      // this is when we are not doing the pipeline optimization
+      // Temporary array for resolved addresses
+      // [leaf_pc .. root_pc] == [0..stack_size-1]
+      // Leave room for a possible "truncated" frame
+      if (natpcsP == NULL)
+       natpcsP = new Vector<DbeInstr*>;
+      natpcs = natpcsP;
+      natpcs->reset ();
+    }
+
+  bool leaf = true;
+  hrtime_t tstamp = (hrtime_t) dDscr->getLongValue (PROP_TSTAMP, idx);
+  uint32_t thrid = (uint32_t) dDscr->getIntValue (PROP_THRID, idx);
+
+  enum
+  {
+    NONE,
+    CHECK_O7,
+    USE_O7,
+    SKIP_O7
+  } state = NONE;
+
+  Vaddr o7_to_skip = 0;
+  for (int index = 0; index < stack_size; index++)
+    {
+      if (frp->isLeafMark (index))
+       {
+         state = CHECK_O7;
+         continue;
+       }
+
+      if (state == SKIP_O7)
+       {
+         // remember this bad o7 value since OMP might not recognize it
+         o7_to_skip = frp->getFromStack (index);
+         state = NONE;
+         continue;
+       }
+
+      Vaddr va = frp->getFromStack (index);
+      DbeInstr *cur_instr = experiment->map_Vaddr_to_PC (va, tstamp);
+#if ARCH(Intel)// TBR? FIXUP_XXX_SPARC_LINUX: switch should be on experiment ARCH, not dbe ARCH
+      // We need to adjust return addresses on intel
+      // in order to attribute inclusive metrics to
+      // proper call instructions.
+      if (experiment->exp_maj_version <= 9)
+       if (!leaf && cur_instr->addr != 0)
+         cur_instr = cur_instr->func->find_dbeinstr (0, cur_instr->addr - 1);
+#endif
+
+      // Skip PC's from PLT, update leaf and state accordingly
+      if ((cur_instr->func->flags & FUNC_FLAG_PLT)
+          && (leaf || state == CHECK_O7))
+       {
+         if (state == CHECK_O7)
+           state = USE_O7;
+         leaf = false;
+         continue;
+       }
+      if (state == CHECK_O7)
+       {
+         state = USE_O7;
+         uint64_t saddr = cur_instr->func->save_addr;
+         if (cur_instr->func->isOutlineFunction)
+           // outline functions assume 'save' instruction
+           // Note: they accidentally have saddr == FUNC_ROOT
+           state = SKIP_O7;
+         else if (saddr == FUNC_ROOT)
+           {
+             // If a function is statically determined as a root
+             // but dynamically appears not, don't discard o7.
+             // One such case is __misalign_trap_handler on sparcv9.
+             if (stack_size == 3)
+               state = SKIP_O7;
+           }
+         else if (saddr != FUNC_NO_SAVE && cur_instr->addr > saddr)
+           state = SKIP_O7;
+       }
+      else if (state == USE_O7)
+       {
+         state = NONE;
+         if (cur_instr->flags & PCInvlFlag)
+           continue;
+       }
+      if (leaf)
+       {
+         Vaddr evpc = (Vaddr) dDscr->getLongValue (PROP_VIRTPC, idx);
+         if (evpc != 0
+             && !(index > 0 && frp->isLeafMark (index - 1)
+                  && evpc == (Vaddr) (-1)))
+           {
+             /* contains hwcprof info */
+             cur_instr->func->module->read_hwcprof_info ();
+
+             // complete ABS validation of candidate eventPC/eventEA
+             // and correction/adjustment of collected callstack leaf PC
+             DbeInstr *candPC = experiment->map_Vaddr_to_PC (evpc, tstamp);
+             Vaddr vaddr = (Vaddr) dDscr->getLongValue (PROP_VADDR, idx);
+             Vaddr tmp_vaddr = vaddr;
+             int abst_type;
+             uint32_t tag = dDscr->getIntValue (PROP_HWCTAG, idx);
+             if (tag < 0 || tag >= MAX_HWCOUNT)
+               abst_type = ABST_NOPC;
+             else
+               abst_type = experiment->coll_params.hw_tpc[tag];
+
+             // We need to adjust addresses for ABST_EXACT_PEBS_PLUS1
+             // (Nehalem/SandyBridge PEBS identifies PC+1, not PC)
+             if (abst_type == ABST_EXACT_PEBS_PLUS1 && candPC->addr != 0)
+               candPC = candPC->func->find_dbeinstr (0, candPC->func->find_previous_addr (candPC->addr));
+
+             cur_instr = adjustEvent (cur_instr, candPC, tmp_vaddr, abst_type);
+             if (vaddr != tmp_vaddr)
+               {
+                 if (tmp_vaddr < ABS_CODE_RANGE)
+                   {
+                     /* post processing backtrack failed */
+                     dDscr->setValue (PROP_VADDR, idx, tmp_vaddr);
+                     dDscr->setValue (PROP_PADDR, idx, ABS_NULL);
+                     /* hwcp->eventVPC =  xxxxx leave eventPC alone,
+                      *   or can we set it to leafpc? */
+                     dDscr->setValue (PROP_PHYSPC, idx, ABS_NULL);
+                   }
+                 else
+                   {
+                     /* internal error: why would post-processing modify vaddr? */
+                     dDscr->setValue (PROP_PADDR, idx, (Vaddr) (-1));
+                     dDscr->setValue (PROP_PHYSPC, idx, (Vaddr) (-1));
+                   }
+               }
+           }
+       }
+      natpcs->append (cur_instr);
+      leaf = false;
+
+      // A hack to deceive the user into believing that outlined code
+      // is called from the base function
+      DbeInstr *drvd = cur_instr->func->derivedNode;
+      if (drvd != NULL)
+       natpcs->append (drvd);
+    }
+  if (frp->isTruncatedStack ())
+    {
+      Function *truncf = dbeSession->getSpecialFunction (DbeSession::TruncatedStackFunc);
+      natpcs->append (truncf->find_dbeinstr (0, 0));
+    }
+  else if (frp->isFailedUnwindStack ())
+    {
+      Function *funwf = dbeSession->getSpecialFunction (DbeSession::FailedUnwindFunc);
+      natpcs->append (funwf->find_dbeinstr (0, 0));
+    }
+
+  CallStackNode *node = (CallStackNode*) add_stack ((Vector<Histable*>*)natpcs);
+  dDscr->setObjValue (PROP_MSTACK, idx, node);
+  dDscr->setObjValue (PROP_XSTACK, idx, node);
+  dDscr->setObjValue (PROP_USTACK, idx, node);
+
+  // OpenMP 3.0 stacks
+  stack_size = frp->ompstack->size ();
+  if (stack_size > 0 || frp->omp_state == OMP_IDLE_STATE)
+    {
+      Function *func;
+      Vector<Histable*> *omppcs = new Vector<Histable*>(stack_size);
+      Vector<Histable*> *ompxpcs = new Vector<Histable*>(stack_size);
+      switch (frp->omp_state)
+       {
+       case OMP_IDLE_STATE:
+       case OMP_RDUC_STATE:
+       case OMP_IBAR_STATE:
+       case OMP_EBAR_STATE:
+       case OMP_LKWT_STATE:
+       case OMP_CTWT_STATE:
+       case OMP_ODWT_STATE:
+       case OMP_ATWT_STATE:
+         {
+           func = dbeSession->get_OMP_Function (frp->omp_state);
+           DbeInstr *instr = func->find_dbeinstr (0, 0);
+           omppcs->append (instr);
+           ompxpcs->append (instr);
+           break;
+         }
+       }
+      Vector<Vaddr> *stck = frp->ompstack;
+      leaf = true;
+      for (int index = 0; index < stack_size; index++)
+       {
+         if (stck->fetch (index) == SP_LEAF_CHECK_MARKER)
+           {
+             state = CHECK_O7;
+             continue;
+           }
+         if (state == SKIP_O7)
+           {
+             state = NONE;
+             continue;
+           }
+
+         // The OMP stack might not have enough information to know to discard a bad o7.
+         // So just remember what the native stack skipped.
+         if (o7_to_skip == stck->fetch (index))
+           {
+             state = NONE;
+             continue;
+           }
+         Vaddr va = stck->fetch (index);
+         DbeInstr *cur_instr = experiment->map_Vaddr_to_PC (va, tstamp);
+
+         // Skip PC's from PLT, update leaf and state accordingly
+         if ((cur_instr->func->flags & FUNC_FLAG_PLT) &&
+             (leaf || state == CHECK_O7))
+           {
+             if (state == CHECK_O7)
+               state = USE_O7;
+             leaf = false;
+             continue;
+           }
+         if (state == CHECK_O7)
+           {
+             state = USE_O7;
+             uint64_t saddr = cur_instr->func->save_addr;
+             if (cur_instr->func->isOutlineFunction)
+               // outline functions assume 'save' instruction
+               // Note: they accidentally have saddr == FUNC_ROOT
+               state = SKIP_O7;
+             else if (saddr == FUNC_ROOT)
+               {
+                 // If a function is statically determined as a root
+                 // but dynamically appears not, don't discard o7.
+                 // One such case is __misalign_trap_handler on sparcv9.
+                 if (stack_size == 3)
+                   state = SKIP_O7;
+               }
+             else if (saddr != FUNC_NO_SAVE && cur_instr->addr > saddr)
+               state = SKIP_O7;
+           }
+         else if (state == USE_O7)
+           {
+             state = NONE;
+             if (cur_instr->flags & PCInvlFlag)
+               continue;
+           }
+
+         DbeLine *dbeline = (DbeLine*) cur_instr->convertto (Histable::LINE);
+         if (cur_instr->func->usrfunc)
+           {
+             dbeline = dbeline->sourceFile->find_dbeline (cur_instr->func->usrfunc, dbeline->lineno);
+             omppcs->append (dbeline);
+           }
+         else if (dbeline->lineno > 0)
+           omppcs->append (dbeline);
+         else
+           omppcs->append (cur_instr);
+         if (dbeline->is_set (DbeLine::OMPPRAGMA) &&
+             frp->omp_state == OMP_WORK_STATE)
+           dDscr->setValue (PROP_OMPSTATE, idx, OMP_OVHD_STATE);
+         ompxpcs->append (cur_instr);
+         leaf = false;
+       }
+      if (frp->omptruncated == SP_TRUNC_STACK_MARKER)
+       {
+         func = dbeSession->getSpecialFunction (DbeSession::TruncatedStackFunc);
+         DbeInstr *instr = func->find_dbeinstr (0, 0);
+         omppcs->append (instr);
+         ompxpcs->append (instr);
+       }
+      else if (frp->omptruncated == SP_FAILED_UNWIND_MARKER)
+       {
+         func = dbeSession->getSpecialFunction (DbeSession::FailedUnwindFunc);
+         DbeInstr *instr = func->find_dbeinstr (0, 0);
+         omppcs->append (instr);
+         ompxpcs->append (instr);
+       }
+
+      // User model call stack
+      node = (CallStackNode*) add_stack (omppcs);
+      dDscr->setObjValue (PROP_USTACK, idx, node);
+      delete omppcs;
+
+      // Expert call stack
+      node = (CallStackNode*) add_stack (ompxpcs);
+      dDscr->setObjValue (PROP_XSTACK, idx, node);
+      delete ompxpcs;
+      dDscr->setObjValue (PROP_JTHREAD, idx, JTHREAD_DEFAULT);
+      return;
+    }
+
+  // OpenMP 2.5 stacks
+  if (frp->omp_cprid || frp->omp_state)
+    {
+      DataView *dview = experiment->getOpenMPdata ();
+      if (dview == NULL)
+       {
+         // It appears we may get OMP_SERL_STATE from a passive libmtsk
+         dDscr->setObjValue (PROP_JTHREAD, idx, JTHREAD_DEFAULT);
+         return;
+       }
+      if (dview->getDataDescriptor () == dDscr)
+       {
+         // Don't process the user stack for OpenMP fork events yet
+         dDscr->setObjValue (PROP_USTACK, idx, (void*) NULL);
+         dDscr->setObjValue (PROP_JTHREAD, idx, JTHREAD_DEFAULT);
+         return;
+       }
+      Vector<Histable*> *omppcs = new Vector<Histable*>(stack_size);
+
+      // Construct OMP user stack
+      // Find the bottom frame
+      int btm = 0;
+      switch (frp->omp_state)
+       {
+       case OMP_IDLE_STATE:
+         {
+           Function *func = dbeSession->get_OMP_Function (frp->omp_state);
+           omppcs->append (func->find_dbeinstr (0, 0));
+           // XXX: workaround for inconsistency between OMP_IDLE_STATE
+           // and omp_cprid != 0
+           frp->omp_cprid = 0;
+           btm = natpcs->size ();
+           break;
+         }
+       case OMP_RDUC_STATE:
+       case OMP_IBAR_STATE:
+       case OMP_EBAR_STATE:
+       case OMP_LKWT_STATE:
+       case OMP_CTWT_STATE:
+       case OMP_ODWT_STATE:
+       case OMP_ATWT_STATE:
+         {
+           Function *func = dbeSession->get_OMP_Function (frp->omp_state);
+           omppcs->append (func->find_dbeinstr (0, 0));
+           bool inOMP = false;
+           for (btm = 0; btm < natpcs->size (); btm++)
+             {
+               LoadObject *lo = natpcs->fetch (btm)->func->module->loadobject;
+               if (!inOMP)
+                 {
+                   if (lo->flags & SEG_FLAG_OMP)
+                     inOMP = true;
+                 }
+               else if (!(lo->flags & SEG_FLAG_OMP))
+                 break;
+             }
+           break;
+         }
+       case OMP_NO_STATE:
+       case OMP_WORK_STATE:
+       case OMP_SERL_STATE:
+       default:
+         break;
+       }
+
+      // Find the top frame
+      int top = -1;
+      switch (frp->omp_state)
+       {
+       case OMP_IDLE_STATE:
+         break;
+       default:
+         {
+           dview->sort (PROP_CPRID);
+           Datum tval;
+           tval.setUINT64 (frp->omp_cprid);
+           long pidx = dview->getIdxByVals (&tval, DataView::REL_EQ);
+           if (pidx < 0)   // No parent. Process the entire nat_stack
+             top = natpcs->size () - 1;
+           else
+             {
+               uint32_t pthrid = (uint32_t) dview->getIntValue (PROP_THRID, pidx);
+               if (thrid != pthrid)
+                 {
+                   // Parent is on a different stack.
+                   // Process the entire nat_stack. Skip libthread.
+                   for (top = natpcs->size () - 1; top >= 0; top--)
+                     {
+                       DbeInstr *instr = natpcs->fetch (top);
+                       if (instr->func->module->loadobject->flags & SEG_FLAG_OMP)
+                         break;
+                     }
+                   if (top < 0) // None found. May be incomplete call stack
+                     top = natpcs->size () - 1;
+                 }
+               else
+                 {
+                   // Parent is on the same stack. Find match.
+                   top = natpcs->size () - 1;
+                   void *pnat_stack = dview->getObjValue (PROP_MSTACK, pidx);
+                   Vector<Histable*> *ppcs = getStackPCs (pnat_stack);
+                   for (int ptop = ppcs->size () - 1; top >= 0 && ptop >= 0;
+                           top--, ptop--)
+                     {
+                       if (natpcs->fetch (top) != ppcs->fetch (ptop))
+                         break;
+                     }
+                   delete ppcs;
+                 }
+             }
+           // If no frames are found for Barrier/Reduction save at least one
+           if ((frp->omp_state == OMP_RDUC_STATE
+                || frp->omp_state == OMP_IBAR_STATE
+                || frp->omp_state == OMP_EBAR_STATE)
+               && top < btm && btm < natpcs->size ())
+             top = btm;
+         }
+       }
+      for (int i = btm; i <= top; ++i)
+       {
+         DbeInstr *instr = natpcs->fetch (i);
+         if (instr->func->module->loadobject->flags & SEG_FLAG_OMP)
+           continue; // Skip all frames from libmtsk
+         omppcs->append (instr);
+       }
+      node = find_preg_stack (frp->omp_cprid);
+      while (node != root)
+       {
+         omppcs->append (node->instr);
+         node = node->ancestor;
+       }
+      node = (CallStackNode *) add_stack (omppcs);
+      dDscr->setObjValue (PROP_USTACK, idx, node);
+      delete omppcs;
+      dDscr->setObjValue (PROP_JTHREAD, idx, JTHREAD_DEFAULT);
+      return;
+    }
+
+  // Construct Java user stack
+  add_stack_java (dDscr, idx, frp, tstamp, thrid, natpcs, true, NULL);
+}
+
+// adjustment of leafPC/eventVA for XHWC packets with candidate eventPC
+//  Called from CallStack during initial processing of the events
+DbeInstr *
+CallStackP::adjustEvent (DbeInstr *leafPC, DbeInstr *candPC, Vaddr &eventVA,
+                        int abst_type)
+{
+  // increment counter of dataspace events
+  experiment->dsevents++;
+  bool isPrecise;
+  if (abst_type == ABST_EXACT_PEBS_PLUS1)
+    isPrecise = true;
+  else if (abst_type == ABST_EXACT)
+    isPrecise = true;
+  else
+    isPrecise = false;
+
+  if (isPrecise)
+    /* precise backtracking */
+    /* assume within 1 instruction of leaf (this could be checked here) */
+    // no change to eventVA or candPC
+    return candPC;
+
+  Function *func = leafPC->func;
+  unsigned int bt_entries = func->module->bTargets.size ();
+  DbeInstr *bestPC = NULL;
+
+  // bt == branch target (potential destination of a branch
+  if (bt_entries == 0)
+    { // no XHWCprof info for this module
+      // increment counter
+      experiment->dsnoxhwcevents++;
+
+      // see if event is to be processed anyway
+      if (!dbeSession->check_ignore_no_xhwcprof ())
+       {
+         // Don't ignore error
+         // XXX -- set error code in event VA -- replace with other mechanism
+         if (eventVA > ABS_CODE_RANGE)
+           eventVA = ABS_NULL;
+         eventVA |= ABS_NO_CTI_INFO; // => effective address can't be validated
+         bestPC = leafPC; // => no PC correction possible
+       }
+      else
+       bestPC = candPC; // assume the event valid
+    }
+  else
+    {
+      // we have the info to verify the backtracking
+      target_info_t *bt;
+      int bt_entry = bt_entries;
+      uint64_t leafPC_offset = func->img_offset + leafPC->addr;
+      uint64_t candPC_offset = candPC->func->img_offset + candPC->addr;
+      do
+       {
+         bt_entry--;
+         bt = func->module->bTargets.fetch (bt_entry);
+         /* bts seem to be sorted by offset, smallest to largest */
+       }
+      while (bt_entry > 0 && bt->offset > leafPC_offset);
+      /* if bt_entry == 0, all items have been checked */
+
+      if (bt->offset > leafPC_offset)
+       { /* XXXX isn't is possible that all bt's are after leafPC_offset? */
+         bestPC = leafPC; // actual event PC can't be determined
+         if (eventVA > ABS_CODE_RANGE)
+           eventVA = ABS_NULL;
+         eventVA |= ABS_INFO_FAILED; // effective address can't be validated
+       }
+      else if (bt->offset > candPC_offset)
+       {
+         // use synthetic PC corresponding to bTarget
+         bestPC = func->find_dbeinstr (PCTrgtFlag, bt->offset - func->img_offset);
+         if (eventVA > ABS_CODE_RANGE)
+           eventVA = ABS_NULL;
+         eventVA |= ABS_CTI_TARGET; // effective  address can't be validated
+       }
+      else
+       bestPC = candPC;    // accept provided virtual address as valid
+    }
+  return bestPC;
+}
+
+void *
+CallStackP::add_stack_d (Vector<Histable*> *objs)
+{
+  // objs: root..leaf
+  // Reverse objs
+  for (int i = 0, j = objs->size () - 1; i < j; ++i, --j)
+    objs->swap (i, j);
+  return add_stack (objs);
+}
+
+CallStackNode::CallStackNode (CallStackNode *_ancestor, Histable *_instr)
+{
+  ancestor = _ancestor;
+  instr = _instr;
+  alt_node = NULL;
+}
+
+CallStackNode::~CallStackNode () { }
+
+bool
+CallStackNode::compare (long start, long end, Vector<Histable*> *objs, CallStackNode *mRoot)
+{
+  CallStackNode *p = this;
+  for (long i = start; i < end; i++, p = p->get_ancestor ())
+    if (p == NULL || p->get_instr () != objs->get (i))
+      return false;
+  return p == mRoot;
+}
+
+void
+CallStackNode::dump ()
+{
+  const char *s = "";
+  int sz = 0;
+  for (CallStackNode *p = this; p; p = p->get_ancestor ())
+    {
+      fprintf (stderr, NTXT ("%.*s 0x%08llx id=0x%08llx %s\n"), sz, s,
+              (long long) p, (long long) p->get_instr ()->id,
+              STR (p->get_instr ()->get_name ()));
+      s = "-";
+      sz += 1;
+    }
+}
+
+long total_calls_add_stack, total_stacks, total_nodes, call_stack_size[201];
+
+void *
+CallStackP::add_stack (Vector<Histable*> *objs)
+{
+  // objs: leaf..root
+  uint64_t hash = objs->size ();
+  for (long i = objs->size () - 1; i >= 0; --i)
+    hash ^= (unsigned long long) objs->get (i);
+
+  uint64_t key = hash ? hash : 1;
+  CallStackNode *node = cstackMap->get (key);
+#ifdef DEBUG
+  if (DUMP_CALL_STACK)
+    {
+      total_calls_add_stack++;
+      call_stack_size[objs->size () > 200 ? 200 : objs->size ()]++;
+      Dprintf (DUMP_CALL_STACK,
+              "add_stack: %lld size=%lld  key=0x%08llx cashNode=0x%08llx\n",
+              (long long) total_calls_add_stack, (long long) objs->size (),
+              (long long) key, (long long) node);
+      for (long i = 0, sz = VecSize (objs); i < sz; i++)
+       Dprintf (DUMP_CALL_STACK, "  add_stack: %.*s 0x%08llx id=0x%08llx %s\n",
+                (int) i, NTXT (" "), (long long) objs->get (i),
+                (long long) objs->get (i)->id, STR (objs->get (i)->get_name ()));
+    }
+#endif
+  if (node && node->compare (0, objs->size (), objs, root))
+    {
+      Dprintf (DUMP_CALL_STACK, NTXT ("STACK FOUND: key=0x%08llx 0x%08llx id=0x%08llx %s\n"),
+              (long long) key, (long long) node,
+              (long long) node->get_instr ()->id,
+              STR (node->get_instr ()->get_name ()));
+      return node;
+    }
+  node = root;
+  for (long i = objs->size () - 1; i >= 0; i--)
+    {
+      Histable *instr = objs->get (i);
+      int old_count = node->count;
+      int left;
+      CallStackNode *nd = node->find (instr, &left);
+      if (nd)
+       {
+         node = nd;
+         continue;
+       }
+      cstackLock->aquireLock (); // Use one lock for all nodes
+      // node->aquireLock();
+      if (old_count != node->count)
+       {
+         nd = node->find (instr, &left);
+         if (nd)
+           { // the other thread has created this node
+             cstackLock->releaseLock ();
+             // node->releaseLock();
+             node = nd;
+             continue;
+           }
+       }
+      // New Call Stack
+      total_stacks++;
+      nd = node;
+      CallStackNode *first = NULL;
+      do
+       {
+         CallStackNode *anc = node;
+         total_nodes++;
+         node = new_Node (anc, objs->get (i));
+         if (first)
+           anc->append (node);
+         else
+           first = node;
+       }
+      while (i-- > 0);
+      nd->insert (left, first);
+      cstackLock->releaseLock ();
+      // nd->releaseLock();
+      break;
+    }
+  cstackMap->put (key, node);
+  if (DUMP_CALL_STACK)
+    node->dump ();
+  return node;
+}
+
+CallStackNode *
+CallStackP::get_node (int n)
+{
+  if (n < nodes)
+    return &chunks[n / CHUNKSZ][n % CHUNKSZ];
+  return NULL;
+}
+
+/*
+ *  Debugging methods
+ */
+void
+CallStackP::print (FILE *fd)
+{
+  FILE *f = (fd == NULL ? stderr : fd);
+  fprintf (f, GTXT ("CallStack: nodes = %d\n\n"), nodes);
+  int maxdepth = 0;
+  int maxwidth = 0;
+  const char *t;
+  char *n;
+  for (int i = 0; i < nodes; i++)
+    {
+      CallStackNode *node = &chunks[i / CHUNKSZ][i % CHUNKSZ];
+      Histable *instr = node->instr;
+      if (instr->get_type () == Histable::LINE)
+       {
+         t = "L";
+         n = ((DbeLine *) instr)->func->get_name ();
+       }
+      else if (instr->get_type () == Histable::INSTR)
+       {
+         t = "I";
+         n = ((DbeInstr *) instr)->func->get_name ();
+       }
+      else
+       {
+         t = "O";
+         n = instr->get_name ();
+       }
+      long long addr = (long long) instr->get_addr ();
+      fprintf (f, GTXT ("node: 0x%016llx anc: 0x%016llx -- 0x%016llX:  %s %s\n"),
+              (unsigned long long) node, (unsigned long long) node->ancestor,
+              addr, t, n);
+    }
+  fprintf (f, GTXT ("md = %d, mw = %d\n"), maxdepth, maxwidth);
+}
+
+/*
+ *  Static CallStack methods
+ */
+CallStack *
+CallStack::getInstance (Experiment *exp)
+{
+  return new CallStackP (exp);
+}
+
+int
+CallStack::stackSize (void *stack)
+{
+  CallStackNode *node = (CallStackNode *) stack;
+  int sz = 0;
+  for (; node; node = node->ancestor)
+    sz++;
+  return sz - 1; // don't count the root node
+}
+
+Histable *
+CallStack::getStackPC (void *stack, int n)
+{
+  CallStackNode *node = (CallStackNode *) stack;
+  while (n-- && node)
+    node = node->ancestor;
+  if (node == NULL)
+    return dbeSession->get_Unknown_Function ()->find_dbeinstr (PCInvlFlag, 0);
+  return node->instr;
+}
+
+Vector<Histable*> *
+CallStack::getStackPCs (void *stack, bool get_hide_stack)
+{
+  Vector<Histable*> *res = new Vector<Histable*>;
+  CallStackNode *node = (CallStackNode *) stack;
+  if (get_hide_stack && node->alt_node != NULL)
+    node = node->alt_node;
+  while (node && node->ancestor)
+    { // skip the root node
+      res->append (node->instr);
+      node = node->ancestor;
+    }
+  return res;
+}
+
+int
+CallStack::compare (void *stack1, void *stack2)
+{
+  // Quick comparision
+  if (stack1 == stack2)
+    return 0;
+
+  CallStackNode *node1 = (CallStackNode *) stack1;
+  CallStackNode *node2 = (CallStackNode *) stack2;
+  while (node1 != NULL && node2 != NULL)
+    {
+      //to keep the result const on different platforms
+      //we use instr->id instead of instr
+      if (node1->instr->id < node2->instr->id)
+       return -1;
+      else if (node1->instr->id > node2->instr->id)
+       return 1;
+      node1 = node1->ancestor;
+      node2 = node2->ancestor;
+    }
+  if (node1 == NULL && node2 != NULL)
+    return -1;
+  else if (node1 != NULL && node2 == NULL)
+    return 1;
+  else
+    return 0;
+}
+
+// LIBRARY VISIBILITY
+
+void
+CallStack::setHideStack (void *stack, void *hideStack)
+{
+  CallStackNode *hNode = (CallStackNode *) stack;
+  hNode->alt_node = (CallStackNode *) hideStack;
+}
diff --git a/gprofng/src/CallStack.h b/gprofng/src/CallStack.h
new file mode 100644 (file)
index 0000000..62e0686
--- /dev/null
@@ -0,0 +1,114 @@
+/* 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 _CALLSTACK_H
+#define _CALLSTACK_H
+
+#include <stdio.h>
+#include "dbe_structs.h"
+#include "Experiment.h"
+#include "DbeLock.h"
+
+class DataDescriptor;
+class FramePacket;
+class DbeInstr;
+class Histable;
+template <class ITEM> class Vector;
+class CallStackNode;
+
+class Descendants /* : public DbeLock */
+{
+public:
+  Descendants ();
+  ~Descendants ();
+  CallStackNode *find (Histable *hi, int *index);
+  void append (CallStackNode *item);
+  void insert (int ind, CallStackNode *item);
+  int volatile count;
+
+private:
+
+  enum
+  {
+    DELTA = 8
+  };
+
+  int limit;
+  CallStackNode **data;
+  CallStackNode *first_data[4];
+};
+
+class CallStackNode : public Descendants
+{
+public:
+  CallStackNode (CallStackNode *_ancestor, Histable *_instr);
+  ~CallStackNode ();
+  bool compare (long start, long end, Vector<Histable*> *objs, CallStackNode *mRoot);
+  void dump ();
+
+  CallStackNode *
+  get_ancestor ()
+  {
+    return ancestor;
+  }
+
+  Histable *
+  get_instr ()
+  {
+    return instr;
+  }
+
+  CallStackNode *alt_node;
+  Histable *instr;
+  CallStackNode *ancestor;
+};
+
+class CallStack
+{
+public:
+  static CallStack *getInstance (Experiment *exp);
+  virtual ~CallStack () { };
+
+  virtual void add_stack (DataDescriptor *dDscr, long idx, FramePacket *frp,
+                         cstk_ctx_chunk* cstCtxChunk) = 0;
+
+  // Creates a call stack representation for objs and
+  // returns an opaque pointer to it
+  virtual void *add_stack (Vector<Histable*> *objs) = 0;
+
+  // Debugging methods
+  virtual void print (FILE *) = 0;
+
+  // Call stack inquiries
+  static int stackSize (void *stack);
+  static Histable *getStackPC (void *stack, int n);
+  static Vector<Histable*> *getStackPCs (void *stack, bool get_hide_stack = false);
+  static void setHideStack (void *stack, void *hideStack);
+  static int compare (void *stack1, void *stack2);
+
+  virtual CallStackNode *
+  get_node (int)
+  {
+    return NULL;
+  };
+
+};
+
+#endif /* _CALLSTACK_H */
diff --git a/gprofng/src/CatchOutOfMemory.cc b/gprofng/src/CatchOutOfMemory.cc
new file mode 100644 (file)
index 0000000..61b91cf
--- /dev/null
@@ -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.  */
+
+#include "config.h"
+#include <new>          // std::bad_alloc
+#include <stdio.h>      // fprintf
+#include <stdlib.h>     // exit
+#include "DbeApplication.h"
+
+static char *name = NULL;
+
+/**
+ * Out Of Memory exception handler
+ */
+void
+out_of_mem ()
+{
+  fprintf (stderr, "%s: %s: %s\n", "Error", name ? name : "", "Out of memory\n");
+  exit (2); // Out of memory
+  // throw bad_alloc();
+}
+
+/**
+ * Calls real_main inside try{...}catch(std::bad_alloc *)
+ */
+int
+catch_out_of_memory (int (*real_main)(int, char*[]), int argc, char *argv[])
+{
+  int i = 0;
+  name = argv[0];
+  std::set_new_handler (out_of_mem);
+  try
+    {
+      i = real_main (argc, argv);
+    }
+  catch (std::bad_alloc */*ba*/)
+    {
+      exit (2); // Out of memory
+    }
+  delete theDbeApplication;
+  return i;
+}
diff --git a/gprofng/src/ClassFile.cc b/gprofng/src/ClassFile.cc
new file mode 100644 (file)
index 0000000..7dd64a7
--- /dev/null
@@ -0,0 +1,1639 @@
+/* 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 <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "ClassFile.h"
+#include "Function.h"
+#include "StringBuilder.h"
+#include "DbeFile.h"
+
+class ByteCodeInfo
+{
+public:
+
+  ByteCodeInfo (JMethod *_func, int _bci, int _lno)
+  {
+    func = _func;
+    bci = _bci;
+    lno = _lno;
+  };
+
+  JMethod *func;
+  int bci;
+  int lno;
+};
+
+typedef unsigned char u1;
+typedef unsigned short u2;
+typedef unsigned int u4;
+
+// Class File Constants
+#define JAVA_MAGIC        0xcafebabe
+
+enum {
+  // First argument in access_flags_to_str()
+  ClassAccess = 1,
+  FieldAccess,
+  MethodAccess,
+  NestedClassAccess,
+
+  // jdk/src/share/classes/sun/tools/java/RuntimeConstants.java
+  // Type codes
+  T_CLASS             = 0x00000002,
+  T_BOOLEAN           = 0x00000004,
+  T_CHAR              = 0x00000005,
+  T_FLOAT             = 0x00000006,
+  T_DOUBLE            = 0x00000007,
+  T_BYTE              = 0x00000008,
+  T_SHORT             = 0x00000009,
+  T_INT               = 0x0000000a,
+  T_LONG              = 0x0000000b,
+
+// Access and modifier flags
+  ACC_PUBLIC          = 0x00000001,
+  ACC_PRIVATE         = 0x00000002,
+  ACC_PROTECTED       = 0x00000004,
+  ACC_STATIC          = 0x00000008,
+  ACC_FINAL           = 0x00000010,
+  ACC_SYNCHRONIZED    = 0x00000020,
+  ACC_VOLATILE        = 0x00000040,
+  ACC_TRANSIENT       = 0x00000080,
+  ACC_NATIVE          = 0x00000100,
+  ACC_INTERFACE       = 0x00000200,
+  ACC_ABSTRACT        = 0x00000400,
+  ACC_STRICT          = 0x00000800,
+  ACC_SYNTHETIC       = 0x00001000,
+  ACC_ANNOTATION      = 0x00002000,
+  ACC_ENUM            = 0x00004000,
+
+  ACC_SUPER           = 0x00000020,
+  ACC_BRIDGE          = 0x00000040,
+  ACC_VARARGS         = 0x00000080,
+
+// Opcodes
+  opc_try             = -3,
+  opc_dead            = -2,
+  opc_label           = -1,
+  opc_nop             = 0,
+  opc_aconst_null     = 1,
+  opc_iconst_m1       = 2,
+  opc_iconst_0        = 3,
+  opc_iconst_1        = 4,
+  opc_iconst_2        = 5,
+  opc_iconst_3        = 6,
+  opc_iconst_4        = 7,
+  opc_iconst_5        = 8,
+  opc_lconst_0        = 9,
+  opc_lconst_1        = 10,
+  opc_fconst_0        = 11,
+  opc_fconst_1        = 12,
+  opc_fconst_2        = 13,
+  opc_dconst_0        = 14,
+  opc_dconst_1        = 15,
+  opc_bipush          = 16,
+  opc_sipush          = 17,
+  opc_ldc             = 18,
+  opc_ldc_w           = 19,
+  opc_ldc2_w          = 20,
+  opc_iload           = 21,
+  opc_lload           = 22,
+  opc_fload           = 23,
+  opc_dload           = 24,
+  opc_aload           = 25,
+  opc_iload_0         = 26,
+  opc_iload_1         = 27,
+  opc_iload_2         = 28,
+  opc_iload_3         = 29,
+  opc_lload_0         = 30,
+  opc_lload_1         = 31,
+  opc_lload_2         = 32,
+  opc_lload_3         = 33,
+  opc_fload_0         = 34,
+  opc_fload_1         = 35,
+  opc_fload_2         = 36,
+  opc_fload_3         = 37,
+  opc_dload_0         = 38,
+  opc_dload_1         = 39,
+  opc_dload_2         = 40,
+  opc_dload_3         = 41,
+  opc_aload_0         = 42,
+  opc_aload_1         = 43,
+  opc_aload_2         = 44,
+  opc_aload_3         = 45,
+  opc_iaload          = 46,
+  opc_laload          = 47,
+  opc_faload          = 48,
+  opc_daload          = 49,
+  opc_aaload          = 50,
+  opc_baload          = 51,
+  opc_caload          = 52,
+  opc_saload          = 53,
+  opc_istore          = 54,
+  opc_lstore          = 55,
+  opc_fstore          = 56,
+  opc_dstore          = 57,
+  opc_astore          = 58,
+  opc_istore_0        = 59,
+  opc_istore_1        = 60,
+  opc_istore_2        = 61,
+  opc_istore_3        = 62,
+  opc_lstore_0        = 63,
+  opc_lstore_1        = 64,
+  opc_lstore_2        = 65,
+  opc_lstore_3        = 66,
+  opc_fstore_0        = 67,
+  opc_fstore_1        = 68,
+  opc_fstore_2        = 69,
+  opc_fstore_3        = 70,
+  opc_dstore_0        = 71,
+  opc_dstore_1        = 72,
+  opc_dstore_2        = 73,
+  opc_dstore_3        = 74,
+  opc_astore_0        = 75,
+  opc_astore_1        = 76,
+  opc_astore_2        = 77,
+  opc_astore_3        = 78,
+  opc_iastore         = 79,
+  opc_lastore         = 80,
+  opc_fastore         = 81,
+  opc_dastore         = 82,
+  opc_aastore         = 83,
+  opc_bastore         = 84,
+  opc_castore         = 85,
+  opc_sastore         = 86,
+  opc_pop             = 87,
+  opc_pop2            = 88,
+  opc_dup             = 89,
+  opc_dup_x1          = 90,
+  opc_dup_x2          = 91,
+  opc_dup2            = 92,
+  opc_dup2_x1         = 93,
+  opc_dup2_x2         = 94,
+  opc_swap            = 95,
+  opc_iadd            = 96,
+  opc_ladd            = 97,
+  opc_fadd            = 98,
+  opc_dadd            = 99,
+  opc_isub            = 100,
+  opc_lsub            = 101,
+  opc_fsub            = 102,
+  opc_dsub            = 103,
+  opc_imul            = 104,
+  opc_lmul            = 105,
+  opc_fmul            = 106,
+  opc_dmul            = 107,
+  opc_idiv            = 108,
+  opc_ldiv            = 109,
+  opc_fdiv            = 110,
+  opc_ddiv            = 111,
+  opc_irem            = 112,
+  opc_lrem            = 113,
+  opc_frem            = 114,
+  opc_drem            = 115,
+  opc_ineg            = 116,
+  opc_lneg            = 117,
+  opc_fneg            = 118,
+  opc_dneg            = 119,
+  opc_ishl            = 120,
+  opc_lshl            = 121,
+  opc_ishr            = 122,
+  opc_lshr            = 123,
+  opc_iushr           = 124,
+  opc_lushr           = 125,
+  opc_iand            = 126,
+  opc_land            = 127,
+  opc_ior             = 128,
+  opc_lor             = 129,
+  opc_ixor            = 130,
+  opc_lxor            = 131,
+  opc_iinc            = 132,
+  opc_i2l             = 133,
+  opc_i2f             = 134,
+  opc_i2d             = 135,
+  opc_l2i             = 136,
+  opc_l2f             = 137,
+  opc_l2d             = 138,
+  opc_f2i             = 139,
+  opc_f2l             = 140,
+  opc_f2d             = 141,
+  opc_d2i             = 142,
+  opc_d2l             = 143,
+  opc_d2f             = 144,
+  opc_i2b             = 145,
+  opc_i2c             = 146,
+  opc_i2s             = 147,
+  opc_lcmp            = 148,
+  opc_fcmpl           = 149,
+  opc_fcmpg           = 150,
+  opc_dcmpl           = 151,
+  opc_dcmpg           = 152,
+  opc_ifeq            = 153,
+  opc_ifne            = 154,
+  opc_iflt            = 155,
+  opc_ifge            = 156,
+  opc_ifgt            = 157,
+  opc_ifle            = 158,
+  opc_if_icmpeq       = 159,
+  opc_if_icmpne       = 160,
+  opc_if_icmplt       = 161,
+  opc_if_icmpge       = 162,
+  opc_if_icmpgt       = 163,
+  opc_if_icmple       = 164,
+  opc_if_acmpeq       = 165,
+  opc_if_acmpne       = 166,
+  opc_goto            = 167,
+  opc_jsr             = 168,
+  opc_ret             = 169,
+  opc_tableswitch     = 170,
+  opc_lookupswitch    = 171,
+  opc_ireturn         = 172,
+  opc_lreturn         = 173,
+  opc_freturn         = 174,
+  opc_dreturn         = 175,
+  opc_areturn         = 176,
+  opc_return          = 177,
+  opc_getstatic       = 178,
+  opc_putstatic       = 179,
+  opc_getfield        = 180,
+  opc_putfield        = 181,
+  opc_invokevirtual   = 182,
+  opc_invokespecial   = 183,
+  opc_invokestatic    = 184,
+  opc_invokeinterface = 185,
+  opc_invokedynamic   = 186,
+  opc_new             = 187,
+  opc_newarray        = 188,
+  opc_anewarray       = 189,
+  opc_arraylength     = 190,
+  opc_athrow          = 191,
+  opc_checkcast       = 192,
+  opc_instanceof      = 193,
+  opc_monitorenter    = 194,
+  opc_monitorexit     = 195,
+  opc_wide            = 196,
+  opc_multianewarray  = 197,
+  opc_ifnull          = 198,
+  opc_ifnonnull       = 199,
+  opc_goto_w          = 200,
+  opc_jsr_w           = 201,
+  opc_breakpoint      = 202,
+
+// Constant table
+  CONSTANT_UTF8       = 1,
+  CONSTANT_UNICODE    = 2,
+  CONSTANT_INTEGER    = 3,
+  CONSTANT_FLOAT      = 4,
+  CONSTANT_LONG       = 5,
+  CONSTANT_DOUBLE     = 6,
+  CONSTANT_CLASS      = 7,
+  CONSTANT_STRING     = 8,
+  CONSTANT_FIELD      = 9,
+  CONSTANT_METHOD     = 10,
+  CONSTANT_INTERFACEMETHOD = 11,
+  CONSTANT_NAMEANDTYPE    = 12,
+  CONSTANT_METHODHANDLE   = 15,
+  CONSTANT_METHODTYPE     = 16,
+  CONSTANT_INVOKEDYNAMIC  = 18
+};
+
+static char *opcNames[] = {
+  NTXT ("nop"),
+  NTXT ("aconst_null"),
+  NTXT ("iconst_m1"),
+  NTXT ("iconst_0"),
+  NTXT ("iconst_1"),
+  NTXT ("iconst_2"),
+  NTXT ("iconst_3"),
+  NTXT ("iconst_4"),
+  NTXT ("iconst_5"),
+  NTXT ("lconst_0"),
+  NTXT ("lconst_1"),
+  NTXT ("fconst_0"),
+  NTXT ("fconst_1"),
+  NTXT ("fconst_2"),
+  NTXT ("dconst_0"),
+  NTXT ("dconst_1"),
+  NTXT ("bipush"),
+  NTXT ("sipush"),
+  NTXT ("ldc"),
+  NTXT ("ldc_w"),
+  NTXT ("ldc2_w"),
+  NTXT ("iload"),
+  NTXT ("lload"),
+  NTXT ("fload"),
+  NTXT ("dload"),
+  NTXT ("aload"),
+  NTXT ("iload_0"),
+  NTXT ("iload_1"),
+  NTXT ("iload_2"),
+  NTXT ("iload_3"),
+  NTXT ("lload_0"),
+  NTXT ("lload_1"),
+  NTXT ("lload_2"),
+  NTXT ("lload_3"),
+  NTXT ("fload_0"),
+  NTXT ("fload_1"),
+  NTXT ("fload_2"),
+  NTXT ("fload_3"),
+  NTXT ("dload_0"),
+  NTXT ("dload_1"),
+  NTXT ("dload_2"),
+  NTXT ("dload_3"),
+  NTXT ("aload_0"),
+  NTXT ("aload_1"),
+  NTXT ("aload_2"),
+  NTXT ("aload_3"),
+  NTXT ("iaload"),
+  NTXT ("laload"),
+  NTXT ("faload"),
+  NTXT ("daload"),
+  NTXT ("aaload"),
+  NTXT ("baload"),
+  NTXT ("caload"),
+  NTXT ("saload"),
+  NTXT ("istore"),
+  NTXT ("lstore"),
+  NTXT ("fstore"),
+  NTXT ("dstore"),
+  NTXT ("astore"),
+  NTXT ("istore_0"),
+  NTXT ("istore_1"),
+  NTXT ("istore_2"),
+  NTXT ("istore_3"),
+  NTXT ("lstore_0"),
+  NTXT ("lstore_1"),
+  NTXT ("lstore_2"),
+  NTXT ("lstore_3"),
+  NTXT ("fstore_0"),
+  NTXT ("fstore_1"),
+  NTXT ("fstore_2"),
+  NTXT ("fstore_3"),
+  NTXT ("dstore_0"),
+  NTXT ("dstore_1"),
+  NTXT ("dstore_2"),
+  NTXT ("dstore_3"),
+  NTXT ("astore_0"),
+  NTXT ("astore_1"),
+  NTXT ("astore_2"),
+  NTXT ("astore_3"),
+  NTXT ("iastore"),
+  NTXT ("lastore"),
+  NTXT ("fastore"),
+  NTXT ("dastore"),
+  NTXT ("aastore"),
+  NTXT ("bastore"),
+  NTXT ("castore"),
+  NTXT ("sastore"),
+  NTXT ("pop"),
+  NTXT ("pop2"),
+  NTXT ("dup"),
+  NTXT ("dup_x1"),
+  NTXT ("dup_x2"),
+  NTXT ("dup2"),
+  NTXT ("dup2_x1"),
+  NTXT ("dup2_x2"),
+  NTXT ("swap"),
+  NTXT ("iadd"),
+  NTXT ("ladd"),
+  NTXT ("fadd"),
+  NTXT ("dadd"),
+  NTXT ("isub"),
+  NTXT ("lsub"),
+  NTXT ("fsub"),
+  NTXT ("dsub"),
+  NTXT ("imul"),
+  NTXT ("lmul"),
+  NTXT ("fmul"),
+  NTXT ("dmul"),
+  NTXT ("idiv"),
+  NTXT ("ldiv"),
+  NTXT ("fdiv"),
+  NTXT ("ddiv"),
+  NTXT ("irem"),
+  NTXT ("lrem"),
+  NTXT ("frem"),
+  NTXT ("drem"),
+  NTXT ("ineg"),
+  NTXT ("lneg"),
+  NTXT ("fneg"),
+  NTXT ("dneg"),
+  NTXT ("ishl"),
+  NTXT ("lshl"),
+  NTXT ("ishr"),
+  NTXT ("lshr"),
+  NTXT ("iushr"),
+  NTXT ("lushr"),
+  NTXT ("iand"),
+  NTXT ("land"),
+  NTXT ("ior"),
+  NTXT ("lor"),
+  NTXT ("ixor"),
+  NTXT ("lxor"),
+  NTXT ("iinc"),
+  NTXT ("i2l"),
+  NTXT ("i2f"),
+  NTXT ("i2d"),
+  NTXT ("l2i"),
+  NTXT ("l2f"),
+  NTXT ("l2d"),
+  NTXT ("f2i"),
+  NTXT ("f2l"),
+  NTXT ("f2d"),
+  NTXT ("d2i"),
+  NTXT ("d2l"),
+  NTXT ("d2f"),
+  NTXT ("i2b"),
+  NTXT ("i2c"),
+  NTXT ("i2s"),
+  NTXT ("lcmp"),
+  NTXT ("fcmpl"),
+  NTXT ("fcmpg"),
+  NTXT ("dcmpl"),
+  NTXT ("dcmpg"),
+  NTXT ("ifeq"),
+  NTXT ("ifne"),
+  NTXT ("iflt"),
+  NTXT ("ifge"),
+  NTXT ("ifgt"),
+  NTXT ("ifle"),
+  NTXT ("if_icmpeq"),
+  NTXT ("if_icmpne"),
+  NTXT ("if_icmplt"),
+  NTXT ("if_icmpge"),
+  NTXT ("if_icmpgt"),
+  NTXT ("if_icmple"),
+  NTXT ("if_acmpeq"),
+  NTXT ("if_acmpne"),
+  NTXT ("goto"),
+  NTXT ("jsr"),
+  NTXT ("ret"),
+  NTXT ("tableswitch"),
+  NTXT ("lookupswitch"),
+  NTXT ("ireturn"),
+  NTXT ("lreturn"),
+  NTXT ("freturn"),
+  NTXT ("dreturn"),
+  NTXT ("areturn"),
+  NTXT ("return"),
+  NTXT ("getstatic"),
+  NTXT ("putstatic"),
+  NTXT ("getfield"),
+  NTXT ("putfield"),
+  NTXT ("invokevirtual"),
+  NTXT ("invokespecial"),
+  NTXT ("invokestatic"),
+  NTXT ("invokeinterface"),
+  NTXT ("invokedynamic"),
+  NTXT ("new"),
+  NTXT ("newarray"),
+  NTXT ("anewarray"),
+  NTXT ("arraylength"),
+  NTXT ("athrow"),
+  NTXT ("checkcast"),
+  NTXT ("instanceof"),
+  NTXT ("monitorenter"),
+  NTXT ("monitorexit"),
+  NTXT ("wide"),
+  NTXT ("multianewarray"),
+  NTXT ("ifnull"),
+  NTXT ("ifnonnull"),
+  NTXT ("goto_w"),
+  NTXT ("jsr_w"),
+  NTXT ("breakpoint")
+};
+
+
+#define APPEND_FLAG(len, buf, flag, x) \
+    if (((x) & (flag)) != 0) \
+      { \
+       flag &= ~(x); \
+       AppendString(len, buf, NTXT("%s%s"), delimiter, #x); \
+       delimiter = NTXT("|"); \
+      }
+
+static char *
+access_flags_to_str (int kind, int flag)
+{
+  static char buf[256];
+  size_t len = 0;
+  buf[0] = 0;
+  if (flag == 0)
+    {
+      AppendString (len, buf, NTXT ("0x%x"), (unsigned int) flag);
+      return buf;
+    }
+  const char *delimiter = "";
+  if (kind == ClassAccess)
+    {
+      APPEND_FLAG (len, buf, flag, ACC_FINAL);
+      APPEND_FLAG (len, buf, flag, ACC_SUPER);
+      APPEND_FLAG (len, buf, flag, ACC_INTERFACE);
+      APPEND_FLAG (len, buf, flag, ACC_ABSTRACT);
+      APPEND_FLAG (len, buf, flag, ACC_SYNTHETIC);
+      APPEND_FLAG (len, buf, flag, ACC_ANNOTATION);
+      APPEND_FLAG (len, buf, flag, ACC_ENUM);
+      if (flag)
+       AppendString (len, buf, "%s0x%x", delimiter, (unsigned int) (flag));
+    }
+  else if (kind == FieldAccess)
+    {
+      APPEND_FLAG (len, buf, flag, ACC_PUBLIC);
+      APPEND_FLAG (len, buf, flag, ACC_PRIVATE);
+      APPEND_FLAG (len, buf, flag, ACC_PROTECTED);
+      APPEND_FLAG (len, buf, flag, ACC_STATIC);
+      APPEND_FLAG (len, buf, flag, ACC_FINAL);
+      APPEND_FLAG (len, buf, flag, ACC_VOLATILE);
+      APPEND_FLAG (len, buf, flag, ACC_TRANSIENT);
+      APPEND_FLAG (len, buf, flag, ACC_SYNTHETIC);
+      APPEND_FLAG (len, buf, flag, ACC_ENUM);
+      if (flag)
+       AppendString (len, buf, "%s0x%x", delimiter, (unsigned int) (flag));
+    }
+  else if (kind == MethodAccess)
+    {
+      APPEND_FLAG (len, buf, flag, ACC_PUBLIC);
+      APPEND_FLAG (len, buf, flag, ACC_PRIVATE);
+      APPEND_FLAG (len, buf, flag, ACC_PROTECTED);
+      APPEND_FLAG (len, buf, flag, ACC_STATIC);
+      APPEND_FLAG (len, buf, flag, ACC_FINAL);
+      APPEND_FLAG (len, buf, flag, ACC_SYNCHRONIZED);
+      APPEND_FLAG (len, buf, flag, ACC_BRIDGE);
+      APPEND_FLAG (len, buf, flag, ACC_VARARGS);
+      APPEND_FLAG (len, buf, flag, ACC_NATIVE);
+      APPEND_FLAG (len, buf, flag, ACC_ABSTRACT);
+      APPEND_FLAG (len, buf, flag, ACC_STRICT);
+      APPEND_FLAG (len, buf, flag, ACC_SYNTHETIC);
+      if (flag)
+       AppendString (len, buf, "%s0x%x", delimiter, (unsigned int) (flag));
+    }
+  else if (kind == NestedClassAccess)
+    {
+      APPEND_FLAG (len, buf, flag, ACC_PUBLIC);
+      APPEND_FLAG (len, buf, flag, ACC_PRIVATE);
+      APPEND_FLAG (len, buf, flag, ACC_PROTECTED);
+      APPEND_FLAG (len, buf, flag, ACC_STATIC);
+      APPEND_FLAG (len, buf, flag, ACC_FINAL);
+      APPEND_FLAG (len, buf, flag, ACC_INTERFACE);
+      APPEND_FLAG (len, buf, flag, ACC_ABSTRACT);
+      APPEND_FLAG (len, buf, flag, ACC_SYNTHETIC);
+      APPEND_FLAG (len, buf, flag, ACC_ANNOTATION);
+      APPEND_FLAG (len, buf, flag, ACC_ENUM);
+      if (flag)
+       AppendString (len, buf, "%s0x%x", delimiter, (unsigned int) (flag));
+    }
+  return buf;
+}
+
+class DataReadException
+{
+public:
+
+  DataReadException (char *s)
+  {
+    str_err = s;
+  }
+
+  ~DataReadException ()
+  {
+    free (str_err);
+  }
+
+  char *
+  toString ()
+  {
+    return str_err;
+  }
+
+private:
+  char *str_err;
+};
+
+class DataInputStream
+{
+public:
+
+  DataInputStream (const unsigned char *bytes, int64_t sz)
+  {
+    bp = bp_orig = bytes;
+    bp_last = bp_orig + sz;
+  }
+
+  DataInputStream (DataInputStream *in)
+  {
+    bp = bp_orig = in->bp_orig;
+    bp_last = in->bp_last;
+  }
+
+  u1
+  readByte ()
+  {
+    check (1);
+    u1 val = *bp;
+    bp++;
+    return val;
+  }
+
+  u2
+  readUnsignedShort ()
+  {
+    check (2);
+    u2 val = (bp[0] << 8) | bp[1];
+    bp += 2;
+    return val;
+  }
+
+  u4
+  readUnsigned ()
+  {
+    check (4);
+    u4 val = (bp[0] << 24) | (bp[1] << 16) | (bp[2] << 8) | bp[3];
+    bp += 4;
+    return val;
+  }
+
+  const u1 *
+  getptr ()
+  {
+    return bp;
+  }
+
+  const size_t
+  get_offset ()
+  {
+    return bp - bp_orig;
+  }
+
+  void
+  skip (int n)
+  {
+    check (n);
+    bp += n;
+  }
+
+  void
+  reset ()
+  {
+    bp = bp_orig;
+  }
+
+  void
+  copy_bytes (char *buf, int64_t len)
+  {
+    check (len);
+    memcpy (buf, bp, len);
+    buf[len] = '\0';
+  }
+
+private:
+
+  void
+  check (int64_t sz)
+  {
+    if (sz < 0 || bp + sz > bp_last)
+      {
+       DataReadException *e1 = new DataReadException (
+              dbe_sprintf (GTXT ("(Cannot read %lld byte(s) offset=0x%llx)\n"),
+                           (long long) sz, (long long) get_offset ()));
+       throw (e1);
+      }
+  };
+
+  const unsigned char *bp_last;
+  const unsigned char *bp_orig;
+  const unsigned char *bp;
+};
+
+class BinaryConstantPool
+{
+public:
+  BinaryConstantPool (DataInputStream &in);
+  ~BinaryConstantPool ();
+
+  u1
+  getType (int n)
+  {
+    return (n < nconst && n > 0) ? types[n] : 0;
+  };
+  char *getString (int index);
+
+private:
+  static char *getTypeName (int ty);
+  static char *type_name_to_str (int ty);
+  static char *offset_to_str (long long offset);
+  int nconst;
+  u1 *types;
+  int64_t *offsets;
+  char **strings;
+  DataInputStream *input;
+};
+
+char *
+BinaryConstantPool::type_name_to_str (int ty)
+{
+  static char buf[128];
+  char *tyName = getTypeName (ty);
+  snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), tyName, ty);
+  return buf;
+}
+
+char *
+BinaryConstantPool::offset_to_str (long long offset)
+{
+  static char buf[128];
+  snprintf (buf, sizeof (buf), NTXT ("offset=0x%06llx (%llu)"), offset, offset);
+  return buf;
+}
+
+BinaryConstantPool::BinaryConstantPool (DataInputStream &in)
+{
+  nconst = 0;
+  types = NULL;
+  offsets = NULL;
+  strings = NULL;
+  input = new DataInputStream (in);
+  int cntConst = in.readUnsignedShort ();
+  if (cntConst > 0)
+    {
+      types = new u1[cntConst];
+      types[0] = 0;
+      offsets = new int64_t [cntConst];
+      strings = new char * [cntConst];
+      strings[0] = NULL;
+    }
+  Dprintf (DUMP_JAVA_CLASS, NTXT ("# BinaryConstantPool: %d\n"), (int) nconst);
+  for (int i = 1; i < cntConst; i++)
+    {
+      nconst = i + 1;
+      strings[i] = NULL;
+      types[i] = in.readByte ();
+      offsets[i] = in.get_offset ();
+      Dprintf (DUMP_JAVA_CLASS, NTXT (" %3d %-25s %-25s"), i, offset_to_str (offsets[i]), type_name_to_str (types[i]));
+      switch (types[i])
+       {
+       case CONSTANT_UTF8:
+         {
+           u2 length = in.readUnsignedShort ();
+           in.skip (length);
+           Dprintf (DUMP_JAVA_CLASS, " length=%u\n", (unsigned int) length);
+           break;
+         }
+       case CONSTANT_INTEGER:
+         {
+           u4 bytes = in.readUnsigned ();
+           Dprintf (DUMP_JAVA_CLASS, " bytes=0x%08x\n", (unsigned int) bytes);
+           break;
+         }
+       case CONSTANT_FLOAT:
+         {
+           u4 bytes = in.readUnsigned ();
+           Dprintf (DUMP_JAVA_CLASS, " bytes=0x%08x\n", (unsigned int) bytes);
+           break;
+         }
+       case CONSTANT_LONG:
+       case CONSTANT_DOUBLE:
+         {
+           // JVM 4.4.5: all 8-byte constants take up
+           // two entries in the constant_pool table.
+           i++;
+           nconst++;
+           offsets[i] = 0;
+           strings[i] = NULL;
+           u4 high_bytes = in.readUnsigned ();
+           u4 low_bytes = in.readUnsigned ();
+           Dprintf (DUMP_JAVA_CLASS, NTXT (" high_bytes=0x%08x  low_bytes=0x%08x\n"),
+                    (unsigned int) high_bytes, (unsigned int) low_bytes);
+           break;
+         }
+       case CONSTANT_CLASS:
+         {
+           u2 name_index = in.readUnsignedShort ();
+           Dprintf (DUMP_JAVA_CLASS, NTXT (" name_index=%6u\n"), (unsigned int) name_index);
+           break;
+         }
+       case CONSTANT_STRING:
+         {
+           u2 string_index = in.readUnsignedShort ();
+           Dprintf (DUMP_JAVA_CLASS, NTXT (" string_index=%4u\n"), (unsigned int) string_index);
+           break;
+         }
+       case CONSTANT_FIELD:
+       case CONSTANT_METHOD:
+       case CONSTANT_INTERFACEMETHOD:
+         {
+           u2 class_index = in.readUnsignedShort ();
+           u2 name_and_type_index = in.readUnsignedShort ();
+           Dprintf (DUMP_JAVA_CLASS, NTXT (" class_index=%5u  name_and_type_index=%u\n"),
+                    (unsigned int) class_index, (unsigned int) name_and_type_index);
+           break;
+         }
+       case CONSTANT_NAMEANDTYPE:
+         {
+           u2 name_index = in.readUnsignedShort ();
+           u2 descriptor_index = in.readUnsignedShort ();
+           Dprintf (DUMP_JAVA_CLASS, " name_index=%6u  descriptor_index=%u\n",
+                   (unsigned int) name_index, (unsigned int) descriptor_index);
+           break;
+         }
+       case CONSTANT_METHODHANDLE:
+         {
+           u1 reference_kind = in.readByte ();
+           u2 reference_index = in.readUnsignedShort ();
+           Dprintf (DUMP_JAVA_CLASS, " reference_kind=%u reference_index=%u\n",
+                (unsigned int) reference_kind, (unsigned int) reference_index);
+           break;
+         }
+       case CONSTANT_METHODTYPE:
+         {
+           u2 descriptor_index = in.readUnsignedShort ();
+           Dprintf (DUMP_JAVA_CLASS, NTXT (" descriptor_index=%u\n"),
+                    (unsigned int) descriptor_index);
+           break;
+         }
+       case CONSTANT_INVOKEDYNAMIC:
+         {
+           u2 bootstrap_method_attr_index = in.readUnsignedShort ();
+           u2 name_and_type_index = in.readUnsignedShort ();
+           Dprintf (DUMP_JAVA_CLASS, NTXT (" bootstrap_method_attr_index=%5u  name_and_type_index=%u\n"),
+                    (unsigned int) bootstrap_method_attr_index,
+                    (unsigned int) name_and_type_index);
+           break;
+         }
+       default:
+         Dprintf (DUMP_JAVA_CLASS, NTXT ("\n"));
+         DataReadException *e1 = new DataReadException (
+                 dbe_sprintf (GTXT ("BinaryConstantPool[%d]: bad tag %d %s\n"),
+                              i, types[i], offset_to_str (offsets[i])));
+         throw (e1);
+       }
+    }
+}
+
+BinaryConstantPool::~BinaryConstantPool ()
+{
+  delete[] types;
+  delete[] offsets;
+  delete input;
+  if (strings)
+    {
+      for (int i = 0; i < nconst; i++)
+       free (strings[i]);
+      delete[] strings;
+    }
+}
+
+#define CASE_S(x)   case x: return (char *) #x
+
+char *
+BinaryConstantPool::getTypeName (int ty)
+{
+  switch (ty)
+    {
+      CASE_S (CONSTANT_UTF8);
+      CASE_S (CONSTANT_INTEGER);
+      CASE_S (CONSTANT_FLOAT);
+      CASE_S (CONSTANT_LONG);
+      CASE_S (CONSTANT_DOUBLE);
+      CASE_S (CONSTANT_CLASS);
+      CASE_S (CONSTANT_STRING);
+      CASE_S (CONSTANT_FIELD);
+      CASE_S (CONSTANT_METHOD);
+      CASE_S (CONSTANT_INTERFACEMETHOD);
+      CASE_S (CONSTANT_NAMEANDTYPE);
+      CASE_S (CONSTANT_METHODHANDLE);
+      CASE_S (CONSTANT_METHODTYPE);
+      CASE_S (CONSTANT_INVOKEDYNAMIC);
+    default: return NTXT ("UNKNOWN_TYPE");
+    }
+}
+
+char *
+BinaryConstantPool::getString (int index)
+{
+  if (index >= nconst || index <= 0)
+    return NULL;
+  if (strings[index])
+    return strings[index];
+  input->reset ();
+  input->skip (offsets[index]);
+  switch (types[index])
+    {
+    case CONSTANT_CLASS:
+    case CONSTANT_STRING:
+    case CONSTANT_NAMEANDTYPE:
+      strings[index] = dbe_strdup (getString (input->readUnsignedShort ()));
+      return strings[index];
+    case CONSTANT_METHOD:
+      input->readUnsignedShort (); // cl_inx
+      strings[index] = dbe_strdup (getString (input->readUnsignedShort ()));
+      return strings[index];
+    case CONSTANT_UTF8:
+      break;
+    default:
+      return NULL;
+    }
+  u2 len = input->readUnsignedShort ();
+  strings[index] = (char *) malloc (len + 1);
+  input->copy_bytes (strings[index], len);
+  return strings[index];
+}
+
+ClassFile::ClassFile () : Module ()
+{
+  input = NULL;
+  bcpool = NULL;
+  cf_buf = NULL;
+  cur_jmthd = NULL;
+  blanksCnt = 0;
+  cf_bufsz = 0;
+  lang_code = Sp_lang_java;
+  class_name = NULL;
+  class_filename = NULL;
+  source_name = NULL;
+  byteCodeInfo = NULL;
+}
+
+char *
+ClassFile::get_opc_name (int op)
+{
+  if (op >= 0 && ((size_t) op) < sizeof (opcNames) / sizeof (char*))
+    return opcNames[op];
+  switch (op)
+    {
+    case opc_try:
+      return NTXT ("try");
+    case opc_dead:
+      return NTXT ("dead");
+    case opc_label:
+      return NTXT ("label");
+    default:
+      return NTXT ("Unknown op code");
+    }
+}
+
+void
+ClassFile::openFile (const char *fname)
+{
+  if (fname == NULL)
+    return;
+  int fd = open64 (fname, O_RDONLY);
+  if (fd == -1)
+    {
+      append_msg (CMSG_ERROR, GTXT ("Cannot open file %s"), fname);
+      return;
+    }
+  struct stat64 stat_buf;
+  if ((fstat64 (fd, &stat_buf) == -1) || (stat_buf.st_size == 0))
+    {
+      close (fd);
+      append_msg (CMSG_ERROR, GTXT ("Cannot read file %s"), fname);
+      return;
+    }
+  cf_bufsz = stat_buf.st_size;
+  cf_buf = (unsigned char *) malloc (cf_bufsz);
+  if (cf_bufsz != read_from_file (fd, cf_buf, cf_bufsz))
+    {
+      free (cf_buf);
+      cf_buf = NULL;
+      close (fd);
+      append_msg (CMSG_ERROR, GTXT ("Cannot read file %s"), fname);
+      return;
+    }
+  close (fd);
+
+  input = new DataInputStream (cf_buf, cf_bufsz);
+  u4 c_magic = input->readUnsigned ();
+  if (c_magic != JAVA_MAGIC)
+    {
+      append_msg (CMSG_ERROR, GTXT ("Not a class file: %s"), fname);
+      return;
+    }
+  /* u2 minor = */ input->readUnsignedShort ();
+  /* u2 major = */ input->readUnsignedShort ();
+  status = AE_OK;
+}
+
+ClassFile::~ClassFile ()
+{
+  free (cf_buf);
+  free (class_name);
+  free (class_filename);
+  free (source_name);
+  delete bcpool;
+  delete input;
+}
+
+static void
+convertName (char *s)
+{
+  while (*s)
+    {
+      if (*s == '/')
+       *s = '.';
+      s++;
+    }
+}
+
+void
+ClassFile::printConstant (StringBuilder *sb, int index)
+{
+  u1 type = bcpool->getType (index);
+  switch (type)
+    {
+    case CONSTANT_METHOD:
+      {
+       char *str = bcpool->getString (index);
+       if (str)
+         {
+           convertName (str);
+           sb->append (str);
+           sb->append (NTXT ("()"));
+         }
+       break;
+      }
+    case CONSTANT_CLASS:
+      {
+       char *str = bcpool->getString (index);
+       if (str)
+         {
+           convertName (str);
+           sb->append (str);
+         }
+       break;
+      }
+    case CONSTANT_UTF8:
+      {
+       char *str = bcpool->getString (index);
+       if (str)
+         sb->append (str);
+       break;
+      }
+    case CONSTANT_STRING:
+      {
+       char *str = bcpool->getString (index);
+       if (str)
+         {
+           sb->append ('"');
+           sb->append (str);
+           sb->append ('"');
+         }
+       break;
+      }
+    default:
+      sb->append ('#');
+      sb->append ((int) index);
+      break;
+    }
+}
+
+long long
+ClassFile::printCodeSequence (StringBuilder *sb, uint64_t addr, DataInputStream *in)
+{
+  int64_t offset = in->get_offset ();
+  sb->appendf (NTXT ("%08llx: "), (long long) addr);
+  int opcode = in->readByte ();
+  if (opcode == opc_wide)
+    {
+      opcode = in->readByte ();
+      sb->append (get_opc_name (opcode));
+      sb->append (NTXT ("_w "));
+      int arg = in->readUnsignedShort ();
+      switch (opcode)
+       {
+       case opc_aload: case opc_astore:
+       case opc_fload: case opc_fstore:
+       case opc_iload: case opc_istore:
+       case opc_lload: case opc_lstore:
+       case opc_dload: case opc_dstore:
+       case opc_ret:
+         sb->append (arg);
+         break;
+       case opc_iinc:
+         sb->append (arg);
+         sb->append (' ');
+         sb->append (in->readUnsignedShort ());
+         break;
+       default:
+         sb->append (GTXT ("Invalid opcode"));
+         break;
+       }
+    }
+  else
+    {
+      sb->append (get_opc_name (opcode));
+      sb->append (' ');
+      switch (opcode)
+       {
+       case opc_aload: case opc_astore:
+       case opc_fload: case opc_fstore:
+       case opc_iload: case opc_istore:
+       case opc_lload: case opc_lstore:
+       case opc_dload: case opc_dstore:
+       case opc_ret:
+         sb->append (in->readByte ());
+         break;
+       case opc_iinc:
+         sb->append (in->readByte ());
+         sb->append (' ');
+         sb->append (in->readByte ());
+         break;
+       case opc_tableswitch:
+         {
+           int align = (addr + 1) % 4; // 1 byte is a length of opc_lookupswitch
+           if (align != 0)
+             {
+               in->skip (4 - align); // four byte boundry
+             }
+           long default_skip = in->readUnsigned ();
+           long low = in->readUnsigned ();
+           long high = in->readUnsigned ();
+           sb->appendf (GTXT ("%ld to %ld: default=0x%llx"),
+                   (long) low, (long) high, (long long) (addr + default_skip));
+           for (long i = low; i <= high; ++i)
+             /* u4 i1 = */ in->readUnsigned ();
+           break;
+         }
+       case opc_lookupswitch:
+         {
+           int align = (addr + 1) % 4; // 1 byte is a length of opc_lookupswitch
+           if (align != 0)
+             in->skip (4 - align); // four byte boundry
+           u4 default_skip = in->readUnsigned ();
+           u4 npairs = in->readUnsigned ();
+           sb->appendf (GTXT ("%d: default=0x%llx"), npairs,
+                        (long long) (addr + default_skip));
+           for (int i = 0, nints = npairs * 2; i < nints; i += 2)
+             {
+               /* u4 i1 = */ in->readUnsigned ();
+               /* u4 i2 = */ in->readUnsigned ();
+             }
+           break;
+         }
+       case opc_newarray:
+         switch (in->readByte ())
+           {
+           case T_INT:
+             sb->append (GTXT ("int"));
+             break;
+           case T_LONG:
+             sb->append (GTXT ("long"));
+             break;
+           case T_FLOAT:
+             sb->append (GTXT ("float"));
+             break;
+           case T_DOUBLE:
+             sb->append (GTXT ("double"));
+             break;
+           case T_CHAR:
+             sb->append (GTXT ("char"));
+             break;
+           case T_SHORT:
+             sb->append (GTXT ("short"));
+             break;
+           case T_BYTE:
+             sb->append (GTXT ("byte"));
+             break;
+           case T_BOOLEAN:
+             sb->append (GTXT ("boolean"));
+             break;
+           default:
+             sb->append (GTXT ("BOGUS TYPE"));
+             break;
+           }
+         break;
+       case opc_anewarray:
+         sb->append (GTXT ("class "));
+         printConstant (sb, in->readUnsignedShort ());
+         break;
+       case opc_sipush:
+         sb->append (in->readUnsignedShort ());
+         break;
+       case opc_bipush:
+         sb->append (in->readByte ());
+         break;
+       case opc_ldc:
+         printConstant (sb, in->readByte ());
+         break;
+       case opc_ldc_w: case opc_ldc2_w:
+       case opc_instanceof: case opc_checkcast:
+       case opc_new:
+       case opc_putstatic: case opc_getstatic:
+       case opc_putfield: case opc_getfield:
+       case opc_invokevirtual:
+       case opc_invokespecial:
+       case opc_invokestatic:
+         printConstant (sb, in->readUnsignedShort ());
+         break;
+       case opc_invokeinterface:
+         {
+           u2 index = in->readUnsignedShort ();
+           u1 count = in->readByte ();
+           /* u1 zero = */ in->readByte ();
+           sb->appendf (" #%u, %u) ", (unsigned int) index, (unsigned int) count);
+           printConstant (sb, index);
+           break;
+         }
+       case opc_multianewarray:
+         {
+           u2 index = in->readUnsignedShort ();
+           printConstant (sb, index);
+           sb->appendf (GTXT (" dim #%d "), index);
+           break;
+         }
+       case opc_jsr: case opc_goto:
+       case opc_ifeq: case opc_ifge: case opc_ifgt:
+       case opc_ifle: case opc_iflt: case opc_ifne:
+       case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge:
+       case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmplt:
+       case opc_if_acmpeq: case opc_if_acmpne:
+       case opc_ifnull: case opc_ifnonnull:
+         sb->appendf (NTXT ("0x%llx"), (long long) (addr + (short) in->readUnsignedShort ()));
+         break;
+       case opc_jsr_w:
+       case opc_goto_w:
+         sb->append (addr + (int) in->readUnsigned ());
+         break;
+       default:
+         break;
+       }
+    }
+  return in->get_offset () - offset;
+}
+
+void
+ClassFile::readAttributes (int count)
+{
+  blanksCnt += 4;
+  for (int ax = 0; ax < count; ax++)
+    {
+      u2 attribute_name_index = input->readUnsignedShort ();
+      u4 attribute_length = input->readUnsigned ();
+      char *attribute_name = bcpool->getString (attribute_name_index);
+      if (!attribute_name)
+       {
+         Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c  %2d: attr_name=%3d %-15s len=%4d\n"),
+                  (int) blanksCnt, ' ', (int) (ax + 1),
+                  (int) attribute_name_index, STR (attribute_name), (int) attribute_length);
+         input->skip (attribute_length);
+         continue;
+       }
+
+      if (strcmp (attribute_name, NTXT ("SourceFile")) == 0)
+       {
+         u2 sourcefile_index = input->readUnsignedShort ();
+         source_name = dbe_strdup (bcpool->getString (sourcefile_index));
+         Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c  %2d: attr_name=%3d %-15s len=%4d file_name=%d %s\n"),
+                  (int) blanksCnt, ' ', (int) (ax + 1),
+                  (int) attribute_name_index, STR (attribute_name), (int) attribute_length,
+                  (int) sourcefile_index, STR (source_name));
+       }
+      else if (strcmp (attribute_name, NTXT ("InnerClasses")) == 0)
+       {
+         int niclasses = input->readUnsignedShort ();
+         for (int ix = 0; ix < niclasses; ix++)
+           {
+             u2 inner_class_info_index = input->readUnsignedShort ();
+             u2 outer_class_info_index = input->readUnsignedShort ();
+             u2 inner_name_index = input->readUnsignedShort ();
+             u2 inner_class_access_flags = input->readUnsignedShort ();
+             Dprintf (DUMP_JAVA_CLASS,
+                      NTXT ("%*c  %2d: attr_name=%3d %-15s len=%4d name=%d '%s'\n"
+                            "%*cinner_class_info_index=%d outer_class_info_index=%d flags=%s\n"),
+                      (int) blanksCnt, ' ', (int) (ax + 1),
+                      (int) attribute_name_index, STR (attribute_name), (int) attribute_length,
+                      (int) inner_name_index, STR (bcpool->getString (inner_name_index)),
+                      (int) (blanksCnt + 10), ' ',
+                      (int) inner_class_info_index, (int) outer_class_info_index,
+                      access_flags_to_str (NestedClassAccess, inner_class_access_flags));
+           }
+       }
+      else if (strcmp (attribute_name, NTXT ("Code")) == 0)
+       {
+         u2 max_stack = input->readUnsignedShort ();
+         u2 max_locals = input->readUnsignedShort ();
+         u4 code_length = input->readUnsigned ();
+         if (cur_jmthd)
+           {
+             cur_jmthd->size = code_length;
+             cur_jmthd->img_fname = dbeFile->get_location ();
+             cur_jmthd->img_offset = input->get_offset ();
+           }
+         input->skip (code_length);
+         u2 exception_table_length = input->readUnsignedShort ();
+         input->skip (exception_table_length * (2 + 2 + 2 + 2));
+         Dprintf (DUMP_JAVA_CLASS,
+                  NTXT ("%*c  %2d: attr_name=%3d %-15s len=%4d max_stack=%d max_locals=%d code_length=%d exception_table_length=%d\n"),
+                  (int) blanksCnt, ' ', (int) (ax + 1),
+                  (int) attribute_name_index, STR (attribute_name), (int) attribute_length,
+                  (int) max_stack, (int) max_locals, (int) code_length, (int) exception_table_length);
+         readAttributes (input->readUnsignedShort ());
+       }
+      else if (strcmp (attribute_name, NTXT ("LineNumberTable")) == 0)
+       {
+         int nlines = input->readUnsignedShort ();
+         Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c  %2d: attr_name=%3d %-15s len=%4d nlines=%d\n"),
+                  (int) blanksCnt, ' ', (int) (ax + 1),
+                  (int) attribute_name_index, STR (attribute_name), (int) attribute_length,
+                  (int) nlines);
+         for (int lx = 0; lx < nlines; lx++)
+           {
+             int bci = input->readUnsignedShort ();
+             int lno = input->readUnsignedShort ();
+             Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c  %3d: pc=%4d (0x%04x)   line=%d\n"),
+                      (int) (blanksCnt + 5), ' ', (int) (lx + 1), (int) bci, (int) bci, (int) lno);
+             if (cur_jmthd)
+               byteCodeInfo->append (new ByteCodeInfo (cur_jmthd, bci, lno));
+           }
+       }
+      else
+       {
+         Dprintf (DUMP_JAVA_CLASS, NTXT ("%*c  %2d: attr_name=%3d %-15s len=%4d\n"),
+                  (int) blanksCnt, ' ', (int) (ax + 1),
+                  (int) attribute_name_index, STR (attribute_name),
+                  (int) attribute_length);
+         input->skip (attribute_length);
+       }
+    }
+  blanksCnt -= 4;
+}
+
+int
+ClassFile::readFile ()
+{
+  if (status != AE_NOTREAD)
+    return status;
+  status = AE_OTHER;
+
+  // The ClassFile Structure http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html
+  try
+    {
+      blanksCnt = 4;
+      cur_jmthd = NULL;
+      char *fname = dbeFile->get_location ();
+      openFile (fname);
+      Dprintf (DUMP_JAVA_CLASS, NTXT ("\nClassFile::readFile status=%d %s location=%s\n"),
+              (unsigned int) status, STR (get_name ()), STR (fname));
+      if (status != AE_OK)
+       return status;
+      byteCodeInfo = new Vector<ByteCodeInfo *>(512);
+      bcpool = new BinaryConstantPool (*input);
+      u2 access_flags = input->readUnsignedShort ();
+      Dprintf (DUMP_JAVA_CLASS, NTXT ("\naccess_flags=%s; %s\n"),
+              access_flags_to_str (ClassAccess, access_flags),
+              STR (dbeFile->get_name ()));
+      u2 classNameInd = input->readUnsignedShort ();
+      class_filename = dbe_strdup (bcpool->getString (classNameInd));
+      if (class_filename)
+       {
+         class_name = strdup (class_filename);
+         convertName (class_name);
+       }
+
+      // Get superclass name
+      u2 superClassInd = input->readUnsignedShort ();
+      //char *str = bcpool->getString(superClassInd);
+      //super_name = str ? convertName( str ) : NULL;
+
+      // Read interfaces
+      int interfaces_count = input->readUnsignedShort ();
+      Dprintf (DUMP_JAVA_CLASS,
+              NTXT ("  class_name=%3d %-20s  superClass=%3d %s  interfaces_count=%d\n"),
+              (int) classNameInd, STR (class_name),
+              (int) superClassInd, STR (bcpool->getString (superClassInd)),
+              (int) interfaces_count);
+      for (int i = 0; i < interfaces_count; i++)
+       {
+         u2 index = input->readUnsignedShort ();
+         Dprintf (DUMP_JAVA_CLASS, NTXT ("  %6lld%s"), (long long) index,
+                  (i % 8 == 7) || (i + 1 == interfaces_count) ? "\n" : "");
+       }
+
+      // Read fields
+      int fields_count = input->readUnsignedShort ();
+      Dprintf (DUMP_JAVA_CLASS, NTXT ("  fields_count=%d\n"), fields_count);
+      for (int i = 0; i < fields_count; i++)
+       {
+         u2 fld_access_flags = input->readUnsignedShort ();
+         u2 name_index = input->readUnsignedShort ();
+         u2 descriptor_index = input->readUnsignedShort ();
+         u2 attributes_count = input->readUnsignedShort ();
+         Dprintf (DUMP_JAVA_CLASS,
+                  NTXT ("    %2d: name=%3d %-20s flags=%s; desc_ind=%d attr_count=%d\n"),
+                  i, (int) name_index, STR (bcpool->getString (name_index)),
+                  access_flags_to_str (FieldAccess, fld_access_flags),
+                  (int) descriptor_index, (int) attributes_count);
+         readAttributes (attributes_count);
+       }
+
+      // Read methods
+      int methods_count = input->readUnsignedShort ();
+      Dprintf (DUMP_JAVA_CLASS, NTXT ("\n  methods_count=%d\n"), (int) methods_count);
+      int func_cnt = functions->size ();
+      for (int i = 0; i < methods_count; i++)
+       {
+         u2 mthd_access_flags = input->readUnsignedShort ();
+         u2 name_index = input->readUnsignedShort ();
+         u2 descriptor_index = input->readUnsignedShort ();
+         char *mname = bcpool->getString (name_index);
+         if (mname == NULL)
+           {
+             DataReadException *e1 = new DataReadException (dbe_sprintf (GTXT ("method name[%d] is NULL\n"), i));
+             throw (e1);
+           }
+         char *msign = bcpool->getString (descriptor_index);
+         if (msign == NULL)
+           {
+             DataReadException *e1 = new DataReadException (dbe_sprintf (GTXT ("method signature[%d] is NULL\n"), i));
+             throw (e1);
+           }
+         size_t len = strlen (class_name);
+         cur_jmthd = NULL;
+         for (int idx = 0; idx < func_cnt; idx++)
+           {
+             JMethod *jmthd = (JMethod*) functions->fetch (idx);
+             char *jmt_name = jmthd->get_name (Histable::SHORT);
+             if (strncmp (jmt_name, class_name, len) == 0)
+               {
+                 if (strcmp (jmt_name + len + 1, mname) == 0 &&
+                     strcmp (jmthd->get_signature (), msign) == 0)
+                   {
+                     cur_jmthd = jmthd;
+                     break;
+                   }
+               }
+           }
+         if (cur_jmthd == NULL)
+           {
+             cur_jmthd = dbeSession->createJMethod ();
+             cur_jmthd->module = this;
+             cur_jmthd->set_signature (dbe_strdup (msign));
+             char *nm = dbe_sprintf (NTXT ("%s.%s"), class_name, mname);
+             cur_jmthd->set_name (nm);
+             free (nm);
+             functions->append (cur_jmthd);
+           }
+         if ((mthd_access_flags & ACC_NATIVE) != 0)
+           {
+             cur_jmthd->flags |= FUNC_FLAG_NATIVE;
+           }
+         u2 attributes_count = input->readUnsignedShort ();
+         Dprintf (DUMP_JAVA_CLASS,
+                  NTXT ("    %2d: name=%d %-20s  flags=%s  desc_ind=%d attr_count=%d\n"),
+                  (int) (i + 1), (int) name_index, STR (bcpool->getString (name_index)),
+                  access_flags_to_str (MethodAccess, mthd_access_flags),
+                  (int) descriptor_index, (int) attributes_count);
+         readAttributes (attributes_count);
+         cur_jmthd->popSrcFile ();
+       }
+
+      // Read global attributes
+      u2 global_attributes_count = input->readUnsignedShort ();
+      Dprintf (DUMP_JAVA_CLASS, NTXT ("  global_attributes_count=%d\n"), global_attributes_count);
+      readAttributes (global_attributes_count);
+      status = AE_OK;
+    }
+  catch (DataReadException *ex)
+    {
+      append_msg (CMSG_ERROR, GTXT ("Cannot read class file %s (%s)"), get_name (), ex->toString ());
+      delete ex;
+      status = AE_OTHER;
+    }
+
+  char *fnm = NULL;
+  if (class_filename)
+    {
+      if (strcmp (class_filename, get_name ()) != 0)
+       set_name (strdup (class_filename));
+      if (source_name)
+       {
+         char *bname = strrchr (class_filename, '/');
+         if (bname)
+           fnm = dbe_sprintf (NTXT ("%.*s/%s"), (int) (bname - class_filename),
+                              class_filename, source_name);
+         else
+           fnm = strdup (source_name);
+       }
+      else
+       fnm = get_java_file_name (class_filename, false);
+    }
+  else if (source_name)
+    fnm = strdup (source_name);
+  if (fnm)
+    {
+      set_file_name (fnm);
+      main_source = findSource (file_name, true);
+      main_source->dbeFile->filetype |= DbeFile::F_JAVA_SOURCE;
+    }
+
+  for (long i = 0, sz = VecSize (functions); i < sz; i++)
+    functions->get (i)->def_source = main_source;
+  JMethod *func = NULL;
+  for (long i = 0, sz = VecSize (byteCodeInfo); i < sz; i++)
+    {
+      ByteCodeInfo *p = byteCodeInfo->get (i);
+      if (func != p->func)
+       {
+         if (func)
+           func->popSrcFile ();
+         func = p->func;
+         func->line_first = p->lno;
+         func->pushSrcFile (main_source, 0);
+       }
+      func->line_last = p->lno;
+      func->add_PC_info (p->bci, p->lno, main_source);
+    }
+  if (func)
+    func->popSrcFile ();
+  Destroy (byteCodeInfo);
+  Dprintf (DUMP_JAVA_CLASS, NTXT ("\n status=%d class_filename=%s class_name=%s source_name=%s file_name=%s %s\n"),
+          (unsigned int) status, STR (class_filename), STR (class_name),
+          STR (source_name), STR (file_name),
+          STR (get_name ()));
+  return status;
+}
+
+#define MAX_CLASS_SIZE 65536
+
+char *
+ClassFile::get_disasm (uint64_t inst_address, uint64_t end_address,
+                      uint64_t start_address, uint64_t f_offset, int64_t &inst_size)
+{
+  int64_t offset = f_offset + (inst_address - start_address);
+  if ((cf_buf == NULL) || (inst_address >= end_address) || (offset >= cf_bufsz))
+    {
+      inst_size = 0;
+      return NULL;
+    }
+
+  // Check for an implausibly large size
+  if ((inst_address - start_address) > MAX_CLASS_SIZE)
+    {
+      append_msg (CMSG_ERROR, GTXT ("Cannot disassemble class file %s (%s), implausible size = %lld"),
+                 get_name (), dbeFile->get_location (),
+                 (end_address - start_address));
+      inst_size = 0;
+      return NULL;
+    }
+
+  StringBuilder sb;
+  DataInputStream *in = new DataInputStream (input);
+  try
+    {
+      in->skip (offset);
+      inst_size = printCodeSequence (&sb, inst_address - start_address, in);
+    }
+  catch (DataReadException *ex)
+    {
+      append_msg (CMSG_ERROR, GTXT ("Cannot disassemble class file %s (%s) %s"),
+                 get_name (), dbeFile->get_location (), ex->toString ());
+      delete ex;
+      inst_size = 0;
+    }
+  delete in;
+  if (inst_size == 0)
+    return NULL;
+  return sb.toString ();
+}
+
+char *
+ClassFile::get_java_file_name (char *clname, bool classSuffix)
+{
+  size_t len = strlen (clname);
+  if (len > 6 && streq (clname + len - 6, NTXT (".class")))
+    len -= 6;
+  if (!classSuffix)
+    { // remove $SubClassName from "ClassName$SubClassName"
+      char *tmp = strchr (clname, '$');
+      if (tmp)
+       len = tmp - clname;
+    }
+  char *clpath = (char *) malloc (len + 10);
+  for (size_t i = 0; i < len; i++)
+    clpath[i] = (clname[i] == '.') ? '/' : clname[i];
+  snprintf (clpath + len, 10, classSuffix ? NTXT (".class") : NTXT (".java"));
+  return clpath;
+}
diff --git a/gprofng/src/ClassFile.h b/gprofng/src/ClassFile.h
new file mode 100644 (file)
index 0000000..bd4c61b
--- /dev/null
@@ -0,0 +1,63 @@
+/* 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 _CLASSFILE_H
+#define _CLASSFILE_H
+
+#include "Module.h"
+
+class DataInputStream;
+class BinaryConstantPool;
+class JMethod;
+class StringBuilder;
+class ByteCodeInfo;
+
+class ClassFile : public Module
+{
+public:
+  ClassFile ();
+  virtual ~ClassFile ();
+  virtual int readFile ();
+  virtual char *get_disasm (uint64_t inst_address, uint64_t end_address,
+                           uint64_t start_address, uint64_t f_offset,
+                           int64_t &inst_size);
+  static char *get_java_file_name (char *clname, bool classSuffix);
+
+private:
+
+  void openFile (const char *fname);
+  char *get_opc_name (int op);
+  void readAttributes (int count);
+  void printConstant (StringBuilder *sb, int index);
+  long long printCodeSequence (StringBuilder *sb, uint64_t addr, DataInputStream *in);
+
+  unsigned char *cf_buf;
+  int64_t cf_bufsz;
+  int blanksCnt;
+  DataInputStream *input;
+  BinaryConstantPool *bcpool;
+  JMethod *cur_jmthd;
+  char *class_name;
+  char *class_filename;
+  char *source_name;
+  Vector<ByteCodeInfo *> *byteCodeInfo;
+};
+
+#endif
diff --git a/gprofng/src/Command.cc b/gprofng/src/Command.cc
new file mode 100644 (file)
index 0000000..d1620d7
--- /dev/null
@@ -0,0 +1,562 @@
+/* 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 <string.h>
+#include <stdlib.h>
+#include <sys/param.h>
+
+#include "gp-defs.h"
+#include "Command.h"
+#include "DbeSession.h"
+#include "MemorySpace.h"
+#include "i18n.h"
+#include "StringBuilder.h"
+
+const char *Command::DEFAULT_CMD = "default";   // token for default
+const char *Command::ALL_CMD     = "all";       // token for all
+const char *Command::ANY_CMD     = "any";       // token for any
+const char *Command::NONE_CMD    = "none";      // token for none
+const char *Command::HWC_CMD     = "hwc";       // token for all HWC
+const char *Command::BIT_CMD     = "bit";  // token for any bit-generated metric
+const char *Command::DEFAULT_METRICS = "ei.user:name";  // if no .rc files read
+const char *Command::DEFAULT_SORT    = "e.user:name";   // if no .rc files read
+
+static char *fhdr, *cchdr, *lahdr, *iohdr, *sdhdr, *lsthdr, *lohdr;
+static char *methdr, *othdr, *mischdr, *deflthdr;
+static char *selhdr, *filthdr, *outhdr, *exphdr, *obj_allhdr;
+static char *unsuphdr, *indxobjhdr;
+static char *helphdr, *rahdr, *ddhdr, *typehdr, *typehdr2;
+
+//  This is the list of commands, which governs the parser scan, as
+//     well as the help command.
+//  A line with the tag NO_CMD is skipped in parsing, but is used
+//     to provide subheadings for the help
+//  The HELP line must be the last one in the list of commands
+//     to be shown by "-help"; The HHELP line must be the
+//     last one to be shown by "-xhelp"
+//  The LAST_CMD line must be the last one recognized by the parser
+//
+//  The ordering of this list should match the ordering in the man
+//     page, and the subheader lines should match the subheadings in
+//     the man page.
+
+static char *desc[LAST_CMD];
+
+static Cmdtable cmd_lst[] = {   // list of commands
+  // User Commands
+  { NO_CMD, "", NULL, NULL, 0, &fhdr},
+  { FUNCS, "functions", NULL, NULL, 0, &desc[FUNCS]},
+  { METRICS, "metrics", NULL, "metric_spec", 1, &desc[METRICS]},
+  { SORT, "sort", NULL, "metric_spec", 1, &desc[SORT]},
+  { FDETAIL, "fsummary", NULL, NULL, 0, &desc[FDETAIL]},
+  { FSINGLE, "fsingle", NULL, "function_name #", 2, &desc[FSINGLE]},
+
+  { NO_CMD, "", NULL, NULL, 0, &cchdr},
+  { GPROF, "callers-callees", "gprof", NULL, 0, &desc[GPROF]},
+  { CSINGLE, "csingle", NULL, "function_name #", 2, &desc[CSINGLE]},
+  { CPREPEND, "cprepend", NULL, "function_name #", 2, &desc[CPREPEND]},
+  { CAPPEND, "cappend", NULL, "function_name #", 2, &desc[CAPPEND]},
+  { CRMFIRST, "crmfirst", NULL, NULL, 0, &desc[CRMFIRST]},
+  { CRMLAST, "crmlast", NULL, NULL, 0, &desc[CRMLAST]},
+  { CALLTREE, "calltree", "ctree", NULL, 0, &desc[CALLTREE]},
+
+  { NO_CMD, "", NULL, NULL, 0, &lahdr},
+  { LEAKS, "leaks", NULL, NULL, 0, &desc[LEAKS]},
+  { ALLOCS, "allocs", NULL, NULL, 0, &desc[ALLOCS]},
+  { HEAP, "heap", NULL, NULL, 0, &desc[HEAP]},
+  { HEAPSTAT, "heapstat", NULL, NULL, 0, &desc[HEAPSTAT]},
+
+  { NO_CMD, "", NULL, NULL, 0, &iohdr},
+  { IOACTIVITY, "ioactivity", NULL, NULL, 0, &desc[IOACTIVITY]},
+  { IOVFD, "iodetail", NULL, NULL, 0, &desc[IOVFD]},
+  { IOCALLSTACK, "iocallstack", NULL, NULL, 0, &desc[IOCALLSTACK]},
+  { IOSTAT, "iostat", NULL, NULL, 0, &desc[IOSTAT]},
+
+  // PC, line, source and dissassembly commands
+  { NO_CMD, "", NULL, NULL, 0, &sdhdr},
+  { HOTPCS, "pcs", NULL, NULL, 0, &desc[HOTPCS]},
+  { PDETAIL, "psummary", NULL, NULL, 0, &desc[PDETAIL]},
+  { HOTLINES, "lines", NULL, NULL, 0, &desc[HOTLINES]},
+  { LDETAIL, "lsummary", NULL, NULL, 0, &desc[LDETAIL]},
+  { SOURCE, "source", NULL, "func/file #", 2, &desc[SOURCE]},
+  { DISASM, "disasm", NULL, "func/file #", 2, &desc[DISASM]},
+  { SCOMPCOM, "scc", NULL, "com_spec", 1, &desc[SCOMPCOM]},
+  { STHRESH, "sthresh", NULL, "value", 1, &desc[STHRESH]},
+  { DCOMPCOM, "dcc", NULL, "com_spec", 1, &desc[DCOMPCOM]},
+  { COMPCOM, "cc", NULL, "com_spec", 1, &desc[COMPCOM]},
+  { DTHRESH, "dthresh", NULL, "value", 1, &desc[DTHRESH]},
+  { SETPATH, "setpath", NULL, "path_list", 1, &desc[SETPATH]},
+  { ADDPATH, "addpath", NULL, "path_list", 1, &desc[ADDPATH]},
+  { PATHMAP, "pathmap", NULL, "old_prefix new_prefix", 2, &desc[PATHMAP]},
+  { LIBDIRS, "preload_libdirs", NULL, NULL, 1, &desc[PATHMAP]},
+
+  // Index Object commands
+  { NO_CMD, "", NULL, NULL, 0, &indxobjhdr},
+  { INDXOBJ, "indxobj", NULL, "type", 1, &desc[INDXOBJ]},
+  { INDXOBJLIST, "indxobj_list", NULL, NULL, 0, &desc[INDXOBJLIST]},
+  { INDXOBJDEF, "indxobj_define", NULL, "type \"index-expr\"", 2, &desc[INDXOBJDEF]},
+
+  // Deadlock detection commands
+  { NO_CMD, "", NULL, NULL, 0, &ddhdr},
+  { DEADLOCK_EVNTS, "deadlocks", NULL, NULL, 0, &desc[DEADLOCK_EVNTS]},
+  { DEADLOCK_SUM, "dsummary", NULL, "{deadlock_id|all}", 1, &desc[DEADLOCK_SUM]},
+
+  { NO_CMD, "", NULL, NULL, 0, &lsthdr},
+  { EXP_LIST, "experiment_list", "exp_list", NULL, 0, &desc[EXP_LIST]},
+  { SAMPLE_LIST, "sample_list", NULL, NULL, 0, &desc[SAMPLE_LIST]},
+  { LWP_LIST, "lwp_list", NULL, NULL, 0, &desc[LWP_LIST]},
+  { THREAD_LIST, "thread_list", NULL, NULL, 0, &desc[THREAD_LIST]},
+  { CPU_LIST, "cpu_list", NULL, NULL, 0, &desc[CPU_LIST]},
+
+  { NO_CMD, "", NULL, NULL, 0, &filthdr},
+  { FILTERS, "filters", NULL, "filter-specification", 1, &desc[FILTERS]},
+  { DESCRIBE, "describe", NULL, NULL, 0, &desc[DESCRIBE]},
+
+  { NO_CMD, "", NULL, NULL, 0, &selhdr},
+  { SAMPLE_SELECT, "sample_select", NULL, "sample_spec", 1, &desc[SAMPLE_SELECT]},
+  { LWP_SELECT, "lwp_select", NULL, "lwp_spec", 1, &desc[LWP_SELECT]},
+  { THREAD_SELECT, "thread_select", NULL, "thread_spec", 1, &desc[THREAD_SELECT]},
+  { CPU_SELECT, "cpu_select", NULL, "cpu_spec", 1, &desc[CPU_SELECT]},
+
+  { NO_CMD, "", NULL, NULL, 0, &lohdr},
+  { OBJECT_LIST, "object_list", NULL, NULL, 0, &desc[OBJECT_LIST]},
+  { OBJECT_SHOW, "object_show", NULL, "obj1,...", 1, &desc[OBJECT_SHOW]},
+  { OBJECT_HIDE, "object_hide", NULL, "obj1,...", 1, &desc[OBJECT_HIDE]},
+  { OBJECT_API, "object_api", NULL, "obj1,...", 1, &desc[OBJECT_API]},
+  { DUMMY_CMD, " ", NULL, NULL, 0, &obj_allhdr},
+  { OBJECTS_DEFAULT, "objects_default", NULL, NULL, 1, &desc[OBJECTS_DEFAULT]},
+
+  { OBJECT_SELECT, "object_select", NULL, "obj1,...", 1, &desc[OBJECT_SELECT]},
+
+  { NO_CMD, "", NULL, NULL, 0, &methdr},
+  { METRIC_LIST, "metric_list", NULL, NULL, 0, &desc[METRIC_LIST]},
+  { GMETRIC_LIST, "cmetric_list", "gmetric_list", NULL, 0, &desc[GMETRIC_LIST]},
+  { INDX_METRIC_LIST, "indx_metric_list", NULL, NULL, 1, &desc[INDX_METRIC_LIST]},
+
+  { NO_CMD, "", NULL, NULL, 0, &outhdr},
+  { OUTFILE, "outfile", NULL, "filename", 1, &desc[OUTFILE]},
+  { APPENDFILE, "appendfile", NULL, "filename", 1, &desc[APPENDFILE]},
+  { LIMIT, "limit", NULL, "n", 1, &desc[LIMIT]},
+  { NAMEFMT, "name", NULL, "{long|short|mangled}[:{soname|nosoname}]", 1, &desc[NAMEFMT]},
+  { VIEWMODE, "viewmode", NULL, "{user|expert|machine}", 1, &desc[VIEWMODE]},
+  { COMPARE, "compare", NULL, "{on|off|delta|ratio}", 1, &desc[COMPARE]},
+  { PRINTMODE, "printmode", NULL, "string", 1, &desc[PRINTMODE]},
+
+  { NO_CMD, "", NULL, NULL, 0, &othdr},
+  { HEADER, "header", NULL, "exp_id", 1, &desc[HEADER]},
+  { OBJECTS, "objects", NULL, NULL, 0, &desc[OBJECTS]},
+  { OVERVIEW_NEW, "overview", NULL, NULL, 0, &desc[OVERVIEW_NEW]},
+  { SAMPLE_DETAIL, "sample_detail", NULL, "exp_id", 1, &desc[SAMPLE_DETAIL]},
+  { STATISTICS, "statistics", NULL, "exp_id", 1, &desc[STATISTICS]},
+
+  { NO_CMD, "", NULL, NULL, 0, &exphdr},
+  { OPEN_EXP, "open_exp", NULL, "experiment", 1, &desc[OPEN_EXP]},
+  { ADD_EXP, "add_exp", NULL, "experiment", 1, &desc[ADD_EXP]},
+  { DROP_EXP, "drop_exp", NULL, "experiment", 1, &desc[DROP_EXP]},
+
+  { NO_CMD, "", NULL, NULL, 0, &deflthdr},
+  { DMETRICS, "dmetrics", NULL, "metric_spec", 1, &desc[DMETRICS]},
+  { DSORT, "dsort", NULL, "metric_spec", 1, &desc[DSORT]},
+  { EN_DESC, "en_desc", NULL, "{on|off|=<regex>}", 1, &desc[EN_DESC]},
+
+  { NO_CMD, "", NULL, NULL, 0, &mischdr},
+  { DUMMY_CMD, "<type>", NULL, NULL, 0, &typehdr},
+  { DUMMY_CMD, " ", NULL, NULL, 0, &typehdr2},
+
+  { IFREQ, "ifreq", NULL, NULL, 0, &desc[IFREQ]},
+  { PROCSTATS, "procstats", NULL, NULL, 0, &desc[PROCSTATS]},
+  { SCRIPT, "script", NULL, "file", 1, &desc[SCRIPT]},
+  { VERSION_cmd, "version", NULL, NULL, 0, &desc[VERSION_cmd]},
+  { QUIT, "quit", "exit", NULL, 0, &desc[QUIT]},
+
+  { NO_CMD, "", NULL, NULL, 0, &helphdr},
+  { HELP, "help", NULL, NULL, 0, &desc[HELP]},
+
+  { NO_CMD, "", NULL, NULL, 0, &unsuphdr},
+  { HELP, "-help", NULL, NULL, 0, &desc[HELP]},
+  { DUMPFUNC, "dfuncs", NULL, "string", 1, &desc[DUMPFUNC]},
+  { DUMPDOBJS, "ddobjs", NULL, "string", 1, &desc[DUMPDOBJS]},
+  { DUMPNODES, "dnodes", NULL, NULL, 0, &desc[DUMPNODES]},
+  { DUMPSTACKS, "dstacks", NULL, NULL, 0, &desc[DUMPSTACKS]},
+  { DUMPUNK, "dunkpc", NULL, NULL, 0, &desc[DUMPUNK]},
+  { DUMPMAP, "dmap", NULL, NULL, 0, &desc[DUMPMAP]},
+  { DUMPENTITIES, "dentities", NULL, NULL, 0, &desc[DUMPENTITIES]},
+  { IGNORE_NO_XHWCPROF, "ignore_no_xhwcprof", NULL, NULL, 0, &desc[IGNORE_NO_XHWCPROF]},
+  { IGNORE_FS_WARN, "ignore_fs_warn", NULL, NULL, 0, &desc[IGNORE_FS_WARN]},
+
+  { DUMP_PROFILE, "dprofile", NULL, NULL, 0, &desc[DUMP_PROFILE]},
+  { DUMP_SYNC, "dsync", NULL, NULL, 0, &desc[DUMP_SYNC]},
+  { DUMP_IOTRACE, "diotrace", NULL, NULL, 0, &desc[DUMP_IOTRACE]},
+  { DUMP_HWC, "dhwc", NULL, NULL, 0, &desc[DUMP_HWC]},
+  { DUMP_HEAP, "dheap", NULL, NULL, 0, &desc[DUMP_HEAP]},
+  { RACE_ACCS, "r_accs", NULL, NULL, 0, &desc[RACE_ACCS]},
+
+  { DMPI_FUNCS, "dmpi_funcs", NULL, NULL, 0, &desc[DMPI_FUNCS]},
+  { DMPI_MSGS, "dmpi_msgs", NULL, NULL, 0, &desc[DMPI_MSGS]},
+  { DMPI_EVENTS, "dmpi_events", NULL, NULL, 0, &desc[DMPI_EVENTS]},
+
+  { DMEM, "dmem", NULL, NULL, 1, &desc[DMEM]},
+  { DUMP_GC, "dumpgc", NULL, NULL, 0, &desc[DUMP_GC]},
+  { DKILL, "dkill", NULL, NULL, 2, &desc[DKILL]},
+
+  { QQUIT, "xquit", NULL, NULL, 0, &desc[QQUIT]},
+  // use xquit for memory leak detection in dbe; it's
+  // like quit, but deletes all data loaded
+
+  { HHELP, "xhelp", NULL, NULL, 0, &desc[HHELP]},
+  { WHOAMI, "-whoami", NULL, NULL, 0, &desc[WHOAMI]},
+
+  // these are not recognized at this point
+  { LOADOBJECT, "segments", "pmap", NULL, 0, &desc[LOADOBJECT]},
+  { LOADOBJECT_LIST, "segment_list", NULL, NULL, 0, &desc[LOADOBJECT_LIST]},
+  { LOADOBJECT_SELECT, "segment_select", NULL, "seg1,...", 1, &desc[LOADOBJECT_SELECT]},
+
+  { LAST_CMD, "xxxx", NULL, NULL, 0, NULL}
+};
+
+CmdType
+Command::get_command (char *cmd, int &arg_count, int &cparam)
+{
+  int i;
+  int len = (int) strlen (cmd);
+  bool got = false;
+  CmdType token = UNKNOWN_CMD;
+  arg_count = 0;
+  cparam = -1;
+  if (*cmd == '\0') // - command
+    return STDIN;
+  if (*cmd == '#') // comment
+    return COMMENT;
+  if (strcmp (cmd, "V") == 0 || strcmp (cmd, "-version") == 0)
+    return VERSION_cmd;
+  if (strcmp (cmd, "-help") == 0)
+    return HELP;
+  if (strncmp (cmd, NTXT ("-whoami="), 8) == 0)
+    {
+      cparam = 8;
+      return WHOAMI;
+    }
+
+  if (*cmd == '-')
+    cmd++;
+  for (i = 0;; i++)
+    {
+      if (cmd_lst[i].token == LAST_CMD)
+       break;
+      if (!strncasecmp (cmd, cmd_lst[i].str, len) ||
+         (cmd_lst[i].alt && !strncasecmp (cmd, cmd_lst[i].alt, len)))
+       {
+         // Is it unambiguous?
+         if (!strcasecmp (cmd, cmd_lst[i].str)
+             || (cmd_lst[i].alt && !strcasecmp (cmd, cmd_lst[i].alt)))
+           {
+             // exact, full-length match
+             token = cmd_lst[i].token;
+             arg_count = cmd_lst[i].arg_count;
+             return token;
+           }
+         if (got)
+           return AMBIGUOUS_CMD;
+         got = true;
+         token = cmd_lst[i].token;
+         arg_count = cmd_lst[i].arg_count;
+       }
+    }
+
+  // Did we find it?
+  if (token != UNKNOWN_CMD)
+    return token;
+
+  // See if it's the name of a index object
+  if (dbeSession)
+    {
+      int indxtype = dbeSession->findIndexSpaceByName (cmd);
+      if (indxtype >= 0)
+       {
+         // found it
+         cparam = indxtype;
+         return INDXOBJ;
+       }
+    }
+  return token;
+}
+
+const char *
+Command::get_cmd_str (CmdType type)
+{
+  for (int i = 0;; i++)
+    {
+      if (cmd_lst[i].token == LAST_CMD)
+       break;
+      if (type == cmd_lst[i].token)
+       return cmd_lst[i].str;
+    }
+  return "xxxx";
+}
+
+char *
+Command::get_err_string (Cmd_status err)
+{
+  switch (err)
+    {
+    case CMD_OK:
+      return NULL;
+    case CMD_BAD:
+      return GTXT ("command bad");
+    case CMD_AMBIGUOUS:
+      return GTXT ("command ambiguous");
+    case CMD_BAD_ARG:
+      return GTXT ("Invalid argument to command");
+    case CMD_OUTRANGE:
+      return GTXT ("argument to command is out-of-range");
+    case CMD_INVALID:
+      return GTXT ("invalid command");
+    }
+  return NULL;
+}
+
+void
+Command::print_help (char *prog_name, bool cmd_line, bool usermode, FILE *outf)
+{
+  char *fmt, *msg;
+  int i;
+  StringBuilder sb;
+  enum CmdType nc;
+  init_desc ();
+  if (usermode)  // show the hidden ones, too
+    nc = HELP;
+  else
+    nc = HHELP;
+
+  if (cmd_line)
+    fprintf (outf, GTXT ("Usage: %s [ -script script | -command | - ] exper_1 ... exper_n\n"),
+            prog_name);
+  fprintf (outf, GTXT ("An alternate spelling for a command is shown in [], where applicable.\n\n"
+         "Those commands followed by a * may appear in .rc files.\n\n"
+         "Those commands followed by a $ can only appear in .rc files.\n\n"));
+  fmt = fmt_help (nc, ' ');
+  for (i = 0;; i++)
+    {
+      // check for end of list
+      if (cmd_lst[i].token == LAST_CMD)
+       break;
+      if (cmd_lst[i].token == NO_CMD)   // this is a header line
+       fprintf (outf, NTXT (" %s\n"), *cmd_lst[i].desc);
+      else
+       {
+         if (strlen (cmd_lst[i].str) == 0)
+           continue;
+         // this is a real command line
+         sb.setLength (0);
+         sb.append (cmd_lst[i].str);
+         if (cmd_lst[i].alt)
+           {
+             sb.append ('[');
+             sb.append (cmd_lst[i].alt);
+             sb.append (']');
+           }
+         if (cmd_lst[i].arg)
+           {
+             sb.append (' ');
+             sb.append (cmd_lst[i].arg);
+           }
+         msg = sb.toString ();
+         fprintf (outf, fmt, msg, *cmd_lst[i].desc);
+         free (msg);
+       }
+      // check for end of list
+      if (cmd_lst[i].token == nc)
+       break;
+    }
+}
+
+//  construct format for printing help
+char *
+Command::fmt_help (int nc, char head)
+{
+  int len, max_len, i;
+  static char fmt[BUFSIZ];
+
+  max_len = 0;
+  for (i = 0; i < nc; i++)
+    {
+      len = (int) strlen (cmd_lst[i].str);
+      if (cmd_lst[i].alt)
+       len += (int) strlen (cmd_lst[i].alt) + 2;
+      if (cmd_lst[i].arg)
+       len += (int) strlen (cmd_lst[i].arg) + 2;
+      if (max_len < len)
+       max_len = len;
+    }
+  snprintf (fmt, sizeof (fmt), NTXT ("    %c%%-%ds %%s\n"), head, max_len + 1);
+  return fmt;
+}
+
+void
+Command::init_desc ()
+{
+  if (desc[0] != NULL)
+    return;
+  desc[FUNCS] = GTXT ("display functions with current metrics");
+  desc[HOTPCS] = GTXT ("display hot PC's with current metrics");
+  desc[HOTLINES] = GTXT ("display hot lines with current metrics");
+  desc[FDETAIL] = GTXT ("display summary metrics for each function");
+  desc[OBJECTS] = GTXT ("display object list with errors or warnings");
+  desc[COMPARE] = GTXT ("enable comparison mode for experiments *");
+  desc[PRINTMODE] = GTXT ("set the mode for printing tables *");
+  desc[LDETAIL] = GTXT ("display summary metrics for each hot line");
+  desc[PDETAIL] = GTXT ("display summary metrics for each hot PC");
+  desc[SOURCE] = GTXT ("display annotated source for function/file");
+  desc[DISASM] = GTXT ("display annotated disassembly for function/file");
+  desc[SCOMPCOM] = GTXT ("set compiler commentary classes for source *");
+  desc[STHRESH] = GTXT ("set highlight threshold for source *");
+  desc[DCOMPCOM] = GTXT ("set compiler commentary classes for disasm *");
+  desc[COMPCOM] = GTXT ("set compiler commentary classes for both source and disasm *");
+  desc[DTHRESH] = GTXT ("set highlight threshold for disasm *");
+  desc[METRIC_LIST] = GTXT ("display the available metrics and dmetrics keywords");
+  desc[METRICS] = GTXT ("set a new list of metrics");
+  desc[SORT] = GTXT ("sort tables by the specified metric");
+  desc[GPROF] = GTXT ("display the callers-callees for each function");
+  desc[CALLTREE] = GTXT ("display the tree of function calls");
+  desc[CALLFLAME] = GTXT ("request calltree flame chart -- not a command, but used in the tabs command");
+  desc[GMETRIC_LIST] = GTXT ("display the available callers-callees metrics");
+  desc[FSINGLE] = GTXT ("display the summary metrics for specified function");
+  desc[CSINGLE] = GTXT ("display the callers-callees for the specified function");
+  desc[CPREPEND] = GTXT ("add specified function to the head of the callstack fragment");
+  desc[CAPPEND] = GTXT ("add specified function to the end of the callstack fragment");
+  desc[CRMFIRST] = GTXT ("remove the first function from the callstack fragment");
+  desc[CRMLAST] = GTXT ("remove the last function from the callstack fragment");
+  desc[LEAKS] = GTXT ("display memory leaks, aggregated by callstack");
+  desc[ALLOCS] = GTXT ("display allocations, aggregated by callstack");
+  desc[HEAP] = GTXT ("display memory allocations and leaks, aggregated by callstack");
+  desc[HEAPSTAT] = GTXT ("display heap statistics report");
+  desc[IOACTIVITY] = GTXT ("display I/O activity report, aggregated by file name");
+  desc[IOVFD] = GTXT ("display I/O activity report, aggregated by file descriptor");
+  desc[IOCALLSTACK] = GTXT ("display I/O activity report, aggregated by callstack");
+  desc[IOSTAT] = GTXT ("display I/O statistics report");
+  desc[RACE_ACCS] = GTXT ("dump race access events");
+  desc[DMPI_MSGS] = GTXT ("dump mpi messages");
+  desc[DMPI_FUNCS] = GTXT ("dump mpi function calls");
+  desc[DMPI_EVENTS] = GTXT ("dump mpi trace events");
+  desc[DMEM] = GTXT ("debug command for internal use");
+  desc[DUMP_GC] = GTXT ("dump Java garbage collector events");
+  desc[DKILL] = GTXT ("send process p signal s");
+  desc[DEADLOCK_EVNTS] = GTXT ("display deadlock events");
+  desc[DEADLOCK_SUM] = GTXT ("display summary for the deadlock event");
+  desc[HEADER] = GTXT ("display information about the experiment");
+  desc[OVERVIEW_NEW] = GTXT ("display the overview of all loaded experiments");
+  desc[SAMPLE_DETAIL] = GTXT ("display the current sample list with data");
+  desc[STATISTICS] = GTXT ("display the execution statistics data");
+  desc[EXP_LIST] = GTXT ("display the existing experiments");
+  desc[DESCRIBE] = GTXT ("describe recorded data and tokens available for filtering data");
+  desc[OBJECT_SHOW] = GTXT ("set load objects to show all functions *");
+  desc[OBJECT_HIDE] = GTXT ("set load objects to hide functions *");
+  desc[OBJECT_API] = GTXT ("set load objects to show API (entry point) only *");
+  desc[OBJECTS_DEFAULT] = GTXT ("reset load objects show to defaults");
+  desc[OBJECT_LIST] = GTXT ("display load objects, functions-shown flag");
+  desc[OBJECT_SELECT] = GTXT ("set list of load objects whose functions are shown");
+  desc[SAMPLE_LIST] = GTXT ("display the list of existing samples");
+  desc[SAMPLE_SELECT] = GTXT ("set a new list of samples");
+  desc[THREAD_LIST] = GTXT ("display the list of existing threads");
+  desc[THREAD_SELECT] = GTXT ("set a new list of threads");
+  desc[LWP_LIST] = GTXT ("display the list of existing LWPs");
+  desc[LWP_SELECT] = GTXT ("set a new list of LWPs");
+  desc[CPU_LIST] = GTXT ("display the list of CPUs");
+  desc[CPU_SELECT] = GTXT ("set a new list of CPUs");
+  desc[OUTFILE] = GTXT ("open filename for subsequent output");
+  desc[APPENDFILE] = GTXT ("open filename for subsequent appended output");
+  desc[LIMIT] = GTXT ("limit output to the first n entries (n=0 for no limit)");
+  desc[NAMEFMT] = GTXT ("set long/short/mangled names for functions *");
+  desc[VIEWMODE] = GTXT ("set viewmode user|expert|machine *");
+  desc[EN_DESC] = GTXT ("enable descendant processes on|off|regex matches lineage or program name $");
+  desc[SETPATH] = GTXT ("set search path for annotated src/dis");
+  desc[ADDPATH] = GTXT ("add search path for annotated src/dis *");
+  desc[PATHMAP] = GTXT ("remap path prefix for annotated src/dis *");
+  desc[LIBDIRS] = GTXT ("set path where the gprofng libraries are installed");
+  desc[SCRIPT] = GTXT ("read er_print commands from script file");
+  desc[PROCSTATS] = GTXT ("display processing statistics");
+  desc[ADD_EXP] = GTXT ("add experiment or group");
+  desc[DROP_EXP] = GTXT ("drop experiment");
+  desc[OPEN_EXP] = GTXT ("open experiment or group (drops all loaded experiments first)");
+  desc[VERSION_cmd] = GTXT ("display the current release version");
+  desc[HELP] = GTXT ("display the list of available commands");
+  desc[QUIT] = GTXT ("terminate processing and exit");
+  desc[DMETRICS] = GTXT ("set default function list metrics $");
+  desc[DSORT] = GTXT ("set default function list sort metric $");
+  desc[TLMODE] = GTXT ("set default timeline mode, align, depth $");
+  desc[TLDATA] = GTXT ("set default timeline visible data $");
+  desc[TABS] = GTXT ("set default visible tabs $");
+  desc[RTABS] = GTXT ("set default visible tabs for Thread Analyzer Experiment $");
+  desc[INDXOBJ] = GTXT ("display index objects of a specified type with current metrics");
+  desc[INDXOBJLIST] = GTXT ("display list of index objects");
+  desc[INDXOBJDEF] = GTXT ("define a new index object type *");
+  desc[INDX_METRIC_LIST] = GTXT ("display the available index object metrics");
+  desc[IFREQ] = GTXT ("display instruction-frequency report");
+  desc[TIMELINE] = GTXT ("request timeline -- not a command, but used in the tabs command");
+  desc[MPI_TIMELINE] = GTXT ("request mpi-timeline -- not a command, but used in the tabs command");
+  desc[MPI_CHART] = GTXT ("request mpi chart -- not a command, but used in the tabs command");
+  desc[DUALSOURCE] = GTXT ("request dualsource tab -- not a command, but used in the tabs command");
+  desc[SOURCEDISAM] = GTXT ("request source/disassembly tab -- not a command, but used in the tabs command");
+  desc[DUMPNODES] = GTXT ("dump pathtree node table");
+  desc[DUMPSTACKS] = GTXT ("dump Experiment callstack tables");
+  desc[DUMPUNK] = GTXT ("dump <Unknown> PCs");
+  desc[DUMPFUNC] = GTXT ("dump functions whose name matches string");
+  desc[DUMPDOBJS] = GTXT ("dump dataobjects whose name matches string");
+  desc[DUMPMAP] = GTXT ("dump load-object map");
+  desc[DUMPENTITIES] = GTXT ("dump threads, lwps, cpus");
+  desc[DUMP_PROFILE] = GTXT ("dump clock profile events");
+  desc[DUMP_SYNC] = GTXT ("dump synchronization trace events");
+  desc[DUMP_IOTRACE] = GTXT ("dump IO trace events");
+  desc[DUMP_HWC] = GTXT ("dump HWC profile events");
+  desc[DUMP_HEAP] = GTXT ("dump heap trace events");
+  desc[IGNORE_NO_XHWCPROF] = GTXT ("ignore absence of -xhwcprof info in dataspace profiling $");
+  desc[IGNORE_FS_WARN] = GTXT ("ignore filesystem (nfs, ...) warning $");
+  desc[HHELP] = GTXT ("display help including unsupported commands");
+  desc[QQUIT] = GTXT ("terminate processing and exit");
+  desc[LOADOBJECT] = GTXT ("display the address map with current metrics");
+  desc[LOADOBJECT_LIST] = GTXT ("display segments, indicating which are selected");
+  desc[LOADOBJECT_SELECT] = GTXT ("set a new list of segments");
+  desc[FILTERS] = GTXT ("define a filter");
+
+  fhdr = GTXT ("\nCommands controlling the function list:");
+  cchdr = GTXT ("\nCommands controlling the callers-callees and calltree lists:");
+  lahdr = GTXT ("\nCommands controlling the leak and allocation lists:");
+  iohdr = GTXT ("\nCommand controlling the I/O activity report:");
+  rahdr = GTXT ("\nCommands controlling the race events lists:");
+  ddhdr = GTXT ("\nCommands controlling the deadlock events lists:");
+  typehdr = GTXT ("equivalent to \"memobj type\", or \"indxobj type\"");
+  typehdr2 = GTXT ("  where type is a memory object or index object type");
+  sdhdr = GTXT ("\nCommands controlling the source and disassembly listings:");
+  lsthdr = GTXT ("\nCommands listing experiments, samples and threads:");
+  lohdr = GTXT ("\nCommands controlling load object selection:");
+  obj_allhdr = GTXT ("  the special object name `all' refers to all load objects");
+  methdr = GTXT ("\nCommands that list metrics:");
+  othdr = GTXT ("\nCommands that print other displays:");
+  outhdr = GTXT ("\nCommands that control output:");
+  mischdr = GTXT ("\nMiscellaneous commands:");
+  exphdr = GTXT ("\nCommands for experiments (scripts and interactive mode only):");
+  deflthdr = GTXT ("\nDefault-setting commands:");
+  selhdr = GTXT ("\nCommands controlling old-style filters/selection:");
+  filthdr = GTXT ("\nCommands controlling filters:");
+  indxobjhdr = GTXT ("\nCommands controlling the index objects:");
+  unsuphdr = GTXT ("\nUnsupported commands:");
+  helphdr = GTXT ("\nHelp command:");
+}
diff --git a/gprofng/src/Command.h b/gprofng/src/Command.h
new file mode 100644 (file)
index 0000000..4dd28ad
--- /dev/null
@@ -0,0 +1,286 @@
+/* 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 _COMMAND_H
+#define _COMMAND_H
+
+
+#include <stdio.h>
+#include <sys/types.h>
+
+#include "Metric.h"
+#include "Hist_data.h"
+#include "dbe_types.h"
+#include "vec.h"
+#include "enums.h"
+
+// This enum lists all the commands parsed by er_print
+//  The ordering here is not important, but LAST_CMD must
+//  be defined as the last command for which a help line will exist
+//  Command.cc has a matching list, and the ordering in
+//  that list determines what shows up under the help and xhelp commands.
+//  In particular, the entry for HELP is the last one printed
+//  for the help command, and the entry for HHELP is the last
+//  one printed for xhelp.
+
+enum CmdType
+{
+  // Pathtree-related commands
+  FUNCS = 0,
+  HOTPCS,
+  HOTLINES,
+  FDETAIL,
+  OBJECTS,
+  LDETAIL,
+  PDETAIL,
+  SOURCE,
+  DISASM,
+  METRIC_LIST,
+  METRICS,
+  SORT,
+  GPROF,
+  GMETRIC_LIST,
+  FSINGLE,
+  CSINGLE,
+  CPREPEND,
+  CAPPEND,
+  CRMFIRST,
+  CRMLAST,
+  CALLTREE,
+  CALLFLAME,
+
+  // Source/disassembly control commands
+  SCOMPCOM,
+  STHRESH,
+  DCOMPCOM,
+  COMPCOM,
+  DTHRESH,
+
+  // Heap trace-related commands
+  LEAKS,
+  ALLOCS,
+  HEAP,
+  HEAPSTAT,
+
+  // I/O trace-related commands
+  IOACTIVITY,
+  IOVFD,
+  IOCALLSTACK,
+  IOSTAT,
+
+  // Race detection related commands
+  RACE_EVNTS,
+  RACE_SUM,
+
+  // Deadlock detection commands
+  DEADLOCK_EVNTS,
+  DEADLOCK_SUM,
+
+  // DataSpace commands
+  DOBJECTS,
+  DO_SINGLE,
+  DO_LAYOUT,
+  DO_METRIC_LIST,
+
+  // MemorySpace commands
+  MEMOBJ,
+  MEMOBJLIST,
+  MEMOBJDEF,
+  MEMOBJDROP,
+  MACHINEMODEL,
+
+  // Custom tab commands
+  INDXOBJDEF,
+  INDXOBJLIST,
+  INDXOBJ,
+  INDX_METRIC_LIST,
+
+  // Old-style filtering commands
+  OBJECT_LIST,
+  OBJECT_SELECT,
+  SAMPLE_LIST,
+  SAMPLE_SELECT,
+  THREAD_LIST,
+  THREAD_SELECT,
+  LWP_LIST,
+  LWP_SELECT,
+  CPU_LIST,
+  CPU_SELECT,
+
+  // Shared Object display commands
+  OBJECT_SHOW,
+  OBJECT_HIDE,
+  OBJECT_API,
+  OBJECTS_DEFAULT,
+
+  // the new filtering commands
+  FILTERS,
+
+  // Miscellaneous commands
+  COMPARE,
+  PRINTMODE,
+  HEADER,
+  OVERVIEW_NEW,
+  SAMPLE_DETAIL,
+  STATISTICS,
+  EXP_LIST,
+  DESCRIBE,
+  OUTFILE,
+  APPENDFILE,
+  LIMIT,
+  NAMEFMT,
+  VIEWMODE,
+  EN_DESC,
+  SETPATH,
+  ADDPATH,
+  PATHMAP,
+  LIBDIRS,
+  SCRIPT,
+  VERSION_cmd,
+  QUIT,
+  PROCSTATS,
+
+  // Experiments handling commands
+  ADD_EXP,
+  DROP_EXP,
+  OPEN_EXP,
+
+  // .rc-only Commands
+  DMETRICS,
+  DSORT,
+  TLMODE,
+  TLDATA,
+  TABS,
+  TIMELINE,
+  MPI_TIMELINE,
+  MPI_CHART,
+  TIMELINE_CLASSIC_TBR,
+  SOURCE_V2,
+  DISASM_V2,
+  RTABS,
+  DUALSOURCE,
+  SOURCEDISAM,
+
+  HELP,             // this is the last of the commands listed with "help"
+  IFREQ,
+  DUMPNODES,
+  DUMPSTACKS,
+  DUMPUNK,
+  DUMPFUNC,
+  DUMPDOBJS,
+  DUMPMAP,
+  DUMPENTITIES,
+  DUMP_PROFILE,
+  DUMP_SYNC,
+  DUMP_HWC,
+  DUMP_HEAP,
+  DUMP_IOTRACE,
+  RACE_ACCS,
+  DMPI_FUNCS,
+  DMPI_MSGS,
+  DMPI_EVENTS,
+  DMEM,
+  DUMP_GC,
+  DKILL,
+  IGNORE_NO_XHWCPROF,
+  IGNORE_FS_WARN,
+  QQUIT,
+  HHELP,            // this is the last command listed with "xhelp"
+  NO_CMD,           // Dummy command, used for headers in help
+  DUMMY_CMD,        // Dummy command, used for help
+
+  // unused commands
+  LOADOBJECT,
+  LOADOBJECT_LIST,
+  LOADOBJECT_SELECT,
+
+  // Internal-only Commands
+  LAST_CMD,         // No more commands for which a help line is possible
+  STDIN,
+  COMMENT,
+  WHOAMI,
+
+  // Error return "commands"
+  AMBIGUOUS_CMD,
+  UNKNOWN_CMD
+};
+
+typedef struct
+{
+  const CmdType token;      // command key
+  const char *str;          // command string
+  const char *alt;          // alternate command string
+  const char *arg;          // argument string for help
+  const int arg_count;      // no. of arguments
+  char **desc;              // description for help
+} Cmdtable;
+
+// Command class: never instantiated, completely static
+class Command
+{
+public:
+
+  // look up a string in the command table, return type, set number of args
+  static CmdType get_command (char *cmd, int &arg_count, int &param);
+  static const char *get_cmd_str (CmdType type);
+  static void print_help (char *prog_name, bool cmd_line, bool usermode, FILE *outf);
+  static char *get_err_string (Cmd_status err);
+
+  static const char *DEFAULT_METRICS;   // default if no .rc files read
+  static const char *DEFAULT_SORT;      // default if no .rc files read
+  static const char *DEFAULT_CMD;       // token for default
+  static const char *ALL_CMD;           // token for all
+  static const char *ANY_CMD;           // token for any
+  static const char *NONE_CMD;          // token for none
+  static const char *HWC_CMD;           // token for all HWC
+  static const char *BIT_CMD;           // token for any bit-derived metric
+
+private:
+  static const int user_no;             // the last user command
+  static const int hidden_no;           // the last hidden command
+  static const int command_no;          // the last parsable command
+
+  static void init_desc ();
+  static char *fmt_help (int nc, char head);
+};
+
+// Analyzer display tabs
+struct DispTab
+{
+  DispTab (int ntype, int num, bool vis, CmdType token)
+  {
+    type = ntype;
+    order = num;
+    visible = vis;
+    available = true;
+    cmdtoken = token;
+  }
+
+  void setAvailability (bool val)       { available = val; }
+
+  int type;             // Display type
+  int order;            // Order in which tabs should appear in GUI
+  bool visible;         // Is Tab visible
+  bool available;       // Is tab available for this experiment
+  CmdType cmdtoken;     // command token
+  int param;            // command parameter (used for memory space)
+};
+
+#endif /* ! _COMMAND_H */
diff --git a/gprofng/src/CompCom.cc b/gprofng/src/CompCom.cc
new file mode 100644 (file)
index 0000000..3a035a9
--- /dev/null
@@ -0,0 +1,313 @@
+/* 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <sys/param.h>
+
+#include "demangle.h"
+#include "gp-defs.h"
+#include "StringBuilder.h"
+#include "CompCom.h"
+#include "Elf.h"
+#include "util.h"
+#include "i18n.h"
+#include "comp_com.c"
+
+CompComment::CompComment (Elf *_elf, int _compcom)
+{
+  elf = _elf;
+  compcom = _compcom;
+  elf_cls = elf->elf_getclass ();
+}
+
+CompComment::~CompComment () { }
+
+int
+CompComment::get_align (int64_t offset, int align)
+{
+  int val = (int) (offset % align);
+  if (val)
+    val = align - val;
+  return val;
+}
+
+/*
+ * Preprocesses the header structure, builds a table of messages with the line
+ * numbers, PCoffsets, original index, and compmsg pointer for each message.
+ * If the show_bits field is not in the message, this routine would fill it in
+ * from the mapping from COMPMSG_ID
+ */
+int
+CompComment::compcom_open (CheckSrcName check_src)
+{
+  if (check_src == NULL)
+    return 0;
+  Elf_Data *data = elf->elf_getdata (compcom);
+  uint64_t b_offset = data->d_off;
+  if (get_align (b_offset, 4))   // not align 4
+    return 0;
+  char *CommData = (char *) data->d_buf;
+  uint64_t offset = b_offset;
+  for (uint64_t e_offset = b_offset + data->d_size; offset < e_offset;)
+    {
+      offset += get_align (offset, (int) data->d_align);
+      if (offset >= e_offset)
+       return 0;
+      compcomhdr *hdr = (compcomhdr *) (CommData + (offset - b_offset));
+      int hdr_msgcount = elf->decode (hdr->msgcount);
+      int hdr_srcname = elf->decode (hdr->srcname);
+      int hdr_stringlen = elf->decode (hdr->stringlen);
+      int hdr_paramcount = elf->decode (hdr->paramcount);
+      size_t length = sizeof (compcomhdr) + hdr_msgcount * sizeof (compmsg) +
+             hdr_paramcount * sizeof (int32_t);
+      if (offset + length + hdr_stringlen > e_offset || hdr_srcname < 0
+         || hdr_srcname >= hdr_stringlen)
+       return 0;
+
+      // check source file
+      char *src_name = (char *) (((char*) hdr) + length + hdr_srcname);
+      if (check_src (src_name))
+       {
+         msgs = (compmsg *) (((char *) hdr) + sizeof (compcomhdr));
+         params = (int32_t *) ((char *) msgs + hdr_msgcount * sizeof (compmsg));
+         strs = (char *) ((char *) params + hdr_paramcount * sizeof (int32_t));
+
+         // initialize the I18N/L10N strings & set the visible table
+         ccm_vis_init ();
+         return hdr_msgcount;
+       }
+      offset += (length + hdr_stringlen);
+    }
+  return 0;
+}
+
+char *
+CompComment::get_demangle_name (char *fname)
+{
+  if (*fname == '_')
+    return cplus_demangle (fname, DMGL_PARAMS);
+  return NULL;
+}
+
+/*
+ * takes the message, and returns the I18N string for the message.
+ */
+char *
+CompComment::compcom_format (int index, compmsg *msg, int &visible)
+{
+  compmsg *p = msgs + index;
+  msg->instaddr = elf->decode (p->instaddr);
+  msg->lineno = elf->decode (p->lineno);
+  msg->msg_type = elf->decode (p->msg_type);
+  msg->nparam = elf->decode (p->nparam);
+  msg->param_index = elf->decode (p->param_index);
+
+  int vindex = ccm_vis_index (msg->msg_type);
+  char *mbuf;
+  Ccm_Primtype_t prim_ty;
+  visible = ccm_attrs[vindex].vis;
+  if (ccm_attrs[vindex].msg == NULL)
+    {
+      /* Print CCM_UNKNOWN message */
+      int uindex = ccm_vis_index (CCM_UNKNOWN);
+      visible = ccm_attrs[uindex].vis;
+      return dbe_sprintf (ccm_attrs[uindex].msg, vindex);
+    }
+
+  /*
+   * Construct the output buffer based on the primitive types of the
+   * message parameters.
+   *
+   * Parameter lists have to be handled carefully -- the 1 parameter
+   * is built up of all the elements separated by ", ".
+   *
+   * Old way: Case by message format string.
+   */
+  int *ind = params + msg->param_index;
+  int plist_idx = ccm_paramlist_index (msg->msg_type);
+  if (plist_idx <= 0)
+    {
+      /* No parameter list to handle; 0 parameters case is handled */
+
+      enum
+      {
+       MAX_COMPCOM_ARGS = 13
+      };
+      char *parms[MAX_COMPCOM_ARGS];
+      if (msg->nparam >= MAX_COMPCOM_ARGS)
+       {
+         fprintf (stderr,
+                  GTXT ("Warning: improperly formatted compiler commentary message (%d parameters >= %d);\n  please report this bug against the compiler\n"),
+                  msg->nparam, MAX_COMPCOM_ARGS);
+         return NULL;
+       }
+      for (int i = 0; i < MAX_COMPCOM_ARGS; i++)
+       parms[i] = NULL; // initialize array
+      int prm_cnt = ccm_num_params (msg->msg_type);
+      if (prm_cnt != msg->nparam)
+       {
+         fprintf (stderr,
+                  GTXT ("Warning, improperly formatted compiler commentary message (parameter count mismatch = %d, param# = %d, msg_type = %x, `%s');\n  please report this bug against the compiler\n"),
+                  prm_cnt, msg->nparam, msg->msg_type, ccm_attrs[vindex].msg);
+         return NULL;
+       }
+      for (int i = 0; i < msg->nparam; i++)
+       {
+         /* Parameters in message-type numbered from '1' */
+         prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
+         if (prim_ty == CCM_PRIMTYPE_INTEGER)
+           {
+             unsigned long v = elf->decode (ind[i]);
+             parms[i] = (char*) v;
+           }
+         else if (prim_ty == CCM_PRIMTYPE_STRING)
+           {
+             char *fname = strs + elf->decode (ind[i]);
+             char *demName = get_demangle_name (fname);
+             parms[i] = demName ? demName : dbe_strdup (fname);
+           }
+         else if (prim_ty == CCM_PRIMTYPE_HEXSTRING)
+           parms[i] = dbe_sprintf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"),
+                                   (unsigned long long) msg->instaddr);
+         else
+           {
+             fprintf (stderr,
+                      GTXT ("Warning, improperly formatted compiler commentary message (unexpected primitive type %d);\n  please report this bug against the compiler\n"),
+                      prim_ty);
+             // Dummy code to avoid compiler's warning: static function ccm_param_hightype is not used
+             Ccm_Hitype_t hightype = CCM_HITYPE_NONE;
+             if (hightype != CCM_HITYPE_NONE)
+               hightype = ccm_param_hightype (msg->msg_type, i + 1);
+             return NULL;
+           }
+       }
+
+      /*
+       * Must make sure to pass _ALL_ params; may pass more because
+       * the format won't access the 'extra' parameters if all the
+       * rules for messages have been followed.
+       */
+      mbuf = dbe_sprintf (ccm_attrs[vindex].msg, parms[0], parms[1], parms[2],
+                         parms[3], parms[4], parms[5], parms[6], parms[7],
+                         parms[8], parms[9], parms[10], parms[11]);
+      // Cleanup allocated memory.
+      for (int i = 0; i < msg->nparam; i++)
+       {
+         prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
+         if (prim_ty == CCM_PRIMTYPE_STRING || prim_ty == CCM_PRIMTYPE_HEXSTRING)
+           free (parms[i]);
+       }
+    }
+  else
+    {
+      /*
+       * Parameter list messages never have 0 parameters; the
+       * primitive type for the parameter list elements is always
+       * the same.  And as of 22-Sep-2006, it was always
+       * CCM_PRIMTYPE_STRING.
+       *
+       * Account for different bases of parameter indices and
+       * 'nparam' count (1 and 0, respectively).
+       */
+      char *parms[3];
+      if (plist_idx > (int) ((sizeof (parms) / sizeof (char*))))
+       {
+         fprintf (stderr,
+                  GTXT ("Warning: improperly formatted compiler commentary message (msg->nparam=%d plist_idx=%d);\n  please report this bug against the compiler\n"),
+                  msg->nparam, plist_idx);
+         return NULL;
+       }
+      for (size_t i = 0; i < (sizeof (parms) / sizeof (char*)); i++)
+       parms[i] = NULL; // initialize array
+
+      StringBuilder sb;
+      prim_ty = ccm_param_primtype (msg->msg_type, plist_idx);
+      for (int i = plist_idx - 1; i < msg->nparam; i++)
+       {
+         if (i != plist_idx - 1)
+           sb.append (GTXT (", "));
+         if (prim_ty == CCM_PRIMTYPE_INTEGER)
+           sb.append (elf->decode (ind[i]));
+         else if (prim_ty == CCM_PRIMTYPE_STRING)
+           {
+             char *fname = strs + elf->decode (ind[i]);
+             char *demName = get_demangle_name (fname);
+             if (demName)
+               {
+                 sb.append (demName);
+                 delete demName;
+               }
+             else
+               sb.append (fname);
+           }
+         else if (prim_ty == CCM_PRIMTYPE_HEXSTRING)
+           sb.appendf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"),
+                       (unsigned long long) msg->instaddr);
+       }
+      parms[plist_idx - 1] = sb.toString ();
+
+      for (int i = 0; i < plist_idx - 1; i++)
+       {
+         prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
+         if (prim_ty == CCM_PRIMTYPE_INTEGER)
+           {
+             unsigned long v = elf->decode (ind[i]);
+             parms[i] = (char*) v;
+           }
+         else if (prim_ty == CCM_PRIMTYPE_STRING)
+           {
+             char *fname = strs + elf->decode (ind[i]);
+             char *demName = get_demangle_name (fname);
+             parms[i] = demName ? demName : dbe_strdup (fname);
+           }
+         else if (prim_ty == CCM_PRIMTYPE_HEXSTRING)
+           parms[i] = dbe_sprintf (elf_cls == ELFCLASS32 ? NTXT ("0x%08llx") : NTXT ("0x%016llx"),
+                                   (unsigned long long) msg->instaddr);
+         else
+           {
+             fprintf (stderr,
+                      GTXT ("Warning, improperly formatted compiler commentary message (unexpected primitive type %d);\n  please report this bug against the compiler\n"),
+                      prim_ty);
+             return NULL;
+           }
+       }
+
+      /*
+       * We have reduced the parameter list to a single string (as
+       * the printf format specifier requires), so only have
+       * 'plist_idx' parameters.
+       */
+      mbuf = dbe_sprintf (ccm_attrs[vindex].msg, parms[0], parms[1], parms[2]);
+
+      // Cleanup allocated memory.
+      free (parms[plist_idx - 1]);
+      for (int i = 0; i < plist_idx - 1; i++)
+       {
+         prim_ty = ccm_param_primtype (msg->msg_type, i + 1);
+         if (prim_ty == CCM_PRIMTYPE_STRING || prim_ty == CCM_PRIMTYPE_STRING)
+           free (parms[i]);
+       }
+    }
+  return mbuf;
+}
diff --git a/gprofng/src/CompCom.h b/gprofng/src/CompCom.h
new file mode 100644 (file)
index 0000000..e653939
--- /dev/null
@@ -0,0 +1,63 @@
+/* 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 _COMPCOM_H
+#define _COMPCOM_H
+
+#include <sys/types.h>
+#include "comp_com.h"
+
+class Elf;
+typedef int (*CheckSrcName) (char *);
+
+class CompComment
+{
+public:
+  CompComment (Elf *_elf, int _compcom);
+  ~CompComment ();
+  int compcom_open (CheckSrcName check_src);
+  char *compcom_format (int index, compmsg *msg, int &visible);
+
+private:
+  int get_align (int64_t, int align);
+  char *get_demangle_name (char *fname);
+
+  Elf *elf;
+  int compcom, elf_cls;
+  compmsg *msgs;        /* the array of messages */
+  int32_t *params;      /* the parameters used in the messages parameters are
+                        *  either integers or string-indices */
+  char *strs; /* the strings used in the messages */
+};
+
+class ComC
+{
+public:
+  ComC ()       { com_str = NULL; };
+  ~ComC ()      { free (com_str); };
+
+  int sec;
+  int type;
+  int visible;
+  int line;
+  char *com_str;
+};
+
+#endif /* _COMPCOM_H */
diff --git a/gprofng/src/DataObject.cc b/gprofng/src/DataObject.cc
new file mode 100644 (file)
index 0000000..870a531
--- /dev/null
@@ -0,0 +1,193 @@
+/* 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 <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "Application.h"
+#include "DataObject.h"
+#include "Module.h"
+#include "debug.h"
+
+DataObject::DataObject ()
+{
+  name = NULL;
+  parent = NULL;
+  master = NULL;
+  _unannotated_name = NULL;
+  _typename = NULL;
+  _instname = NULL;
+  scope = NULL;
+  EAs = new Vector<DbeEA*>;
+  size = 0;
+  offset = (uint64_t) (-1);
+}
+
+DataObject::~DataObject ()
+{
+  free (_unannotated_name);
+  free (_typename);
+  free (_instname);
+  EAs->destroy ();
+  delete EAs;
+}
+
+// get_addr() doesn't return an actual address for a DataObject
+// but rather synthesises an address-like identifier tuple.
+// XXXX since an aggregate and its first element have identical tuples
+// may need to arrange for special-purpose sorting "by address"
+uint64_t
+DataObject::get_addr ()
+{
+  uint64_t addr;
+  if (parent && parent->get_typename ())
+    addr = MAKE_ADDRESS (parent->id, offset);   // element
+  else if (parent)
+    addr = MAKE_ADDRESS (parent->id, id) | 0x8000000000000000ULL; // Scalar, Unknown
+  else if (id == dbeSession->get_Scalars_DataObject ()->id)
+    addr = MAKE_ADDRESS (id, 0) | 0x8000000000000000ULL;    // Scalar aggregate
+  else if (id == dbeSession->get_Unknown_DataObject ()->id)
+    addr = MAKE_ADDRESS (id, 0) | 0x8000000000000000ULL;    // Unknown aggregate
+  else
+    addr = MAKE_ADDRESS (id, 0);     // aggregate
+  return addr;
+}
+
+Histable *
+DataObject::convertto (Histable_type type, Histable *)
+{
+  return type == DOBJECT ? this : NULL;
+}
+
+char
+DataObject::get_offset_mark ()
+{
+  enum
+  {
+    blocksize = 32
+  };
+
+  if (size == 0 || offset == -1)
+    return '?';     // undefined
+  if (size > blocksize)
+    return '#';     // requires multiple blocks
+  if (size == blocksize && (offset % blocksize == 0))
+    return '<';     // fits block entirely
+  if (offset % blocksize == 0)
+    return '/';     // starts block
+  if ((offset + size) % blocksize == 0)
+    return '\\';    // closes block
+  if (offset / blocksize == ((offset + size) / blocksize))
+    return '|';     // inside block
+  return 'X';       // crosses blocks unnecessarily
+}
+
+char *
+DataObject::get_offset_name ()
+{
+  char *offset_name;
+  if (parent && parent->get_typename ()) // element
+    offset_name = dbe_sprintf (GTXT ("%c%+6lld .{%s %s}"),
+                              get_offset_mark (), (long long) offset,
+                              _typename ? _typename : GTXT ("NO_TYPE"),
+                              _instname ? _instname : GTXT ("-")); // "NO_NAME"
+  else if ((offset != -1) && (offset > 0)) // filler
+    offset_name = dbe_sprintf (GTXT ("%c%+6lld %s"), get_offset_mark (),
+                              (long long) offset, get_name ());
+  else if (parent) // Scalar/Unknown element
+    offset_name = dbe_sprintf (GTXT ("        .%s"), get_unannotated_name ());
+  else // aggregate
+    offset_name = dbe_strdup (get_name ());
+  return offset_name;
+}
+
+void
+DataObject::set_dobjname (char *type_name, char *inst_name)
+{
+  _unannotated_name = _typename = _instname = NULL;
+  if (inst_name)
+    _instname = dbe_strdup (inst_name);
+
+  char *buf;
+  if (parent == dbeSession->get_Scalars_DataObject ())
+    {
+      if (type_name)
+       _typename = dbe_strdup (type_name);
+      _unannotated_name = dbe_sprintf (NTXT ("{%s %s}"), type_name,
+                                      inst_name ? inst_name : NTXT ("-"));
+      buf = dbe_sprintf (NTXT ("%s.%s"), parent->get_name (), _unannotated_name);
+    }
+  else if (parent == dbeSession->get_Unknown_DataObject ())
+    {
+      _unannotated_name = dbe_strdup (type_name);
+      buf = dbe_sprintf (NTXT ("%s.%s"), parent->get_name (), _unannotated_name);
+    }
+  else
+    {
+      if (type_name)
+       _typename = dbe_strdup (type_name);
+      if (parent && parent->get_typename ())
+       buf = dbe_sprintf (NTXT ("%s.{%s %s}"),
+                          parent->get_name () ? parent->get_name () : NTXT ("ORPHAN"),
+                          type_name ? type_name : NTXT ("NO_TYPE"),
+                          inst_name ? inst_name : NTXT ("-")); // "NO_NAME"
+      else
+       buf = dbe_sprintf (NTXT ("{%s %s}"),
+                          type_name ? type_name : NTXT ("NO_TYPE"),
+                          inst_name ? inst_name : NTXT ("-")); // "NO_NAME"
+    }
+  name = buf;
+  dbeSession->dobj_updateHT (this);
+}
+
+void
+DataObject::set_name (char *string)
+{
+  name = dbe_strdup (string);
+  dbeSession->dobj_updateHT (this);
+}
+
+DbeEA *
+DataObject::find_dbeEA (Vaddr EA)
+{
+  DbeEA *dbeEA;
+  int left = 0;
+  int right = EAs->size () - 1;
+  while (left <= right)
+    {
+      int index = (left + right) / 2;
+      dbeEA = EAs->fetch (index);
+      if (EA < dbeEA->eaddr)
+       right = index - 1;
+      else if (EA > dbeEA->eaddr)
+       left = index + 1;
+      else
+       return dbeEA;
+    }
+
+  // None found, create a new one
+  dbeEA = new DbeEA (this, EA);
+  EAs->insert (left, dbeEA);
+  return dbeEA;
+}
diff --git a/gprofng/src/DataObject.h b/gprofng/src/DataObject.h
new file mode 100644 (file)
index 0000000..f70bbad
--- /dev/null
@@ -0,0 +1,82 @@
+/* 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 _DATAOBJECT_H
+#define _DATAOBJECT_H
+
+// A DataObject object represents a distinct dataobject.
+
+#include "dbe_structs.h"
+#include "Histable.h"
+
+extern char *DOBJ_UNSPECIFIED;
+extern char *DOBJ_UNIDENTIFIED;
+extern char *DOBJ_UNDETERMINED;
+extern char *DOBJ_ANON;
+extern char *DOBJ_UNASCERTAINABLE;
+extern char *DOBJ_UNVERIFIABLE;
+extern char *DOBJ_UNRESOLVABLE;
+
+class DataObject : public Histable
+{
+public:
+  DataObject ();
+  ~DataObject ();
+
+  static const unsigned UNSPECIFIED_ID = 0xFFFFFFFF;
+
+  int64_t size;             // size of the dataobject in bytes
+  int64_t offset;           // offset of dataobject from parent
+  DataObject *parent;       // this dataobject's parent (if any)
+  Histable *scope;          // scope of this dataobject
+  DataObject *master;       // this dataobject's master (if any)
+
+  Histable_type get_type ()         { return DOBJECT; }
+  int64_t get_size ()               { return size; }
+  int64_t get_offset ()             { return offset; }
+  DataObject *get_parent ()         { return parent; }
+  DataObject *get_master ()         { return master; }
+  char *get_typename ()             { return _typename; }
+  char *get_instname ()             { return _instname; }
+  Histable *get_scope ()            { return scope; }
+
+  char *get_unannotated_name ()
+  { // name without a <Scalar> or <Unknown> prefix
+    if (_unannotated_name)
+      return _unannotated_name;
+    return get_name ();
+  }
+
+  uint64_t get_addr ();
+  char get_offset_mark ();
+  char *get_offset_name ();
+  void set_dobjname (char *type_name, char *inst_name); // dobj->parent must already be set
+  void set_name (char *);
+  Histable *convertto (Histable_type type, Histable *obj = NULL);
+  DbeEA *find_dbeEA (Vaddr EA);
+
+private:
+  char *_unannotated_name;  // name without a <Scalar> or <Unknown> prefix
+  char *_typename;          // name of this dataobject's type
+  char *_instname;          // name of this dataobject instance
+  Vector<DbeEA*> *EAs;
+};
+
+#endif  /* _DATAOBJECT_H */
diff --git a/gprofng/src/DataSpace.cc b/gprofng/src/DataSpace.cc
new file mode 100644 (file)
index 0000000..e5b48dd
--- /dev/null
@@ -0,0 +1,558 @@
+/* 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 <stdlib.h>
+#include <stdarg.h>
+
+#include "util.h"
+#include "Application.h"
+#include "CallStack.h"
+#include "Experiment.h"
+#include "Exp_Layout.h"
+#include "DataObject.h"
+#include "DbeSession.h"
+#include "MetricList.h"
+#include "Function.h"
+#include "Module.h"
+#include "MemObject.h"
+#include "DbeView.h"
+#include "Metric.h"
+#include "DataSpace.h"
+#include "LoadObject.h"
+
+#include "debug.h"
+#include "ABS.h"
+
+//char *DOBJ_UNSPECIFIED  = STXT("(Not identified by the compiler as a memory-referencing instruction)");
+char *DOBJ_UNSPECIFIED  = STXT("(No type information)");
+char *DOBJ_UNIDENTIFIED = STXT("(No identifying descriptor provided by the compiler)");
+char *DOBJ_UNDETERMINED = STXT("(Not determined from the symbolic information provided by the compiler)");
+char *DOBJ_ANON         = STXT("(Padding in structure)");
+
+// run-time codes
+//  ABS_UNSUPPORTED = 0x01, /* inappropriate HWC event type */
+//  ABS_BLOCKED     = 0x02, /* runtime backtrack blocker reached */
+//  ABS_INCOMPLETE  = 0x03, /* runtime backtrack limit reached */
+//  ABS_REG_LOSS    = 0x04, /* address register contaminated */
+//  ABS_INVALID_EA  = 0x05, /* invalid effective address value */
+
+const char *ABS_RT_CODES[NUM_ABS_RT_CODES] = {
+  "(OK)",
+  "(Dataspace data not requested during data collection)",
+  "(Backtracking was prevented by a jump or call instruction)",
+  "(Backtracking did not find trigger PC)",
+  "(Could not determine VA because registers changed after trigger instruction)",
+  "(Memory-referencing instruction did not specify a valid VA)",
+  "(UNKNOWN)"
+};
+
+// post-processing codes
+//  ABS_NO_CTI_INFO = 0x10, /* no AnalyzerInfo for validation */
+//  ABS_INFO_FAILED = 0x20, /* info failed to validate backtrack */
+//  ABS_CTI_TARGET  = 0x30, /* CTI target invalidated backtrack */
+char *DOBJ_UNASCERTAINABLE = STXT("(Module with trigger PC not compiled with -xhwcprof)");
+char *DOBJ_UNVERIFIABLE    = STXT("(Backtracking failed to find a valid branch target)");
+char *DOBJ_UNRESOLVABLE    = STXT("(Backtracking traversed a branch target)");
+
+char *ABS_PP_CODES[NUM_ABS_PP_CODES] = {
+  STXT ("(OK)"),
+  DOBJ_UNASCERTAINABLE,
+  DOBJ_UNVERIFIABLE,
+  DOBJ_UNRESOLVABLE,
+  STXT ("(<INTERNAL ERROR DURING POST-PROCESSING>)")
+};
+
+DataSpace::DataSpace (DbeView *_dbev, int /* _picked */)
+{
+  dbev = _dbev;
+}
+
+DataSpace::~DataSpace () { }
+
+void
+DataSpace::reset () { }
+
+char *
+DataSpace::status_str ()
+{
+  return NULL;
+}
+
+Histable *
+DataSpace::get_hist_obj (Histable::Type type, DataView *dview, long i)
+{
+  DataObject *dobj = NULL;
+  char *errcode = NTXT ("<internal error>");
+  switch (type)
+    {
+    case Histable::DOBJECT:
+      dobj = (DataObject*) dview->getObjValue (PROP_HWCDOBJ, i);
+      if (dobj == NULL)
+       {
+         Vaddr leafVA = (Vaddr) dview->getLongValue (PROP_VADDR, i);
+         unsigned rt_code = (unsigned) ABS_GET_RT_CODE (leafVA);
+         unsigned pp_code = (unsigned) ABS_GET_PP_CODE (leafVA);
+         if (leafVA < ABS_CODE_RANGE
+             && (pp_code || (rt_code && rt_code != ABS_REG_LOSS)))
+           {
+             if (rt_code >= NUM_ABS_RT_CODES)
+               rt_code = NUM_ABS_RT_CODES - 1;
+             if (pp_code >= NUM_ABS_PP_CODES)
+               pp_code = NUM_ABS_PP_CODES - 1;
+             if (rt_code)
+               errcode = PTXT (ABS_RT_CODES[rt_code]);
+             else
+               errcode = PTXT (ABS_PP_CODES[pp_code]);
+           }
+         else
+           {
+             // associate dataobject with event
+             int index;
+
+             // search for memop in Module infoList
+             void *cstack = dview->getObjValue (PROP_MSTACK, i);
+             Histable *leafPCObj = CallStack::getStackPC (cstack, 0);
+             DbeInstr *leafPC = NULL;
+             if (leafPCObj->get_type () == Histable::INSTR)
+               leafPC = (DbeInstr*) leafPCObj;
+             else  // DBELINE
+               leafPC = (DbeInstr*) leafPCObj->convertto (Histable::INSTR);
+             Function *func = leafPC->func;
+             uint64_t leafPC_offset = func->img_offset + leafPC->addr;
+             Module *mod = func->module;
+             uint32_t dtype_id = 0;
+             inst_info_t *info = NULL;
+             Vec_loop (inst_info_t*, mod->infoList, index, info)
+             {
+               if (info->offset == leafPC_offset)
+                 {
+                   dtype_id = info->memop->datatype_id;
+                   break;
+                 }
+             }
+             dobj = mod->get_dobj (dtype_id);
+             if (dobj == NULL)
+               {
+                 // ensure dobj is determined
+                 if (dtype_id == DataObject::UNSPECIFIED_ID)
+                   errcode = PTXT (DOBJ_UNSPECIFIED);
+                 else
+                   errcode = PTXT (DOBJ_UNIDENTIFIED);
+               }
+             else
+               {
+                 // determine associated master dataobject
+                 if (!dobj->master && dobj->scope)
+                   dobj->master = dbeSession->createMasterDataObject (dobj);
+                 if (dobj->scope)
+                   dobj = dobj->master;  // use associated master
+               }
+           }
+         if (!dobj)
+           {
+             // if dobj is not set yet, supply a dobj for errcode
+             // search for a dobj with the same name
+             dobj = dbeSession->find_dobj_by_name (errcode);
+             if (dobj == NULL)
+               {
+                 // create new DataObject for unknown code
+                 dobj = (DataObject*) dbeSession->createHistObject (Histable::DOBJECT);
+                 dobj->size = 0;
+                 dobj->offset = -1;
+                 dobj->parent = dbeSession->get_Unknown_DataObject ();
+                 dobj->set_dobjname (errcode, NULL); // dobj->parent must already be set
+               }
+           }
+         dview->setObjValue (PROP_HWCDOBJ, i, dobj);
+       }
+      break;
+    default:
+      break;
+    }
+  return dobj;
+}
+
+Hist_data *
+DataSpace::compute_metrics (MetricList *mlist, Histable::Type type,
+                           Hist_data::Mode mode, Histable *sel_obj)
+{
+  int nmetrics = mlist->get_items ()->size ();
+  int sort_ind = -1;
+  Hist_data::HistItem *hi;
+  int index;
+
+  // reset event_data count for all datatypes
+  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+  for (int i = 0, sz = lobjs ? lobjs->size () : -1; i < sz; i++)
+    {
+      LoadObject *lo = lobjs->fetch (i);
+      Vector<Module*> *modules = lo->seg_modules;
+      for (int j = 0, msize = modules ? modules->size () : -1; j < msize; j++)
+       {
+         Module *mod = modules->fetch (j);
+         mod->reset_datatypes ();
+       }
+    }
+  Hist_data *hist_data = new Hist_data (mlist, type, mode);
+
+  // add each experiment, skipping disabled and broken experiments
+  for (index = 0; index < dbeSession->nexps (); index++)
+    {
+      Experiment *exp = dbeSession->get_exp (index);
+      if (exp->broken)
+       continue;
+
+      Collection_params *params = exp->get_params ();
+      if (!params->xhw_mode)
+       continue;
+
+      char *expt_name = exp->get_expt_name ();
+      char *base_name = strrchr (expt_name, '/');
+      base_name = base_name ? base_name + 1 : expt_name;
+
+      // Determine mapping of experiment HWC metrics to hist_data metric list
+      int *xlate = new int[MAX_HWCOUNT];
+      for (unsigned i = 0; i < MAX_HWCOUNT; i++)
+       {
+         xlate[i] = -1;
+         if (params->hw_interval[i] > 0)
+           {
+             const char *ctr_name = params->hw_aux_name[i];
+             int mindex;
+             Metric *met;
+             Vec_loop (Metric*, mlist->get_items (), mindex, met)
+             {
+               if (dbe_strcmp (met->get_cmd (), ctr_name) == 0)
+                 xlate[i] = mindex;
+             }
+           }
+       }
+
+      //
+      // Process hardware profiling data
+      //
+      DataView *dview = dbev->get_filtered_events (index, DATA_HWC);
+      if (dview)
+       {
+         DataDescriptor *ddscr = dview ->getDataDescriptor ();
+         if (ddscr->getProp (PROP_HWCDOBJ) == NULL)
+           {
+             PropDescr *prop = new PropDescr (PROP_HWCDOBJ, NTXT ("HWCDOBJ"));
+             prop->uname = NULL;
+             prop->vtype = TYPE_OBJ;
+             ddscr->addProperty (prop);
+           }
+       }
+      if (dview && dview->getSize () != 0)
+       {
+         char *msg = NULL;
+         for (long i = 0; i < dview->getSize (); i++)
+           {
+             if (i % 5000 == 0)
+               {
+                 int percent = (int) (100.0 * i / dview->getSize ());
+                 if (percent == 0 && msg == NULL)
+                   msg = dbe_sprintf (GTXT ("Filtering HW Profile Address Data: %s"), base_name);
+                 theApplication->set_progress (percent, (percent != 0) ? NULL : msg);
+               }
+
+             uint32_t tag = dview->getIntValue (PROP_HWCTAG, i);
+             if (tag < 0 || tag >= MAX_HWCOUNT)
+               continue;  // invalid HWC tag in the record; ignore it
+             int mHwcntr_idx = xlate[tag];
+             if (mHwcntr_idx < 0)
+               continue;
+
+             Vaddr leafVA = (Vaddr) dview->getLongValue (PROP_VADDR, i);
+             if (leafVA == ABS_UNSUPPORTED)
+               continue; // skip this record
+             Histable *obj = get_hist_obj (type, dview, i);
+             if (obj == NULL)
+               continue;
+             uint64_t interval = dview->getLongValue (PROP_HWCINT, i);
+             if (HWCVAL_HAS_ERR (interval))
+               continue;
+             if (mode == Hist_data::ALL)
+               { // data_objects
+                 hi = hist_data->append_hist_item (obj);
+                 hi->value[mHwcntr_idx].ll += interval;
+                 for (DataObject *dobj = ((DataObject *) obj)->parent; dobj; dobj = dobj->parent)
+                   {
+                     hi = hist_data->append_hist_item (dobj);
+                     hi->value[mHwcntr_idx].ll += interval;
+                   }
+               }
+             else if (mode == Hist_data::LAYOUT || mode == Hist_data::DETAIL)
+               { // data_single
+                 {
+                   // for data layout, insert elements that have no metrics yet
+                   DataObject *tmpParent = ((DataObject *) obj)->parent;
+                   if (tmpParent && tmpParent->get_typename ())
+                     {
+                       // dobj is an aggregate element
+                       if (!hist_data->find_hist_item (tmpParent))
+                         {
+                           // parent not yet a member of hist_data
+                           // supply parent's children with 0 values for layout
+                           Vector<DataObject*> *elements = dbeSession->get_dobj_elements (tmpParent);
+                           for (long eli = 0, sz = elements->size (); eli < sz; eli++)
+                             {
+                               DataObject* element = elements->fetch (eli);
+                               assert (!hist_data->find_hist_item (element));
+                               hi = hist_data->append_hist_item (element);
+                             }
+                         }
+                     }
+                 }
+
+                 // Same as for mode == Hist_data::ALL:
+                 hi = hist_data->append_hist_item (obj);
+                 hi->value[mHwcntr_idx].ll += interval;
+                 for (DataObject *dobj = ((DataObject *) obj)->parent; dobj; dobj = dobj->parent)
+                   {
+                     hi = hist_data->append_hist_item (dobj);
+                     hi->value[mHwcntr_idx].ll += interval;
+                   }
+               }
+             else if (mode == Hist_data::SELF)
+               { // used by dbeGetSummary()
+                 if (obj == sel_obj)
+                   {
+                     hi = hist_data->append_hist_item (obj);
+                     hi->value[mHwcntr_idx].ll += interval;
+                   }
+                 else
+                   {
+                     for (DataObject *dobj = ((DataObject *) obj)->parent; dobj; dobj = dobj->parent)
+                       {
+                         if ((Histable*) dobj == sel_obj)
+                           {
+                             hi = hist_data->append_hist_item (dobj);
+                             hi->value[mHwcntr_idx].ll += interval;
+                             break;
+                           }
+                       }
+                   }
+               }
+             // Update total
+             hist_data->total->value[mHwcntr_idx].ll += interval;
+           }
+         free (msg);
+         theApplication->set_progress (0, NTXT (""));
+       }
+      delete[] xlate;
+    }
+
+  // include a regular HistItem for <Total> -- for all DataObjects, and MemObjects
+  DataObject *dtot = dbeSession->get_Total_DataObject ();
+  if (mode == Hist_data::ALL || mode == Hist_data::DETAIL
+      || mode == Hist_data::LAYOUT ||
+      sel_obj == dtot)
+    {
+      hi = hist_data->append_hist_item (dtot);
+      for (int mind = 0; mind < nmetrics; mind++)
+       hi->value[mind] = hist_data->total->value[mind];
+    }
+  if (hist_data->get_status () != Hist_data::SUCCESS)
+    return hist_data;
+  theApplication->set_progress (0, GTXT ("Constructing Metrics"));
+
+  // Determine by which metric to sort if any
+  bool rev_sort = mlist->get_sort_rev ();
+
+  // Compute static metrics: SIZES, ADDRESS.
+  for (int mind = 0; mind < nmetrics; mind++)
+    {
+      Metric *mtr = mlist->get_items ()->fetch (mind);
+      if (mlist->get_sort_ref_index () == mind)
+       sort_ind = mind;
+      else if (!mtr->is_visible () && !mtr->is_tvisible ()
+              && !mtr->is_pvisible ())
+       continue;
+      Metric::Type mtype = mtr->get_type ();
+      if (mtype == Metric::SIZES)
+       {
+         Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+         {
+           Histable *h = mtr->get_comparable_obj (hi->obj);
+           hi->value[mind].tag = VT_LLONG;
+           hi->value[mind].ll = h ? h->get_size () : 0;
+         }
+       }
+      else if (mtype == Metric::ONAME
+              && (mode == Hist_data::SELF
+                  || ((DataObject*) sel_obj == dbeSession->get_Total_DataObject ())))
+       {
+         Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+         {
+           hi->value[mind].tag = VT_OFFSET; // offset labels
+         }
+       }
+      else if (mtype == Metric::ADDRESS)
+       { // pseudo-address
+         Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+         {
+           hi->value[mind].tag = VT_ADDRESS;
+           Histable *h = mtr->get_comparable_obj (hi->obj);
+           hi->value[mind].ll = h ? h->get_addr () : 0;
+         }
+         // force sort by offset // XXXX should visibility also be set?
+         if (mode == Hist_data::SELF)
+           { // used by dbeGetSummary()
+             sort_ind = mind;
+             //hist_data->metrics->fetch(mind)->set_visible(T);
+           }
+       }
+      else
+       {
+         ValueTag vtype = mtr->get_vtype ();
+         switch (vtype)
+           {
+           case VT_ULLONG: // most Data-derived HWC metrics are VT_ULLONG
+             hist_data->total->value[mind].tag = vtype;
+             Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+             {
+               hi->value[mind].tag = vtype;
+             }
+             break;
+           case VT_DOUBLE:
+             {
+               double prec = mtr->get_precision ();
+               hist_data->total->value[mind].tag = vtype;
+               hist_data->total->value[mind].d = hist_data->total->value[mind].ll / prec;
+               Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+               {
+                 hi->value[mind].tag = vtype;
+                 hi->value[mind].d = hi->value[mind].ll / prec;
+               }
+               break;
+             }
+           default:
+             if (mtr->get_subtype () != Metric::STATIC)
+               abort ();
+             break;
+           }
+       }
+    }
+  hist_data->sort (sort_ind, rev_sort);
+  hist_data->compute_minmax ();
+  theApplication->set_progress (0, NTXT (""));
+  return hist_data;
+}
+
+
+// generate annotated structure info for data_layout
+// note: similar data traversal found in er_print_histogram::dump_detail()
+Hist_data *
+DataSpace::get_layout_data (Hist_data *sorted_data,
+                           Vector<int> *marks, int /* _threshold */)
+{
+  Hist_data *data_items = NULL;
+  Hist_data::HistItem *new_item;
+  MetricList *mlist = new MetricList (sorted_data->get_metric_list ());
+  int no_metrics = mlist->get_items ()->size ();
+  int index, addr_index = -1, name_index = -1;
+  Dprintf (DEBUG_DATAOBJ, NTXT ("DataSpace::get_layout_data(ALL)\n"));
+
+  // Allocate a new Hist_data for the list, to be copied from the DataObect list
+  data_items = new Hist_data (mlist, Histable::DOBJECT, Hist_data::MODL);
+  data_items->set_status (sorted_data->get_status ());
+
+  // suppress threshold setting
+  // XXX this threshold should probably not be used
+  sorted_data->set_threshold ((double) 75. / 100.0);
+  TValue* all_empty = new TValue[no_metrics];
+  memset (all_empty, 0, sizeof (TValue) * no_metrics);
+
+  Metric *mitem;
+  Vec_loop (Metric*, mlist->get_items (), index, mitem)
+  {
+    // new data items have same total as original items
+    data_items->total->value[index] = sorted_data->total->value[index];
+    // empty metric items need matching types
+    all_empty[index].tag = mitem->get_vtype ();
+    if (mitem->get_type () == Metric::ONAME) name_index = index;
+    if (mitem->get_type () == Metric::ADDRESS) addr_index = index;
+  }
+
+  int64_t next_elem_offset = 0;
+  for (long i = 0; i < sorted_data->size (); i++)
+    {
+      Hist_data::HistItem* ditem = sorted_data->fetch (i);
+      DataObject* dobj = (DataObject*) (ditem->obj);
+      if (!dobj->get_parent ())
+       { // doesn't have a parent; top level item
+         next_elem_offset = 0;
+         if (i > 0)
+           { // add a blank line as separator
+             // fixme xxxxx, is it really ok to create a DataObject just for this?
+             DataObject* empty = new DataObject ();
+             empty->size = 0;
+             empty->offset = 0;
+             empty->set_name (NTXT (""));
+             new_item = sorted_data->new_hist_item (empty, Module::AT_EMPTY, all_empty);
+             new_item->value[name_index].tag = VT_LABEL;
+             new_item->value[name_index].l = NULL;
+             data_items->append_hist_item (new_item);
+           }
+         // then add the aggregate
+         new_item = sorted_data->new_hist_item (dobj, Module::AT_SRC, ditem->value);
+         new_item->value[name_index].tag = VT_OFFSET;
+         new_item->value[name_index].l = dbe_strdup (dobj->get_name ());
+         data_items->append_hist_item (new_item);
+       }
+      else
+       { // is a child
+         if (dobj->get_parent ()->get_typename ())
+           { // typed sub-element that has offset
+             if (dobj->offset > next_elem_offset)
+               { // filler entry
+                 // hole in offsets
+                 // fixme xxxxx, is it really ok to create a DataObject just for this?
+                 DataObject* filler = new DataObject ();
+                 filler->set_name (PTXT (DOBJ_ANON));
+                 filler->size = (dobj->offset - next_elem_offset);
+                 filler->offset = next_elem_offset;
+                 new_item = sorted_data->new_hist_item (filler, Module::AT_EMPTY, all_empty);
+                 new_item->value[name_index].tag = VT_OFFSET;
+                 new_item->value[name_index].l = dbe_strdup (filler->get_offset_name ());
+                 if (addr_index >= 0)
+                   {
+                     new_item->value[addr_index].tag = VT_ADDRESS;
+                     new_item->value[addr_index].ll = (dobj->get_addr () - filler->size);
+                   }
+                 data_items->append_hist_item (new_item);
+               }
+             next_elem_offset = dobj->offset + dobj->size;
+           }
+         // then add the aggregate's subelement
+         if (marks)
+           if (sorted_data->above_threshold (ditem))
+             marks->append (data_items->size ());
+         new_item = sorted_data->new_hist_item (dobj, Module::AT_DIS, ditem->value);
+         new_item->value[name_index].tag = VT_OFFSET;
+         new_item->value[name_index].l = dbe_strdup (dobj->get_offset_name ());
+         data_items->append_hist_item (new_item);
+       }
+    }
+  delete[] all_empty;
+  return data_items;
+}
diff --git a/gprofng/src/DataSpace.h b/gprofng/src/DataSpace.h
new file mode 100644 (file)
index 0000000..c4d80fb
--- /dev/null
@@ -0,0 +1,55 @@
+/* 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 _DATASPACE_H
+#define _DATASPACE_H
+
+#include <stdio.h>
+
+#include "dbe_structs.h"
+#include "vec.h"
+#include "Exp_Layout.h"
+#include "Hist_data.h"
+#include "Histable.h"
+#include "Metric.h"
+
+class DbeView;
+class DataView;
+
+class DataSpace
+{
+public:
+  DataSpace (DbeView *_dbev, int picked = 0);
+  ~DataSpace ();
+  void reset ();
+  Hist_data *compute_metrics (MetricList *, Histable::Type,
+                             Hist_data::Mode, Histable*);
+  Hist_data *get_layout_data (Hist_data *sorted_data, Vector<int> *marks,
+                             int threshold);
+
+  static char *status_str ();
+
+private:
+  Histable *get_hist_obj (Histable::Type, DataView*, long);
+
+  DbeView *dbev;
+};
+
+#endif /* _DATASPACE_H */
diff --git a/gprofng/src/DataStream.cc b/gprofng/src/DataStream.cc
new file mode 100644 (file)
index 0000000..8e244e2
--- /dev/null
@@ -0,0 +1,55 @@
+/* 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 "util.h"
+#include "DataStream.h"
+#include "debug.h"
+
+DataStream::DataStream (char *filename) : Data_window (filename)
+{
+  set_span (0, -1);
+}
+
+DataStream::~DataStream () { }
+
+void
+DataStream::set_span (int64_t f_offset, int64_t sz)
+{
+  span_offset = 0;
+  span_fileoffset = f_offset;
+  int64_t fsz = get_fsize ();
+  span_size = sz == -1 ? fsz : sz;
+  if (span_fileoffset >= fsz)
+    span_fileoffset = fsz;
+  if (span_size > fsz - span_fileoffset)
+    span_size = fsz - span_fileoffset;
+}
+
+int64_t
+DataStream::read (void *buf, int64_t len)
+{
+  if (len > span_size - span_offset)
+    len = span_size - span_offset;
+  int64_t off = span_offset + span_fileoffset;
+  span_offset += len;
+  get_data (off, len, buf);
+  return len;
+}
diff --git a/gprofng/src/DataStream.h b/gprofng/src/DataStream.h
new file mode 100644 (file)
index 0000000..59ee293
--- /dev/null
@@ -0,0 +1,51 @@
+/* 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 _DATASTREAM_H
+#define _DATASTREAM_H
+
+#include "Data_window.h"
+
+// sequential access to the file
+class DataStream : public Data_window
+{
+public:
+  // Create an empty data window.
+  DataStream (char *file_name);
+  ~DataStream ();
+  void set_span (int64_t f_offset, int64_t sz);
+  int64_t read (void *buf, int64_t len);
+
+  template <typename Key_t> inline int64_t
+  read (Key_t &val)
+  {
+    int64_t sz = read (&val, sizeof (val));
+    if (need_swap_endian && sz == sizeof (val))
+      swapByteOrder (&val, sizeof (val));
+    return sz;
+  }
+
+private:
+  int64_t span_offset;
+  int64_t span_size;        // the window size
+  int64_t span_fileoffset;  // the window begin on the file
+};
+
+#endif /* _DATASTREAM_H */
diff --git a/gprofng/src/Data_window.cc b/gprofng/src/Data_window.cc
new file mode 100644 (file)
index 0000000..d9b0067
--- /dev/null
@@ -0,0 +1,241 @@
+/* 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/mman.h>
+#include <fcntl.h>
+#include <unistd.h>     //  for close();
+
+#include "util.h"
+#include "Data_window.h"
+#include "debug.h"
+
+enum
+{
+  MINBUFSIZE    = 1 << 16,
+  WIN_ALIGN     = 8
+};
+
+Data_window::Data_window (char *file_name)
+{
+  Dprintf (DEBUG_DATA_WINDOW, NTXT ("Data_window:%d %s\n"), (int) __LINE__, STR (file_name));
+  page_size = sysconf (_SC_PAGESIZE);
+  need_swap_endian = false;
+  opened = false;
+  fsize = 0;
+  base = NULL;
+  woffset = 0;
+  wsize = 0;
+  basesize = 0;
+  fname = dbe_strdup (file_name);
+  mmap_on_file = false;
+  use_mmap = false;
+#if DEBUG
+  if (DBE_USE_MMAP)
+    use_mmap = true;
+#endif /* DEBUG */
+  fd = open64 (fname, O_RDONLY);
+  if (fd == -1)
+    return;
+  fsize = lseek (fd, 0, SEEK_END);
+  if (fsize == 0)
+    {
+      close (fd);
+      fd = -1;
+      return;
+    }
+  opened = true;
+  if (use_mmap)
+    {
+      if (fsize != -1)
+       {
+         base = (void*) mmap (NULL, (size_t) fsize, PROT_READ, MAP_PRIVATE, fd, 0);
+         close (fd);
+         fd = -1;
+         if (base == MAP_FAILED)
+           {
+             base = NULL;
+             use_mmap = false;
+             return;
+           }
+         mmap_on_file = true;
+         wsize = fsize;
+       }
+    }
+}
+
+void *
+Data_window::bind (int64_t file_offset, int64_t minSize)
+{
+  Span span;
+  span.length = fsize - file_offset;
+  span.offset = file_offset;
+  return bind (&span, minSize);
+}
+
+void *
+Data_window::bind (Span *span, int64_t minSize)
+{
+  // Do any necessary mapping to access the desired span of data
+  // and return a pointer to the first byte.
+  Dprintf (DEBUG_DATA_WINDOW, NTXT ("Data_window:bind:%d offset=%llx:%lld minSize=%lld \n"),
+          (int) __LINE__, (long long) span->offset, (long long) span->length, (long long) minSize);
+  if (minSize == 0 || span->length < minSize)
+    return NULL;
+
+  if (span->offset < woffset || span->offset + minSize > woffset + wsize)
+    {
+      // Remap the window
+      if (span->offset + minSize > fsize)
+       return NULL;
+      int myfd = fd;
+      if (myfd == -1)
+       {
+         if (fname)
+           myfd = open64 (fname, O_RDONLY, 0);
+         if (myfd == -1)
+           return NULL;
+       }
+      bool remap_failed = true;
+      if (use_mmap)
+       {
+         if (base)
+           {
+             munmap ((caddr_t) base, (size_t) wsize);
+             base = NULL;
+           }
+         woffset = span->offset & ~(page_size - 1);
+         wsize = page_size * ((MINBUFSIZE + page_size - 1) / page_size);
+         if (span->offset + minSize > woffset + wsize)
+           // Extend a window
+           wsize += page_size * ((span->offset + minSize -
+                                  woffset - wsize + page_size - 1) / page_size);
+         base = (void *) mmap (0, (size_t) wsize, PROT_READ, MAP_SHARED, fd, woffset);
+         if (base == MAP_FAILED)
+           {
+             base = NULL;
+             use_mmap = false;
+           }
+         remap_failed = (base == NULL);
+       }
+      if (remap_failed)
+       {
+         remap_failed = false;
+         woffset = span->offset & ~(WIN_ALIGN - 1);
+         wsize = minSize + (span->offset % WIN_ALIGN);
+         if (wsize < MINBUFSIZE)
+           wsize = MINBUFSIZE;
+         if (wsize > fsize)
+           wsize = fsize;
+         if (basesize < wsize)
+           { // Need to realloc 'base'
+             free (base);
+             basesize = wsize;
+             base = (void *) malloc (basesize);
+             Dprintf (DEBUG_DATA_WINDOW,
+                      NTXT ("Data_window:bind:%d realloc basesize=%llx woffset=%lld \n"),
+                      (int) __LINE__, (long long) basesize, (long long) woffset);
+             if (base == NULL)
+               {
+                 basesize = 0;
+                 remap_failed = true;
+               }
+           }
+         if (wsize > fsize - woffset)
+           wsize = fsize - woffset;
+         off_t woff = (off_t) woffset;
+         if (base == NULL || woff != lseek (myfd, woff, SEEK_SET)
+             || wsize != read_from_file (myfd, base, wsize))
+           remap_failed = true;
+       }
+      if (fd == -1)
+       close (myfd);
+      if (remap_failed)
+       {
+         woffset = 0;
+         wsize = 0;
+         return NULL;
+       }
+    }
+  return (void *) ((char*) base + span->offset - woffset);
+}
+
+void *
+Data_window::get_data (int64_t offset, int64_t size, void *datap)
+{
+  if (size <= 0)
+    return NULL;
+  void *buf = bind (offset, size);
+  if (buf == NULL)
+    return NULL;
+  if (datap == NULL && !mmap_on_file)
+    // Can be remmaped or reallocated. Need to make a copy
+    datap = (void *) malloc (size);
+  if (datap)
+    {
+      memcpy (datap, buf, (size_t) size);
+      return datap;
+    }
+  return buf;
+}
+
+Data_window::~Data_window ()
+{
+  free (fname);
+  if (fd != -1)
+    close (fd);
+  if (base)
+    {
+      if (use_mmap)
+       munmap ((caddr_t) base, (size_t) wsize);
+      else
+       free (base);
+    }
+}
+
+int64_t
+Data_window::get_buf_size ()
+{
+  int64_t sz = MINBUFSIZE;
+  if (sz < basesize)
+    sz = basesize;
+  if (sz > fsize)
+    sz = fsize;
+  return sz;
+}
+
+int64_t
+Data_window::copy_to_file (int f, int64_t offset, int64_t size)
+{
+  long long bsz = get_buf_size ();
+  for (long long n = 0; n < size;)
+    {
+      long long sz = (bsz <= (size - n)) ? bsz : (size - n);
+      void *b = bind (offset + n, sz);
+      if (b == NULL)
+       return n;
+      long long len = write (f, b, sz);
+      if (len <= 0)
+       return n;
+      n += len;
+    }
+  return size;
+}
diff --git a/gprofng/src/Data_window.h b/gprofng/src/Data_window.h
new file mode 100644 (file)
index 0000000..a3e98c0
--- /dev/null
@@ -0,0 +1,99 @@
+/* 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 _DATA_WINDOW_H
+#define _DATA_WINDOW_H
+
+// The Data_window class hiearchy is used to access raw data in the
+// experiment record.
+//
+// The Data_window base class implements a set of windows into a raw data file.
+// It is responsible for mapping and unmapping regions of the file as
+// requested by other levels inside of the DBE.
+
+#include "util.h"
+
+class Data_window
+{
+public:
+
+  // Span in data file
+  typedef struct
+  {
+    int64_t offset; // file offset
+    int64_t length; // span length
+  } Span;
+
+  Data_window (char *filename);
+  ~Data_window ();
+
+  // Return address of "offset" byte of window for "length" bytes.
+  // Return 0 on error or locked.
+  void *bind (Span *span, int64_t minSize);
+  void *bind (int64_t file_offset, int64_t minSize);
+  void *get_data (int64_t offset, int64_t size, void *datap);
+  int64_t get_buf_size ();
+  int64_t copy_to_file (int f, int64_t offset, int64_t size);
+
+  bool not_opened ()            { return !opened; }
+  off64_t get_fsize ()          { return fsize; }
+
+  template <typename Key_t> inline Key_t
+  get_align_val (Key_t *vp)
+  {
+    if (sizeof (Key_t) <= sizeof (int))
+      return *vp;
+    // 64-bit value can have a wrong alignment
+    Key_t val = (Key_t) 0;
+    uint32_t *p1 = (uint32_t *) vp;
+    uint32_t *p2 = (uint32_t*) (&val);
+    p2[0] = p1[0];
+    p2[1] = p1[1];
+    return val;
+  }
+
+  template <typename Key_t> inline Key_t
+  decode (Key_t &v)
+  {
+    Key_t val = get_align_val (&v);
+    if (need_swap_endian)
+      swapByteOrder (&val, sizeof (val));
+    return val;
+  }
+
+  bool need_swap_endian;
+  char *fname;          // file name
+
+protected:
+  int fd;               // file descriptor
+  bool mmap_on_file;
+
+private:
+  long page_size;       // used in mmap()
+  bool use_mmap;
+  bool opened;
+  int64_t fsize;        // file size
+  void *base;           // current window
+  int64_t woffset;      // offset of current window
+  int64_t wsize;        // size of current window
+  int64_t basesize;     // size of allocated window
+};
+
+#endif /* _DATA_WINDOW_H */
diff --git a/gprofng/src/Dbe.cc b/gprofng/src/Dbe.cc
new file mode 100644 (file)
index 0000000..1a6e521
--- /dev/null
@@ -0,0 +1,10371 @@
+/* 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 <errno.h>
+#include <sys/types.h> // open, chmod
+#include <signal.h>
+#include <fcntl.h>     // open
+#include <strings.h>
+#include <unistd.h>
+
+#include "util.h"
+#include "Histable.h"
+#include "DbeSession.h"
+#include "DbeView.h"
+#include "BaseMetric.h"
+#include "CallStack.h"
+#include "collctrl.h"
+#include "Command.h"
+#include "Dbe.h"
+#include "DbeApplication.h"
+#include "DefaultMap.h"
+#include "LoadObject.h"
+#include "Experiment.h"
+#include "IndexObject.h"
+#include "IOActivity.h"
+#include "PreviewExp.h"
+#include "Function.h"
+#include "Hist_data.h"
+#include "MetricList.h"
+#include "Module.h"
+#include "DataSpace.h"
+#include "MemorySpace.h"
+#include "DataObject.h"
+#include "MemObject.h"
+#include "Filter.h"
+#include "FilterSet.h"
+#include "FilterExp.h"
+#include "Sample.h"
+#include "Print.h"
+#include "StringBuilder.h"
+#include "dbe_types.h"
+#include "ExpGroup.h"
+#include "vec.h"
+#include "UserLabel.h"
+#include "DbeFile.h"
+#include "PathTree.h"
+
+// Data structures for managing the collector control info for Collection GUI
+static Coll_Ctrl *col_ctr = NULL;
+
+template<> VecType Vector<int>::type ()
+{
+  return VEC_INTEGER;
+}
+
+template<> VecType Vector<unsigned>::type ()
+{
+  return VEC_INTEGER;
+}
+
+template<> VecType Vector<char>::type ()
+{
+  return VEC_CHAR;
+}
+
+template<> VecType Vector<bool>::type ()
+{
+  return VEC_BOOL;
+}
+
+template<> VecType Vector<double>::type ()
+{
+  return VEC_DOUBLE;
+}
+
+template<> VecType Vector<long long>::type ()
+{
+  return VEC_LLONG;
+}
+
+template<> VecType Vector<uint64_t>::type ()
+{
+  return VEC_LLONG;
+}
+
+template<> VecType Vector<void*>::type ()
+{
+  return VEC_VOIDARR;
+}
+
+template<> VecType Vector<char*>::type ()
+{
+  return VEC_STRING;
+}
+
+template<> VecType Vector<Vector<int>*>::type ()
+{
+  return VEC_INTARR;
+}
+
+template<> VecType Vector<Vector<char*>*>::type ()
+{
+  return VEC_STRINGARR;
+}
+
+template<> VecType Vector<Vector<long long>*>::type ()
+{
+  return VEC_LLONGARR;
+}
+
+// gcc won't instantiate Vector<unsigned>::type() without it
+Vector<unsigned> __dummy_unsigned_vector;
+
+#define CASE_S(x)   case x: return #x
+static const char *
+dsp_type_to_string (int t)
+{
+  switch (t)
+    {
+      CASE_S (DSP_FUNCTION);
+      CASE_S (DSP_LINE);
+      CASE_S (DSP_PC);
+      CASE_S (DSP_SOURCE);
+      CASE_S (DSP_DISASM);
+      CASE_S (DSP_SELF);
+      CASE_S (DSP_CALLER);
+      CASE_S (DSP_CALLEE);
+      CASE_S (DSP_CALLTREE);
+      CASE_S (DSP_TIMELINE);
+      CASE_S (DSP_STATIS);
+      CASE_S (DSP_EXP);
+      CASE_S (DSP_LEAKLIST);
+      CASE_S (DSP_MEMOBJ);
+      CASE_S (DSP_DATAOBJ);
+      CASE_S (DSP_DLAYOUT);
+      CASE_S (DSP_SRC_FILE);
+      CASE_S (DSP_IFREQ);
+      CASE_S (DSP_RACES);
+      CASE_S (DSP_INDXOBJ);
+      CASE_S (DSP_DUALSOURCE);
+      CASE_S (DSP_SOURCE_DISASM);
+      CASE_S (DSP_DEADLOCKS);
+      CASE_S (DSP_SOURCE_V2);
+      CASE_S (DSP_DISASM_V2);
+      CASE_S (DSP_IOACTIVITY);
+      CASE_S (DSP_OVERVIEW);
+      CASE_S (DSP_IOCALLSTACK);
+      CASE_S (DSP_HEAPCALLSTACK);
+      CASE_S (DSP_SAMPLE);
+    default:
+      break;
+    }
+  return NTXT ("ERROR");
+}
+
+enum
+{
+  COMPARE_BIT       = 1 << 8,
+  MTYPE_MASK        = (1 << 8) - 1,
+  GROUP_ID_SHIFT    = 16
+};
+
+static DbeView *
+getDbeView (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  return dbev;
+}
+
+
+Vector<char*> *
+dbeGetInitMessages ()
+{
+  // If any comments from the .rc files, send them to the GUI
+  Emsg *msg = theDbeApplication->fetch_comments ();
+  int size = 0;
+  while (msg != NULL)
+    {
+      size++;
+      msg = msg->next;
+    }
+
+  // Initialize Java String array
+  Vector<char*> *list = new Vector<char*>(size);
+  msg = theDbeApplication->fetch_comments ();
+  size = 0;
+  int i = 0;
+  while (msg != NULL)
+    {
+      char *str = msg->get_msg ();
+      list->store (i, dbe_strdup (str));
+      i++;
+      msg = msg->next;
+    }
+
+  // now delete the comments
+  theDbeApplication->delete_comments ();
+  return list;
+}
+
+Vector<char*> *
+dbeGetExpPreview (int /*dbevindex*/, char *exp_name)
+{
+  PreviewExp *preview = new PreviewExp ();
+  preview->experiment_open (exp_name);
+  preview->open_epilogue ();
+
+  // Initialize Java String array
+  Vector<char*> *info = preview->preview_info ();
+  int size = info->size ();
+  Vector<char*> *list = new Vector<char*>(size);
+
+  // Get experiment names
+  for (int i = 0; i < size; i++)
+    {
+      char *str = info->fetch (i);
+      if (str == NULL)
+       str = GTXT ("N/A");
+      list->store (i, dbe_strdup (str));
+    }
+  delete info;
+  delete preview;
+  return list;
+}
+
+char *
+dbeGetExpParams (int /*dbevindex*/, char *exp_name)
+{
+  PreviewExp *preview = new PreviewExp ();
+  preview->experiment_open (exp_name);
+
+  // Initialize Java String array
+  char *arg_list = dbe_strdup (preview->getArgList ());
+  delete preview;
+  return arg_list;
+}
+
+/**
+ * Gets File Attributes according to the specified format
+ * Supported formats:
+ * "/bin/ls -dl " - see 'man ls' for details
+ * @param filename
+ * @param format
+ * @return char * attributes
+ */
+char *
+dbeGetFileAttributes (const char *filename, const char *format)
+{
+  if (format != NULL)
+    {
+      if (!strcmp (format, NTXT ("/bin/ls -dl ")))
+       {
+         // A kind of "/bin/ls -dl " simulation
+         struct stat64 sbuf;
+         sbuf.st_mode = 0;
+         dbe_stat (filename, &sbuf);
+         if (S_IREAD & sbuf.st_mode)
+           { // Readable
+             if (S_ISDIR (sbuf.st_mode) != 0)
+               return dbe_sprintf (NTXT ("%s %s\n"), NTXT ("drwxrwxr-x"), filename);
+             else if (S_ISREG (sbuf.st_mode) != 0)
+               return dbe_sprintf (NTXT ("%s %s\n"), NTXT ("-rwxrwxr-x"), filename);
+           }
+       }
+    }
+  return dbe_strdup (NTXT (""));
+}
+
+/**
+ * Gets list of files for specified directory according to the specified format
+ * Supported formats:
+ * "/bin/ls -a" - see 'man ls' for details
+ * "/bin/ls -aF" - see 'man ls' for details
+ * @param dirname
+ * @param format
+ * @return char * files
+ */
+char *
+dbeGetFiles (const char *dirname, const char *format)
+{
+  if (format != NULL)
+    return dbe_read_dir (dirname, format);
+  return dbe_strdup (NTXT (""));
+}
+
+/**
+ * Creates the directory named by this full path name, including any
+ * necessary but nonexistent parent directories.
+ * @param dirname
+ * @return result
+ */
+char *
+dbeCreateDirectories (const char *dirname)
+{
+  if (dirname != NULL)
+    {
+      char *res = dbe_create_directories (dirname);
+      if (res != NULL)
+       return res;
+    }
+  return dbe_strdup (NTXT (""));
+}
+
+/**
+ * Deletes the file or the directory named by the specified path name.
+ * If this pathname denotes a directory, then the directory must be empty in order to be deleted.
+ * @param const char *pathname
+ * @return int result
+ */
+char *
+dbeDeleteFile (const char *pathname)
+{
+  // return unlink(pathname);
+  if (pathname != NULL)
+    {
+      char *res = dbe_delete_file (pathname);
+      if (res != NULL)
+       return res;
+    }
+  return dbe_strdup (NTXT (""));
+}
+
+/**
+ * Reads the file named by the specified path name.
+ * Temporary limitation: file should be "text only" and its size should be less than the 1 MB limit.
+ * If the operation was successful, the contents is in the first element, and second element is NULL.
+ * If the operation failed, then first element is NULL, and second element contains the error message.
+ * @param const char *pathname
+ * @return Vector<char*> *result
+ */
+Vector<char*> *
+dbeReadFile (const char *pathname)
+{
+  Vector<char*> *result = new Vector<char*>(2);
+  int limit = 1024 * 1024; // Temporary limit: 1 MB
+  char * contents = (char *) malloc (limit);
+  StringBuilder sb;
+  if (NULL == contents)
+    {
+      sb.sprintf (NTXT ("\nError: Cannot allocate %d bytes\n"), limit);
+      result->store (0, NULL);
+      result->store (1, sb.toString ()); // failure
+      return result;
+    }
+  int fd = open (pathname, O_RDONLY);
+  if (fd >= 0)
+    {
+      int64_t bytes = read_from_file (fd, contents, limit);
+      close (fd);
+      if (bytes >= limit)
+       {
+         sb.sprintf (NTXT ("\nError: file size is greater than the limit (%d bytes)\n"), limit);
+         result->store (0, NULL);
+         result->store (1, sb.toString ()); // failure
+       }
+      else
+       {
+         contents[bytes] = '\0'; // add string terminator
+         result->store (0, contents);
+         result->store (1, NULL); // success
+       }
+    }
+  else
+    {
+      sb.sprintf (NTXT ("\nError: Cannot open file %s\n"), pathname);
+      result->store (0, NULL);
+      result->store (1, sb.toString ()); // failure
+      free (contents);
+    }
+  return result;
+}
+
+/**
+ * Writes the file named by the specified path name.
+ * Temporary limitation: file should be "text only" and its size should be less than the 1 MB limit.
+ * If the operation failed, then -1 is returned.
+ * @param const char *pathname
+ * @return int result  (written bytes)
+ */
+int
+dbeWriteFile (const char *pathname, const char *contents)
+{
+  int result = -1; // error
+  size_t len = 0;
+  if (NULL != contents)
+    len = strlen (contents);
+  size_t limit = 1024 * 1024; // Temporary limit: 1 MB
+  if (len > limit) return result;
+  unlink (pathname);
+  mode_t mode = S_IRUSR | S_IWUSR;
+  int fd = open (pathname, O_WRONLY | O_CREAT | O_TRUNC, mode);
+  if (fd >= 0)
+    {  // replace file contents
+      chmod (pathname, /*S_IRUSR || S_IWUSR*/ 0600); // rw for owner only
+      ssize_t bytes = 0;
+      if (len > 0)
+       bytes = write (fd, contents, len);
+      close (fd);
+      result = (int) bytes;
+    }
+  return result;
+}
+
+/**
+ * Gets list of running processes according to the specified format
+ * Supported formats:
+ * "/bin/ps -ef" - see 'man ps' for details
+ * @param format
+ * @return char * processes
+ */
+char *
+dbeGetRunningProcesses (const char *format)
+{
+  if (format != NULL)
+    return dbe_get_processes (format);
+  return dbe_strdup (NTXT (""));
+}
+
+//
+// Open experiment
+//
+char *
+dbeOpenExperimentList (int /* dbevindex */, Vector<Vector<char*>*> *groups,
+                      bool sessionRestart)
+{
+  if (sessionRestart)
+    dbeSession->reset ();
+  char *errstr;
+  // Open experiments
+  try
+    {
+      errstr = dbeSession->setExperimentsGroups (groups);
+    }
+  catch (ExperimentLoadCancelException *)
+    {
+      errstr = dbe_strdup (NTXT ("Experiment Load Cancelled"));
+    }
+  return errstr;
+}
+
+//
+// Drop experiments
+//
+char *
+dbeDropExperiment (int /* dbevindex */, Vector<int> *drop_index)
+{
+  for (int i = drop_index->size () - 1; i >= 0; i--)
+    {
+      char *ret = dbeSession->drop_experiment (drop_index->fetch (i));
+      if (ret != NULL)
+         return ret;
+    }
+  return NULL;
+}
+
+/**
+ * Read .er.rc file from the specified location
+ * @param path
+ * @return
+ */
+char *
+dbeReadRCFile (int dbevindex, char* path)
+{
+  DbeView *dbev = getDbeView (dbevindex);
+  char *err_msg = dbev->get_settings ()->read_rc (path);
+  return err_msg;
+}
+
+char *
+dbeSetExperimentsGroups (Vector<Vector<char*>*> *groups)
+{
+  int cmp_mode = dbeSession->get_settings ()->get_compare_mode ();
+  if (groups->size () < 2)
+    cmp_mode = CMP_DISABLE;
+  else if (cmp_mode == CMP_DISABLE)
+    cmp_mode = CMP_ENABLE;
+  for (int i = 0;; i++)
+    {
+      DbeView *dbev = dbeSession->getView (i);
+      if (dbev == NULL)
+       break;
+      dbev->get_settings ()->set_compare_mode (cmp_mode);
+    }
+  char *err_msg = dbeSession->setExperimentsGroups (groups);
+
+  // automatically load machine model if applicable
+  dbeDetectLoadMachineModel (0);
+  return err_msg;
+}
+
+Vector<Vector<char*>*> *
+dbeGetExperimensGroups ()
+{
+  Vector<Vector<char*>*> *grops = dbeSession->getExperimensGroups ();
+  return grops;
+}
+
+Vector<int> *
+dbeGetFounderExpId (Vector<int> *expIds)
+{
+  Vector<int> *ret = new Vector<int>(expIds->size ());
+  for (int i = 0; i < expIds->size (); i++)
+    {
+      int expId = expIds->fetch (i);
+      Experiment *exp = dbeSession->get_exp (expId);
+      if (exp != NULL)
+       {
+         int founderExpId = exp->getBaseFounder ()->getExpIdx ();
+         ret->store (i, founderExpId);
+       }
+      else
+       ret->store (i, -1);
+    }
+  return ret;
+}
+
+Vector<int> *
+dbeGetUserExpId (Vector<int> *expIds)
+{
+  // returns "User Visible" ids used for EXPID filters and timeline processes
+  Vector<int> *ret = new Vector<int>(expIds->size ());
+  for (int i = 0; i < expIds->size (); i++)
+    {
+      int expId = expIds->fetch (i);
+      Experiment *exp = dbeSession->get_exp (expId);
+      if (exp != NULL)
+       {
+         int userExpId = exp->getUserExpId ();
+         ret->store (i, userExpId);
+       }
+      else
+       ret->store (i, -1);
+    }
+  return ret;
+}
+
+//
+// Get experiment groupid
+//
+Vector<int> *
+dbeGetExpGroupId (Vector<int> *expIds)
+{
+  Vector<int> *ret = new Vector<int>(expIds->size ());
+  for (int i = 0; i < expIds->size (); i++)
+    {
+      int expId = expIds->fetch (i);
+      Experiment *exp = dbeSession->get_exp (expId);
+      if (exp != NULL)
+       {
+         int gId = exp->groupId;
+         ret->store (i, gId);
+       }
+      else
+       ret->store (i, -1);
+    }
+  return ret;
+}
+
+Vector<char*> *
+dbeGetExpsProperty (const char *prop_name)
+{
+  long nexps = dbeSession->nexps ();
+  if (prop_name == NULL || nexps == 0)
+    return NULL;
+  Vector<char*> *list = new Vector<char*>(nexps);
+  StringBuilder sb;
+  int empty = 1;
+  int prop = 99;
+  if (strcasecmp (prop_name, NTXT ("ERRORS")) == 0)
+    prop = 1;
+  else if (strcasecmp (prop_name, NTXT ("WARNINGS")) == 0)
+    prop = 2;
+  if (prop < 3)
+    {
+      for (long i = 0; i < nexps; i++)
+       {
+         Experiment *exp = dbeSession->get_exp (i);
+         char *nm = exp->get_expt_name ();
+         sb.setLength (0);
+         for (Emsg *emsg = (prop == 1) ? exp->fetch_errors () : exp->fetch_warnings ();
+                 emsg; emsg = emsg->next)
+           sb.appendf (NTXT ("%s: %s\n"), STR (nm), STR (emsg->get_msg ()));
+         char *s = NULL;
+         if (sb.length () > 0)
+           {
+             s = sb.toString ();
+             empty = 0;
+           }
+         list->append (s);
+       }
+    }
+  if (empty)
+    {
+      delete list;
+      list = NULL;
+    }
+  return list;
+}
+
+//
+// Get experiment names
+//
+Vector<char*> *
+dbeGetExpName (int /*dbevindex*/)
+{
+  int size = dbeSession->nexps ();
+  if (size == 0)
+    return NULL;
+  // Initialize Java String array
+  Vector<char*> *list = new Vector<char*>(size);
+
+  // Get experiment names
+  for (int i = 0; i < size; i++)
+    {
+      Experiment *texp = dbeSession->get_exp (i);
+      char *buf = dbe_sprintf (NTXT ("%s [%s]"), texp->get_expt_name (),
+                              texp->utargname != NULL ? texp->utargname : GTXT ("(unknown)"));
+      list->store (i, buf);
+    }
+  return list;
+}
+
+//
+// Get experiment state
+//
+Vector<int> *
+dbeGetExpState (int /* dbevindex */)
+{
+  int size = dbeSession->nexps ();
+  if (size == 0)
+    return NULL;
+  // Initialize Java array
+  Vector<int> *state = new Vector<int>(size);
+
+  // Get experiment state
+  for (int i = 0; i < size; i++)
+    {
+      Experiment *exp = dbeSession->get_exp (i);
+      int set = EXP_SUCCESS;
+      if (exp->get_status () == Experiment::FAILURE)
+       set |= EXP_FAILURE;
+      if (exp->get_status () == Experiment::INCOMPLETE)
+       set |= EXP_INCOMPLETE;
+      if (exp->broken)
+       set |= EXP_BROKEN;
+      if (exp->obsolete)
+       set |= EXP_OBSOLETE;
+      state->store (i, set);
+    }
+  return state;
+}
+
+//
+// Get enabled experiment indices
+//
+Vector<bool> *
+dbeGetExpEnable (int dbevindex)
+{
+  DbeView *dbev = getDbeView (dbevindex);
+  int size = dbeSession->nexps ();
+  if (dbev == NULL || size == 0)
+    return NULL;
+
+  // Get enabled experiment
+  Vector<bool> *enable = new Vector<bool>(size);
+  for (int i = 0; i < size; i++)
+    {
+      bool val = dbev->get_exp_enable (i) && !dbeSession->get_exp (i)->broken;
+      enable->store (i, val);
+    }
+  return enable;
+}
+
+//
+// Get enabled experiment indices
+//
+bool
+dbeSetExpEnable (int dbevindex, Vector<bool> *enable)
+{
+  DbeView *dbev = getDbeView (dbevindex);
+  bool ret = false;
+  int size = dbeSession->nexps ();
+  if (dbev == NULL || size == 0)
+    return false;
+
+  // set enable, as per input vector
+  for (int i = 0; i < size; i++)
+    if (!dbeSession->get_exp (i)->broken
+       && dbev->get_exp_enable (i) != enable->fetch (i))
+      {
+       dbev->set_exp_enable (i, enable->fetch (i));
+       ret = true;
+      }
+  return ret;
+}
+
+//
+// Get experiment info
+//
+Vector<char*> *
+dbeGetExpInfo (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  int size = dbeSession->nexps ();
+  if (size == 0)
+    return NULL;
+
+  // Initialize Java String array
+  Vector<char*> *list = new Vector<char*>(size * 2 + 1);
+
+  // Get experiment names
+  Vector<LoadObject*> *text_segments = dbeSession->get_text_segments ();
+  char *msg = pr_load_objects (text_segments, NTXT (""));
+  delete text_segments;
+  list->store (0, msg);
+  int k = 1;
+  for (int i = 0; i < size; i++)
+    {
+      Experiment *exp = dbeSession->get_exp (i);
+      char *msg0 = pr_mesgs (exp->fetch_notes (), NTXT (""), NTXT (""));
+      char *msg1 = pr_mesgs (exp->fetch_errors (), GTXT ("No errors\n"), NTXT (""));
+      char *msg2 = pr_mesgs (exp->fetch_warnings (), GTXT ("No warnings\n"), NTXT (""));
+      char *msg3 = pr_mesgs (exp->fetch_comments (), NTXT (""), NTXT (""));
+      char *msg4 = pr_mesgs (exp->fetch_pprocq (), NTXT (""), NTXT (""));
+      msg = dbe_sprintf (NTXT ("%s%s%s%s"), msg1, msg2, msg3, msg4);
+      list->store (k++, msg0);
+      list->store (k++, msg);
+      free (msg1);
+      free (msg2);
+      free (msg3);
+      free (msg4);
+    }
+  return list;
+}
+
+bool
+dbeGetViewModeEnable ()
+{
+  return dbeSession->has_ompavail () || dbeSession->has_java ();
+}
+
+bool
+dbeGetJavaEnable ()
+{
+  return dbeSession->has_java ();
+}
+
+int
+dbeUpdateNotes (int dbevindex, int exp_id, int type, char* text, bool handle_file)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  int size = dbeSession->nexps ();
+  if (size == 0)
+    return -1;
+  Experiment *exp = dbeSession->get_exp (exp_id);
+  return (type == 0) ? exp->save_notes (text, handle_file) : exp->delete_notes (handle_file);
+}
+
+//
+// Get load object names
+//
+Vector<char*> *
+dbeGetLoadObjectName (int /* dbevindex */)
+{
+  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+  int size = lobjs->size ();
+
+  // Initialize Java String array
+  Vector<char*> *list = new Vector<char*>(size);
+
+  // Get load object names
+  LoadObject *lo;
+  int index;
+  Vec_loop (LoadObject*, lobjs, index, lo)
+  {
+    list->store (index, dbe_strdup (lo->get_name ()));
+  }
+  delete lobjs;
+  return list;
+}
+
+// XXX Will use later when order has to be passed too,
+// Get complete List of tabs
+//
+Vector<void*> *
+dbeGetTabList (int /* dbevindex */)
+{
+  //DbeView *dbev = getDbeView (dbevindex);
+  //Vector<void*> *tabs = dbeSession->get_TabList();
+  //return tabs;
+  return NULL;
+}
+
+//
+// Returns list of available tabs
+//
+Vector<void*> *
+dbeGetTabListInfo (int dbevindex)
+{
+  int index;
+  DispTab *dsptab;
+  DbeView *dbev = getDbeView (dbevindex);
+
+  // make sure the tabs are initialized properly
+  dbev->get_settings ()->proc_tabs (theDbeApplication->rdtMode);
+  Vector<DispTab*> *tabs = dbev->get_TabList ();
+
+  // Get number of available tabs
+  int size = 0;
+  Vec_loop (DispTab*, tabs, index, dsptab)
+  {
+    if (!dsptab->available)
+      continue;
+    size++;
+  }
+  Vector<void*> *data = new Vector<void*>(2);
+  Vector<int> *typelist = new Vector<int>(size);
+  Vector<char*> *cmdlist = new Vector<char*>(size);
+  Vector<int> *ordlist = new Vector<int>(size);
+
+  // Build list of avaliable tabs
+  int i = 0;
+
+  Vec_loop (DispTab*, tabs, index, dsptab)
+  {
+    if (!dsptab->available)
+      continue;
+    typelist->store (i, dsptab->type);
+    cmdlist->store (i, dbe_strdup (Command::get_cmd_str (dsptab->cmdtoken)));
+    ordlist->store (i, dsptab->order);
+    i++;
+  }
+  data->store (0, typelist);
+  data->store (1, cmdlist);
+  data->store (2, ordlist);
+  return data;
+}
+
+// Return visibility state for all available tabs
+//
+Vector<bool> *
+dbeGetTabSelectionState (int dbevindex)
+{
+  int index;
+  DispTab *dsptab;
+  DbeView *dbev = getDbeView (dbevindex);
+  Vector<DispTab*> *tabs = dbev->get_TabList ();
+
+  // Get number of available tabs
+  int size = 0;
+  Vec_loop (DispTab*, tabs, index, dsptab)
+  {
+    if (!dsptab->available)
+      continue;
+    size++;
+  }
+  Vector<bool> *states = new Vector<bool>(size);
+
+  // Get visibility bit for all available tabs
+  int i = 0;
+  Vec_loop (DispTab*, tabs, index, dsptab)
+  {
+    if (!dsptab->available)
+      continue;
+    states->store (i++, dsptab->visible);
+  }
+  return states;
+}
+
+// Set visibility bit for a tab
+void
+dbeSetTabSelectionState (int dbevindex, Vector<bool> *selected)
+{
+  int index;
+  DispTab *dsptab;
+  DbeView *dbev = getDbeView (dbevindex);
+  Vector<DispTab*> *tabs = dbev->get_TabList ();
+  int i = 0;
+  Vec_loop (DispTab*, tabs, index, dsptab)
+  {
+    if (!dsptab->available)
+      continue;
+    dsptab->visible = selected->fetch (i++);
+  }
+}
+
+// Return visibility state for all available MemObj tabs
+Vector<bool> *
+dbeGetMemTabSelectionState (int dbevindex)
+{
+  int index;
+  bool dsptab;
+  DbeView *dbev = getDbeView (dbevindex);
+  Vector<bool> *memtabs = dbev->get_MemTabState ();
+
+  // set the output vector
+  int size = memtabs->size ();
+  Vector<bool> *states = new Vector<bool>(size);
+
+  // Get visibility bit for all available tabs
+  int i = 0;
+  Vec_loop (bool, memtabs, index, dsptab)
+  {
+    states->store (i++, dsptab);
+  }
+  return states;
+}
+
+// Set visibility bit for a memory tab
+//
+void
+dbeSetMemTabSelectionState (int dbevindex, Vector<bool> *selected)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  dbev->set_MemTabState (selected);
+}
+
+// Return visibility state for all available index tabs
+Vector<bool> *
+dbeGetIndxTabSelectionState (int dbevindex)
+{
+  int index;
+  bool dsptab;
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Vector<bool> *indxtabs = dbev->get_IndxTabState ();
+
+  // set the output vector
+  int size = indxtabs->size ();
+  Vector<bool> *states = new Vector<bool>(size);
+
+  // Get visibility bit for all available tabs
+  int i = 0;
+  Vec_loop (bool, indxtabs, index, dsptab)
+  {
+    states->store (i++, dsptab);
+  }
+  return states;
+}
+
+// Set visibility bit for a index tab
+void
+dbeSetIndxTabSelectionState (int dbevindex, Vector<bool> *selected)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  dbev->set_IndxTabState (selected);
+}
+
+//
+// Get search path
+//
+Vector<char*> *
+dbeGetSearchPath (int /*dbevindex*/)
+{
+  Vector<char*> *path = dbeSession->get_search_path ();
+  int size = path->size ();
+  Vector<char*> *list = new Vector<char*>(size);
+  int index;
+  char *name;
+  Vec_loop (char*, path, index, name)
+  {
+    list->store (index, dbe_strdup (name));
+  }
+  return list;
+}
+
+//
+// Set search path
+//
+void
+dbeSetSearchPath (int /*dbevindex*/, Vector<char*> *path)
+{
+  dbeSession->set_search_path (path, true);
+  return;
+}
+
+//
+// Get pathmaps
+//
+Vector<void*> *
+dbeGetPathmaps (int /*dbevindex*/)
+{
+  int index;
+  pathmap_t *pthmap;
+  Vector<pathmap_t*> *path = dbeSession->get_pathmaps ();
+  int size = path->size ();
+  Vector<void*> *data = new Vector<void*>(2);
+  Vector<char*> *oldlist = new Vector<char*>(size);
+  Vector<char*> *newlist = new Vector<char*>(size);
+
+  int i = 0;
+  Vec_loop (pathmap_t*, path, index, pthmap)
+  {
+    oldlist->store (i, dbe_strdup (pthmap->old_prefix));
+    newlist->store (i, dbe_strdup (pthmap->new_prefix));
+    i++;
+  }
+  data->store (0, oldlist);
+  data->store (1, newlist);
+  return data;
+} // dbeGetPathmaps
+
+char *
+dbeSetPathmaps (Vector<char*> *from, Vector<char*> *to)
+{
+  if (from == NULL || to == NULL || from->size () != to->size ())
+    return dbe_strdup ("dbeSetPathmaps: size of 'from' does not match for size of 'to'\n");
+  Vector<pathmap_t*> *newPath = new Vector<pathmap_t*>(from->size ());
+  for (int i = 0, sz = from->size (); i < sz; i++)
+    {
+      char *err = Settings::add_pathmap (newPath, from->get (i), to->get (i));
+      if (err)
+       {
+         newPath->destroy ();
+         delete newPath;
+         return err;
+       }
+    }
+  dbeSession->set_pathmaps (newPath);
+  return NULL;
+}
+
+//
+// Add pathmap
+char *
+dbeAddPathmap (int /* dbevindex */, char *from, char *to)
+{
+  Vector<pathmap_t*> *pmp = dbeSession->get_pathmaps ();
+  char *err = Settings::add_pathmap (pmp, from, to);
+  return err;
+}
+
+//
+// Get error/warning string of data
+char *
+dbeGetMsg (int dbevindex, int type)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  char *msgstr = NULL;
+  if (type == ERROR_MSG)
+    msgstr = dbev->get_error_msg ();
+  else if (type == WARNING_MSG)
+    msgstr = dbev->get_warning_msg ();
+  else if (type == PSTAT_MSG)
+    msgstr = dbev->get_processor_msg (PSTAT_MSG);
+  else if (type == PWARN_MSG)
+    msgstr = dbev->get_processor_msg (PWARN_MSG);
+  return msgstr ? dbe_strdup (msgstr) : NULL;
+}
+
+// Create a DbeView, given new index, and index of view to clone
+int
+dbeInitView (int id, int cloneid)
+{
+  return dbeSession->createView (id, cloneid);
+}
+
+
+// Delete a DbeView
+void
+dbeDeleteView (int dbevindex)
+{
+  dbeSession->dropView (dbevindex);
+  return;
+} // dbeDeleteView
+
+MetricList *
+dbeGetMetricListV2 (int dbevindex, MetricType mtype,
+                   Vector<int> *type, Vector<int> *subtype, Vector<bool> *sort,
+                   Vector<int> *vis, Vector<char*> *cmd,
+                   Vector<char*> *expr_spec, Vector<char*> *legends)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  MetricList *mlist = new MetricList (mtype);
+  for (int i = 0, msize = type->size (); i < msize; i++)
+    {
+      BaseMetric *bm = dbev->register_metric_expr ((BaseMetric::Type) type->fetch (i),
+                                                  cmd->fetch (i),
+                                                  expr_spec->fetch (i));
+      Metric *m = new Metric (bm, (Metric::SubType) subtype->fetch (i));
+      m->set_raw_visbits (vis->fetch (i));
+      if (m->legend == NULL)
+       m->legend = dbe_strdup (legends->fetch (i));
+      mlist->append (m);
+      if (sort->fetch (i))
+       {
+         mlist->set_sort_ref_index (i);
+       }
+    }
+  return mlist;
+}
+
+static Vector<void*> *
+dbeGetMetricList (MetricList *mlist)
+{
+  int clock_val = dbeSession->get_clock (-1);
+  Vector<Metric*> *items = mlist->get_items ();
+  int size = items->size ();
+
+  Vector<int> *type = new Vector<int>(size);
+  Vector<int> *subtype = new Vector<int>(size);
+  Vector<int> *clock = new Vector<int>(size);
+  Vector<int> *flavors = new Vector<int>(size);
+  Vector<int> *vis = new Vector<int>(size);
+  Vector<bool> *sorted = new Vector<bool>(size);
+  Vector<int> *value_styles = new Vector<int>(size);
+  Vector<char*> *aux = new Vector<char*>(size);
+  Vector<char*> *name = new Vector<char*>(size);
+  Vector<char*> *abbr = new Vector<char*>(size);
+  Vector<char*> *comd = new Vector<char*>(size);
+  Vector<char*> *unit = new Vector<char*>(size);
+  Vector<char*> *user_name = new Vector<char*>(size);
+  Vector<char*> *expr_spec = new Vector<char*>(size);
+  Vector<char*> *legend = new Vector<char*>(size);
+  Vector<int> *valtype = new Vector<int>(size);
+  Vector<char*> *data_type_name = new Vector<char*>(size);
+  Vector<char*> *data_type_uname = new Vector<char*>(size);
+  Vector<char*> *short_desc = new Vector<char*>(size);
+
+  int sort_index = mlist->get_sort_ref_index ();
+  // Fill metric elements
+  for (int i = 0; i < size; i++)
+    {
+      Metric *m = items->fetch (i);
+      type->append (m->get_type ());
+      subtype->append (m->get_subtype ());
+      flavors->append (m->get_flavors ());
+      abbr->append (dbe_strdup (m->get_abbr ()));
+      char *s = m->get_abbr_unit ();
+      if ((m->get_visbits () & VAL_RATIO) != 0)
+       s = NULL;
+      unit->append (dbe_strdup (s ? s : NTXT ("")));
+      value_styles->append (m->get_value_styles ());
+      vis->append (m->get_visbits ());
+      sorted->append (i == sort_index);
+      clock->append (m->get_type () == Metric::HWCNTR ? clock_val
+                    : m->get_clock_unit ());
+      aux->append (dbe_strdup (m->get_aux ()));
+      name->append (dbe_strdup (m->get_name ()));
+      comd->append (dbe_strdup (m->get_cmd ()));
+      user_name->append (dbe_strdup (m->get_username ()));
+      expr_spec->append (dbe_strdup (m->get_expr_spec ()));
+      legend->append (dbe_strdup (m->legend));
+      valtype->append (m->get_vtype2 ());
+
+      char* _data_type_name = NULL;
+      char* _data_type_uname = NULL;
+      int data_type = m->get_packet_type ();
+      if (data_type >= 0 && data_type < DATA_LAST)
+       {
+         _data_type_name = dbe_strdup (get_prof_data_type_name (data_type));
+         _data_type_uname = dbe_strdup (get_prof_data_type_uname (data_type));
+       }
+      data_type_name->append (_data_type_name);
+      data_type_uname->append (_data_type_uname);
+
+      char* _short_desc = NULL;
+      if (m->get_type () == Metric::HWCNTR)
+       {
+         Hwcentry * hwctr = m->get_hw_ctr ();
+         if (hwctr)
+           _short_desc = dbe_strdup (hwctr->short_desc);
+       }
+      short_desc->append (_short_desc);
+    }
+
+  // Set Java array
+  Vector<void*> *data = new Vector<void*>(16);
+  data->append (type);
+  data->append (subtype);
+  data->append (clock);
+  data->append (flavors);
+  data->append (value_styles);
+  data->append (user_name);
+  data->append (expr_spec);
+  data->append (aux);
+  data->append (name);
+  data->append (abbr);
+  data->append (comd);
+  data->append (unit);
+  data->append (vis);
+  data->append (sorted);
+  data->append (legend);
+  data->append (valtype);
+  data->append (data_type_name);
+  data->append (data_type_uname);
+  data->append (short_desc);
+  return data;
+}
+
+Vector<void*> *
+dbeGetRefMetricsV2 ()
+{
+  MetricList *mlist = new MetricList (MET_NORMAL);
+  Vector<BaseMetric*> *base_metrics = dbeSession->get_base_reg_metrics ();
+  for (long i = 0, sz = base_metrics->size (); i < sz; i++)
+    {
+      BaseMetric *bm = base_metrics->fetch (i);
+      Metric *m;
+      if (bm->get_flavors () & Metric::EXCLUSIVE)
+       {
+         m = new Metric (bm, Metric::EXCLUSIVE);
+         m->enable_all_visbits ();
+         mlist->append (m);
+       }
+      else if (bm->get_flavors () & BaseMetric::STATIC)
+       {
+         m = new Metric (bm, BaseMetric::STATIC);
+         m->enable_all_visbits ();
+         mlist->append (m);
+       }
+    }
+  Vector<void*> *data = dbeGetMetricList (mlist);
+  delete mlist;
+  return data;
+}
+
+Vector<void*> *
+dbeGetCurMetricsV2 (int dbevindex, MetricType mtype)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  MetricList *mlist = dbev->get_metric_list (mtype);
+  Vector<void*> *data = dbeGetMetricList (mlist);
+  return data;
+}
+
+// YXXX we should refactor Metrics/BaseMetrics so that it no longer uses VAL_VALUE to enable time.
+static int
+convert_visbits_to_gui_checkbox_bits (BaseMetric *bm, const int visbits)
+{
+  // The purpose of this function is to handle the following case:
+  //    When bm->get_value_styles() supports VAL_TIMEVAL but not VAL_VALUE
+  //        Metric and BaseMetric use (visbits&VAL_VALUE) to enable time.
+  //    However, the Overview expects the VAL_TIMEVAL bit to enable time.
+  // Inputs: visbits as returned by BaseMetric->get_default_visbits();
+  // Returns: valuebits, as used for checks in GUI checkboxes
+  int valuebits = visbits;
+  const int value_styles = bm->get_value_styles ();
+  if ((value_styles & VAL_TIMEVAL) && // supports time
+      !(value_styles & VAL_VALUE))
+    { // but not value
+      unsigned mask = ~(VAL_VALUE | VAL_TIMEVAL);
+      valuebits = (unsigned) valuebits & mask; // clear bits
+      if (visbits & VAL_VALUE)
+       valuebits |= VAL_TIMEVAL; // set VAL_TIMEVAL
+      if (visbits & VAL_TIMEVAL)
+       valuebits |= VAL_TIMEVAL; // weird, this should never happen.
+    }
+  return valuebits;
+}
+
+static Vector<void*> *
+dbeGetMetricTreeNode (BaseMetricTreeNode* curr, MetricList *mlist,
+                     bool include_unregistered, bool has_clock_profiling_data)
+{
+  Vector<void*> *data = new Vector<void*>(2);
+
+  // ----- fields
+  Vector<void*> *fields = new Vector<void*>();
+  Vector<char*> *name = new Vector<char*>(1);
+  Vector<char*> *username = new Vector<char*>(1);
+  Vector<char*> *description = new Vector<char*>(1);
+  Vector<int> * flavors = new Vector<int>(1);
+  Vector<int> * vtype = new Vector<int>(1);
+  Vector<int> * vstyles_capable = new Vector<int>(1);
+
+  // Specifies which default styles should be enabled when a metric is enabled.
+  // Also, specifies if metric should start enabled
+  Vector<int> *vstyles_e_defaults = new Vector<int>(1);
+  Vector<int> *vstyles_i_defaults = new Vector<int>(1);
+  Vector<bool> *registered = new Vector<bool>(1);
+  Vector<bool> *aggregation = new Vector<bool>(1);
+  Vector<bool> *has_value = new Vector<bool>(1);
+  Vector<char*> *unit = new Vector<char*>(1);
+  Vector<char*> *unit_uname = new Vector<char*>(1);
+
+  char *_name = NULL;
+  char *_username = NULL;
+  char *_description = dbe_strdup (curr->get_description ());
+
+  // BaseMetric fields
+  int _flavors = 0; // SubType bitmask: (e.g. EXCLUSIVE)
+  int _vtype = 0; // ValueTag: e.g. VT_INT, VT_FLOAT, ...
+  int _vstyles_capable = 0; // ValueType bitmask, e.g. VAL_TIMEVAL
+  int _vstyles_e_default_values = 0; // default visibility settings, exclusive/static
+  int _vstyles_i_derault_values = 0; // default visibility settings, inclusive
+  bool _registered = curr->is_registered ()
+         || curr->get_num_registered_descendents () > 0;
+  bool _aggregation = curr->is_composite_metric ()
+         && curr->get_num_registered_descendents () > 0;
+  bool _has_value = false; //not used yet; for nodes that don't have metrics
+  char *_unit = NULL;
+  char *_unit_uname = NULL;
+
+  BaseMetric *bm = curr->get_BaseMetric ();
+  if (bm)
+    {
+      _name = dbe_strdup (bm->get_cmd ());
+      _username = dbe_strdup (bm->get_username ());
+      if (!include_unregistered && !curr->is_registered ())
+       abort ();
+      _flavors = bm->get_flavors ();
+      _vtype = bm->get_vtype ();
+      _vstyles_capable = bm->get_value_styles ();
+      int e_visbits = bm->get_default_visbits (BaseMetric::EXCLUSIVE);
+      int i_visbits = bm->get_default_visbits (BaseMetric::INCLUSIVE);
+      _vstyles_e_default_values = convert_visbits_to_gui_checkbox_bits (bm, e_visbits);
+      _vstyles_i_derault_values = convert_visbits_to_gui_checkbox_bits (bm, i_visbits);
+      // not all metrics shown in er_print cmd line should be selected in the GUI at startup:
+      if (has_clock_profiling_data && bm->get_hw_ctr ())
+       {
+         bool hide = true; // by default, hide HWCs
+         if (dbe_strcmp (bm->get_hw_ctr ()->name, NTXT ("c_stalls")) == 0 ||
+             dbe_strcmp (bm->get_hw_ctr ()->name, NTXT ("K_c_stalls")) == 0)
+           {
+             bool is_time = (bm->get_value_styles () & VAL_TIMEVAL) != 0;
+             if (is_time)
+               // By default, show time variant of c_stalls
+               hide = false;
+           }
+         if (hide)
+           {
+             _vstyles_e_default_values |= VAL_HIDE_ALL;
+             _vstyles_i_derault_values |= VAL_HIDE_ALL;
+           }
+       }
+    }
+  else
+    {
+      // not a base metric
+      _name = dbe_strdup (curr->get_name ());
+      _username = dbe_strdup (curr->get_user_name ());
+     if (curr->get_unit ())
+       { // represents a value
+         _has_value = true;
+         _unit = dbe_strdup (curr->get_unit ());
+         _unit_uname = dbe_strdup (curr->get_unit_uname ());
+       }
+    }
+  name->append (_name); // unique id string (dmetrics cmd)
+  username->append (_username); // user-visible name
+  description->append (_description);
+  flavors->append (_flavors); // SubType bitmask: (e.g. EXCLUSIVE)
+  vtype->append (_vtype); // ValueTag: e.g. VT_INT, VT_FLOAT, ...
+  vstyles_capable->append (_vstyles_capable); // ValueType bitmask, e.g. VAL_TIMEVAL
+  vstyles_e_defaults->append (_vstyles_e_default_values);
+  vstyles_i_defaults->append (_vstyles_i_derault_values);
+  registered->append (_registered); // is a "live" metric
+  aggregation->append (_aggregation); // value derived from children nodes
+  has_value->append (_has_value); // value generated from other source
+  unit->append (_unit); // See BaseMetric.h, e.g. UNIT_SECONDS
+  unit_uname->append (_unit_uname); //See BaseMetric.h,
+
+  fields->append (name);
+  fields->append (username);
+  fields->append (description);
+  fields->append (flavors);
+  fields->append (vtype);
+  fields->append (vstyles_capable);
+  fields->append (vstyles_e_defaults);
+  fields->append (vstyles_i_defaults);
+  fields->append (registered);
+  fields->append (aggregation);
+  fields->append (has_value);
+  fields->append (unit);
+  fields->append (unit_uname);
+  data->append (fields);
+
+  // ----- children
+  Vector<BaseMetricTreeNode*> *children = curr->get_children ();
+  int num_children = children->size ();
+  Vector<void*> *children_list = new Vector<void*>(num_children);
+  BaseMetricTreeNode *child_node;
+  int index;
+
+  Vec_loop (BaseMetricTreeNode*, children, index, child_node)
+  {
+    if (include_unregistered /* fetch everything */
+       || child_node->is_registered ()
+       || child_node->get_num_registered_descendents () > 0)
+      {
+       //Special case for metrics that aren't registered
+       // but have registered children
+       // Linux example: Total Time is unregistered, CPU Time is registered
+       if (!include_unregistered && /* not fetching everything */
+           !child_node->is_registered () &&
+           (child_node->get_BaseMetric () != NULL ||
+            child_node->is_composite_metric ()))
+         {
+           Vector<BaseMetricTreeNode*> *registered_descendents =
+                   new Vector<BaseMetricTreeNode*>();
+           child_node->get_nearest_registered_descendents (registered_descendents);
+           int idx2;
+           BaseMetricTreeNode*desc_node;
+           Vec_loop (BaseMetricTreeNode*, registered_descendents, idx2, desc_node)
+           {
+             Vector<void*> *desc_data;
+             desc_data = dbeGetMetricTreeNode (desc_node, mlist,
+                               include_unregistered, has_clock_profiling_data);
+             children_list->append (desc_data);
+           }
+           delete registered_descendents;
+           continue;
+         }
+       Vector<void*> *child_data;
+       child_data = dbeGetMetricTreeNode (child_node, mlist,
+                               include_unregistered, has_clock_profiling_data);
+       children_list->append (child_data);
+      }
+  }
+  data->append (children_list);
+  return data;
+}
+
+Vector<void*> *
+dbeGetRefMetricTree (int dbevindex, bool include_unregistered)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  MetricList *mlist = dbev->get_metric_list (MET_NORMAL);
+  bool has_clock_profiling_data = false;
+  for (long i = 0, sz = mlist->get_items ()->size (); i < sz; i++)
+    {
+      Metric *m = mlist->get_items ()->fetch (i);
+      if (m->get_packet_type () == DATA_CLOCK)
+       {
+         has_clock_profiling_data = true;
+         break;
+       }
+    }
+  BaseMetricTreeNode *curr = dbeSession->get_reg_metrics_tree ();
+  return dbeGetMetricTreeNode (curr, mlist, include_unregistered, has_clock_profiling_data);
+}
+
+static Vector<void*> *
+dbeGetTableDataV2Data (DbeView *dbev, Hist_data *data);
+
+static Vector<void*> *dbeGetTableDataOneColumn (Hist_data *data, int met_ind);
+static Vector<void*> *
+dbeGetTableDataOneColumn (DbeView *dbev, Vector<Hist_data::HistItem*> *data,
+                         ValueTag vtype, int metricColumnNumber);
+
+static hrtime_t
+dbeCalcGroupDuration (int grInd)
+{
+  int thisGroupSize = 1;
+  hrtime_t max_time = 0;
+  Experiment *exp;
+  if (dbeSession->expGroups->size () > 0)
+    {
+      ExpGroup *grp = dbeSession->expGroups->fetch (grInd);
+      thisGroupSize = grp->exps->size ();
+      for (int ii = 0; ii < thisGroupSize; ii++)
+       {
+         exp = grp->exps->fetch (ii);
+         Vector<DataDescriptor*> *ddscr = exp->getDataDescriptors ();
+         delete ddscr;// getDataDescriptors() forces reading of experiment data
+         if (exp != NULL)
+           {
+             hrtime_t tot_time = exp->getLastEvent () - exp->getStartTime ()
+                     + exp->getRelativeStartTime ();
+             if (max_time < tot_time)
+               max_time = tot_time;
+           }
+       }
+    }
+  else
+    {
+      exp = dbeSession->get_exp (0);
+      if (exp != NULL)
+       max_time = exp->getLastEvent () - exp->getStartTime ();
+    }
+  return max_time; //nanoseconds
+}
+
+static hrtime_t
+dbeCalcGroupGCDuration (int grInd)
+{
+  int thisGroupSize = 1;
+  hrtime_t tot_time = 0;
+  Experiment *exp;
+  if (dbeSession->expGroups->size () > 0)
+    {
+      ExpGroup *grp = dbeSession->expGroups->fetch (grInd);
+      thisGroupSize = grp->exps->size ();
+      for (int ii = 0; ii < thisGroupSize; ii++)
+       {
+         exp = grp->exps->fetch (ii);
+         Vector<DataDescriptor*> *ddscr = exp->getDataDescriptors ();
+         delete ddscr; // getDataDescriptors() forces reading of experiment data
+         if (exp != NULL)
+           tot_time += exp->getGCDuration ();
+       }
+    }
+  else
+    {
+      exp = dbeSession->get_exp (0);
+      if (exp != NULL)
+       tot_time = exp->getGCDuration ();
+    }
+  return tot_time; //nanoseconds
+}
+
+Vector<void*> *
+dbeGetRefMetricTreeValues (int dbevindex, Vector<char *> *metric_cmds,
+                          Vector<char *> *non_metric_cmds)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  // valueTable will have N "columns" of values, where N is the number of
+  //   requested metrics and non-metrics.
+  // Each column will be a vector with M "rows", where M is the number of
+  //   compare groups.
+  // highlightTable mirrors the structure of valueTable.  Each cell indicates
+  //   if the corresponding valueTable cell is "hot" (interesting)
+  int numMetrics = metric_cmds->size ();
+  int numNonMetrics = non_metric_cmds->size ();
+  int totalColumns = numMetrics + numNonMetrics; // Columns
+  Vector<void*> *valueTable = new Vector<void*>(totalColumns);
+  Vector<void*> *highlightTable = new Vector<void*>(totalColumns);
+
+  // the return value consists of the two tables discussed above.
+  Vector<void*> *rc = new Vector<void*>(2);
+  rc->append (valueTable);
+  rc->append (highlightTable);
+  if (dbeSession->nexps () == 0)
+    { // no experiments are loaded
+      for (int jj = 0; jj < totalColumns; jj++)
+       {
+         Vector<void *> *columnData = new Vector<void *>();
+         valueTable->append (columnData);
+         highlightTable->append (columnData);
+       }
+      return rc;
+    }
+
+  int ngroups = dbeSession->expGroups->size (); // Rows (one per compare group)
+  if (ngroups == 0 || !dbev->comparingExperiments ())
+    ngroups = 1;
+
+  Vector<double> *groupTotalTime = new Vector<double>(ngroups);
+  Vector<double> *groupCpuTime = new Vector<double>(ngroups);
+  // initialize highlight table
+  for (int ii = 0; ii < totalColumns; ii++)
+    { // metrics
+      Vector<bool> *columnData = new Vector<bool>(ngroups);
+      highlightTable->append (columnData);
+      for (int grInd = 0; grInd < ngroups; grInd++)
+       columnData->store (grInd, false); // non-highlight
+    }
+
+  if (numMetrics > 0)
+    {
+      MetricList *bmlist;
+      // set bmlist to list of requested base metrics
+      BaseMetricTreeNode *root = dbeSession->get_reg_metrics_tree ();
+      int index;
+      char *mcmd;
+      Vector<BaseMetric*> *base_metrics = new Vector<BaseMetric*>();
+      Vec_loop (char *, metric_cmds, index, mcmd)
+      {
+       BaseMetricTreeNode *bmt_node = root->find (mcmd);
+       if (!bmt_node)
+         abort (); //YXXX weird
+       BaseMetric * baseNetric = bmt_node->get_BaseMetric ();
+       if (!baseNetric)
+         abort ();
+       base_metrics->append (baseNetric);
+      }
+
+      // MET_INDX will create MetricList of Exclusive metrics
+      bmlist = new MetricList (base_metrics, MET_SRCDIS);
+
+      // Use the Function List to fetch <Total> values
+      // A temporary table, v_totals, stores <total> by group
+      Vector<Hist_data::HistItem *> *v_totals = new Vector<Hist_data::HistItem *>(ngroups);
+      for (int grInd = 0; grInd < ngroups; grInd++)
+       {
+         MetricList *mlist;
+         if (ngroups > 1)
+           mlist = dbev->get_compare_mlist (bmlist, grInd);
+         else
+           mlist = bmlist;
+         if (mlist->size () != numMetrics)
+           abort ();
+
+         Hist_data *data;
+         data = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+                                     Hist_data::ALL);
+         Hist_data::HistItem * totals = data->get_totals ();
+         v_totals->append (totals);
+       }
+
+      // store the Hist_data totals in valueTable
+      {
+       Metric *mitem;
+       int index;
+       Vec_loop (Metric*, bmlist->get_items (), index, mitem)
+       {
+         Vector<void*> * columnData = dbeGetTableDataOneColumn (dbev,
+                                         v_totals, mitem->get_vtype (), index);
+         valueTable->append (columnData);
+       }
+      }
+
+      // 7207285: hack for hwc profiling cycles conversion:
+      {
+       Metric *mitem;
+       int index;
+       Vec_loop (Metric*, bmlist->get_items (), index, mitem)
+       {
+         if (mitem->is_time_val ()
+             && mitem->get_vtype () == VT_ULLONG)
+           {
+             Vector<long long> *cycleValues = (Vector<long long> *)valueTable->fetch (index);
+             Vector<double> *timeValues = new Vector<double>(ngroups);
+             assert (cycleValues->size () == ngroups);
+             for (int grInd = 0; grInd < ngroups; grInd++)
+               {
+                 long long cycles = cycleValues->fetch (grInd);
+                 int expId;
+                 if (dbeSession->expGroups->size () > 0)
+                   {
+                     ExpGroup *gr = dbeSession->expGroups->fetch (grInd);
+                     Experiment *exp = gr->exps->fetch (0);
+                     expId = exp->getExpIdx ();
+                   }
+                 else
+                   expId = -1;
+                 int clock = dbeSession->get_clock (expId);
+                 double time;
+                 if (clock)
+                   time = cycles / (1.e+6 * clock);
+                 else
+                   time = cycles; //weird
+                 timeValues->store (grInd, time);
+               }
+             delete cycleValues;
+             valueTable->store (index, timeValues);
+           }
+       }
+      }
+
+      // Scan metrics for best measure of CPU time
+      int bestCpuTimeIndx = -1;
+      {
+       Metric *mitem;
+       int index;
+       Vec_loop (Metric*, bmlist->get_items (), index, mitem)
+       {
+         BaseMetric::Type type = mitem->get_type ();
+         if (type == BaseMetric::CP_KERNEL_CPU)
+           {
+             bestCpuTimeIndx = index;
+             break; // CP_KERNEL_CPU trumps other measures
+           }
+         if (type == BaseMetric::CP_TOTAL_CPU)
+           {
+             // clock profiling CPU time
+             bestCpuTimeIndx = index;
+             // keep looking in case CP_KERNEL_CPU also exists
+             continue;
+           }
+
+         bool isTime = ((mitem->get_value_styles () & VAL_TIMEVAL) != 0);
+         bool isHwcCycles = (type == BaseMetric::HWCNTR
+                             && (dbe_strcmp (mitem->get_aux (), "cycles") == 0)
+                             && isTime);
+         if (isHwcCycles)
+           if (bestCpuTimeIndx < 0)
+             bestCpuTimeIndx = index;
+       }
+       if (bestCpuTimeIndx >= 0)
+         {
+           Vector<double> *timeValues = (Vector<double> *)valueTable->fetch (bestCpuTimeIndx);
+           if (timeValues->type () == VEC_DOUBLE)
+             for (int grInd = 0; grInd < ngroups; grInd++)
+               {
+                 double time = timeValues->fetch (grInd);
+                 groupCpuTime->append (time);
+               }
+         }
+      }
+
+      // Scan metrics for Total Thread time
+      {
+       Metric *mitem;
+       int index;
+       Vec_loop (Metric*, bmlist->get_items (), index, mitem)
+       {
+         BaseMetric::Type type = mitem->get_type ();
+         if (type == BaseMetric::CP_TOTAL)
+           {
+             Vector<double> *timeValues = (Vector<double> *)valueTable->fetch (index);
+             if (timeValues->type () != VEC_DOUBLE)
+               continue; // weird
+             for (int grInd = 0; grInd < ngroups; grInd++)
+               {
+                 double time = timeValues->fetch (grInd);
+                 groupTotalTime->append (time);
+               }
+             break;
+           }
+       }
+      }
+
+      // highlight metrics based on cpu time
+#define CPUSEC_PERCENT_THRESHOLD            10.0
+#define HWC_OVERFLOWS_PER_CPUSEC_THRESHOLD  15
+      {
+       Metric *mitem;
+       int index;
+       Vec_loop (Metric*, bmlist->get_items (), index, mitem)
+       {
+         BaseMetric::Type type = mitem->get_type ();
+         Vector<bool> * columnHilites = (Vector<bool> *)highlightTable->fetch (index);
+
+         // always highlight the following
+         if (index == bestCpuTimeIndx)
+           {
+             for (int grInd = 0; grInd < ngroups; grInd++)
+               columnHilites->store (grInd, true);
+             continue;
+           }
+
+         // skip certain types
+         bool typeIsCycles = (type == BaseMetric::HWCNTR
+                      && dbe_strcmp (mitem->get_aux (), NTXT ("cycles")) == 0);
+         bool typeIsInsts = (type == BaseMetric::HWCNTR
+                       && dbe_strcmp (mitem->get_aux (), NTXT ("insts")) == 0);
+         if (type == BaseMetric::CP_TOTAL
+             || type == BaseMetric::CP_TOTAL_CPU
+             || type == BaseMetric::CP_LMS_USER
+             || type == BaseMetric::CP_LMS_SYSTEM
+             || type == BaseMetric::CP_LMS_TRAP
+             || type == BaseMetric::CP_LMS_USER_LOCK
+             || type == BaseMetric::CP_LMS_SLEEP
+             || type == BaseMetric::CP_KERNEL_CPU
+             || type == BaseMetric::OMP_WORK
+             || typeIsCycles
+             || typeIsInsts
+             // || type == BaseMetric::CP_TOTAL_WAIT
+             )
+           continue; // types we never highlight
+
+         // for time values, compare against CPUSEC_PERCENT_THRESHOLD
+         bool isTime = ((mitem->get_value_styles () & VAL_TIMEVAL) != 0);
+         if (isTime)
+           {
+             if (groupCpuTime->size () == 0)
+               continue; // no time to use as reference
+             Vector<double> *timeValues = (Vector<double> *)valueTable->fetch (index);
+             if (timeValues->type () != VEC_DOUBLE)
+               continue; // weird
+             for (int grInd = 0; grInd < ngroups; grInd++)
+               {
+                 double thistime = timeValues->fetch (grInd);
+                 double usertime = groupCpuTime->fetch (grInd);
+                 if (thistime / (CPUSEC_PERCENT_THRESHOLD / 100) > usertime)
+                   columnHilites->store (grInd, true);
+               }
+             continue;
+           }
+
+         // for HWC event counts, look at rate of events
+         if (type == BaseMetric::HWCNTR)
+           {
+             Hwcentry *hwctr = mitem->get_hw_ctr ();
+             if (!hwctr)
+               continue; // weird
+             if (!hwctr->metric)
+               continue; // raw counter
+             if (groupCpuTime->size () == 0)
+               continue; // no time to use as reference
+             if (mitem->get_base_metric ()->get_dependent_bm ())
+               continue; // has a derived time metric, only flag time version
+             Vector<long long> *llValues = (Vector<long long> *)valueTable->fetch (index);
+             if (llValues->type () != VEC_LLONG)
+               continue; // weird
+             int overflowVal = hwctr->val; //overflow count
+             if (!overflowVal)
+               continue; // weird
+             if (overflowVal > (4000000))
+               // cut off events that are very frequent like loads/stores
+               // 4Ghz * (0.01 seconds/event) / (4000000 events/overflow) = 10 cycles
+               continue;
+             // for HWCs we could base it on the overflow rate
+             for (int grInd = 0; grInd < ngroups; grInd++)
+               {
+                 double thisVal = llValues->fetch (grInd);
+                 thisVal /= overflowVal;
+                 double usertime = groupCpuTime->fetch (grInd);
+                 if (thisVal > usertime * HWC_OVERFLOWS_PER_CPUSEC_THRESHOLD)
+                   columnHilites->store (grInd, true);
+               }
+             continue;
+           }
+
+         // check for non-zero counts of the following
+         if (type == BaseMetric::DEADLOCKS ||
+             type == BaseMetric::RACCESS ||
+             type == BaseMetric::HEAP_ALLOC_BYTES ||
+             type == BaseMetric::HEAP_LEAK_BYTES)
+           {
+             Vector<long long> *llValues = (Vector<long long> *)valueTable->fetch (index);
+             if (llValues->type () != VEC_LLONG)
+               continue; // weird
+             for (int grInd = 0; grInd < ngroups; grInd++)
+               {
+                 long long thisVal = llValues->fetch (grInd);
+                 if (thisVal)
+                   columnHilites->store (grInd, true);
+               }
+             continue;
+           }
+         // continue adding cases as needed
+       }
+      }
+    }
+
+  if (numNonMetrics > 0)
+    {
+      int index;
+      char *mcmd;
+      Vec_loop (char *, non_metric_cmds, index, mcmd)
+      {
+       if (dbe_strcmp (mcmd, NTXT ("YXXX_TOTAL_TIME_PLUS_THREADS")) == 0
+           && groupCpuTime->size () == ngroups)
+         {
+           Vector<char *> *columnData = new Vector<char *>(ngroups);
+           for (int grInd = 0; grInd < ngroups; grInd++)
+             {
+               double totaltime = groupTotalTime->fetch (grInd);
+               columnData->append (dbe_sprintf (NTXT ("%0.3f %s"), totaltime, GTXT ("Seconds")));
+             }
+           valueTable->append (columnData);
+         }
+       else if (dbe_strcmp (mcmd, L1_DURATION) == 0)
+         {
+           Vector<double> *columnData = new Vector<double>(ngroups);
+           for (int grInd = 0; grInd < ngroups; grInd++)
+             {
+               hrtime_t duration = dbeCalcGroupDuration (grInd);
+               double seconds = duration * 1.e-9;
+               columnData->append (seconds);
+             }
+           valueTable->append (columnData);
+         }
+       else if (dbe_strcmp (mcmd, L1_GCDURATION) == 0)
+         {
+           Vector<double> *columnData = new Vector<double>(ngroups);
+           for (int grInd = 0; grInd < ngroups; grInd++)
+             {
+               hrtime_t duration = dbeCalcGroupGCDuration (grInd);
+               double seconds = duration * 1.e-9;
+               columnData->append (seconds);
+             }
+           valueTable->append (columnData);
+         }
+       else
+         {
+           Vector<char *> *columnData = new Vector<char *>(ngroups);
+           char * valueString = NTXT ("<unknown>");
+           for (int grInd = 0; grInd < ngroups; grInd++)
+             columnData->append (dbe_strdup (valueString));
+           valueTable->append (columnData);
+         }
+      }
+    }
+  return rc;
+}
+
+Vector<char*> *
+dbeGetOverviewText (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  Vector<char*> *info = new Vector<char*>;
+  char *field;
+  int ngroups = dbeSession->expGroups->size (); // Rows (one per compare group)
+  if (ngroups == 0 || !dbev->comparingExperiments ())
+    ngroups = 1;
+  for (int grInd = 0; grInd < ngroups; grInd++)
+    {
+      int thisGroupSize = 1;
+      Experiment *exp;
+      if (dbeSession->expGroups->size () > 0)
+       {
+         ExpGroup *gr = dbeSession->expGroups->fetch (grInd);
+         exp = gr->exps->fetch (0);
+         thisGroupSize = gr->exps->size ();
+       }
+      else
+       {
+         if (dbeSession->nexps () == 0)
+           return info;
+         exp = dbeSession->get_exp (0);
+       }
+      char * expHeader;
+      if (ngroups == 1)
+       expHeader = dbe_strdup (GTXT ("Experiment      :"));
+      else if (grInd == 0)
+       expHeader = dbe_strdup (GTXT ("Base Group      : "));
+      else if (ngroups == 2)
+       expHeader = dbe_strdup (GTXT ("Compare Group   : "));
+      else
+       expHeader = dbe_sprintf (GTXT ("Compare Group %d : "), grInd);
+      if (thisGroupSize == 1)
+       info->append (dbe_sprintf ("%s%s", expHeader, exp->get_expt_name ()));
+      else
+       info->append (dbe_sprintf ("%s%s (plus %d more)",
+                         expHeader, exp->get_expt_name (), thisGroupSize - 1));
+      free (expHeader);
+      field = exp->uarglist;
+      if (field && field[0])
+       info->append (dbe_sprintf (GTXT ("  Target        : '%s'"), field));
+      field = exp->hostname;
+      if (field && field[0])
+       info->append (dbe_sprintf (NTXT ("  %s %s (%s, %s)"),
+                                  GTXT ("Host          :"),
+                                  field,
+                                  exp->architecture ? exp->architecture
+                                  : GTXT ("<CPU architecture not recorded>"),
+                                  exp->os_version ? exp->os_version
+                                  : GTXT ("<OS version not recorded>")));
+      long start_sec = exp->start_sec;
+      char *p = ctime (&start_sec); // does this need to be freed? YXXX
+      hrtime_t tot_time = dbeCalcGroupDuration (grInd);
+      double seconds = tot_time * 1.e-9;
+      info->append (dbe_sprintf (NTXT ("  %s %s  %s %0.3f %s"),
+                                GTXT ("Start Time    :"), p,
+                                GTXT ("Duration      :"), seconds,
+                                GTXT ("Seconds")));
+      // Number of descendants/processes would be nice
+      info->append (dbe_strdup (NTXT ("")));
+    }
+  return info;
+}
+
+//--------------------------------------------------------------------------
+// Set Sort by index
+//
+void
+dbeSetSort (int dbevindex, int sort_index, MetricType mtype, bool reverse)
+{
+  DbeView *dbev;
+
+  dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  dbev->setSort (sort_index, mtype, reverse);
+  return;
+}
+
+//
+// Get annotation setting
+//
+Vector<int> *
+dbeGetAnoValue (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Vector<int> *set = new Vector<int>(9);
+  set->store (0, dbev->get_src_compcom ());
+  set->store (1, dbev->get_dis_compcom ());
+  set->store (2, dbev->get_thresh_src ());
+  set->store (3, dbev->get_thresh_src ());
+  set->store (4, dbev->get_src_visible ());
+  set->store (5, (int) dbev->get_srcmetric_visible ());
+  set->store (6, (int) dbev->get_hex_visible ());
+  set->store (7, (int) dbev->get_cmpline_visible ());
+  set->store (8, (int) dbev->get_func_scope ());
+  return set;
+}
+
+//
+// Set annotation setting
+//
+void
+dbeSetAnoValue (int dbevindex, Vector<int> *set)
+{
+  DbeView *dbev;
+  dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  if (set->size () != 10)
+    return;
+  dbev->set_src_compcom (set->fetch (0));
+  dbev->set_dis_compcom (set->fetch (1));
+  dbev->set_thresh_src (set->fetch (2));
+  dbev->set_thresh_dis (set->fetch (3));
+  dbev->set_src_visible (set->fetch (4));
+  dbev->set_srcmetric_visible ((bool)set->fetch (5));
+  dbev->set_hex_visible ((bool)set->fetch (6));
+  dbev->set_cmpline_visible ((bool)set->fetch (7));
+  dbev->set_func_scope (set->fetch (8));
+  dbev->set_funcline_visible ((bool)set->fetch (9));
+  return;
+}
+
+//
+// Get name formats
+//
+int
+dbeGetNameFormat (int dbevindex)
+{
+  DbeView *dbev;
+  dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Histable::NameFormat fmt = dbev->get_name_format ();
+  return Histable::fname_fmt (fmt);
+}
+
+bool
+dbeGetSoName (int dbevindex)
+{
+  DbeView *dbev;
+  dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Histable::NameFormat fmt = dbev->get_name_format ();
+  return Histable::soname_fmt (fmt);
+}
+
+//
+// Set name formats
+//
+void
+dbeSetNameFormat (int dbevindex, int nformat, bool soname)
+{
+  DbeView *dbev;
+  dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  dbev->set_name_format (nformat, soname);
+}
+
+//
+// Get View mode
+//
+int
+dbeGetViewMode (int dbevindex)
+{
+  DbeView *dbev;
+  dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  return (int) dbev->get_view_mode ();
+}
+
+// Set View mode
+void
+dbeSetViewMode (int dbevindex, int nmode)
+{
+  DbeView *dbev;
+  dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  dbev->set_view_mode ((VMode) nmode);
+  return;
+}
+
+// Get timeline setting
+//
+Vector<void*> *
+dbeGetTLValue (int dbevindex)
+{
+  DbeView *dbev;
+  dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Vector<char *> *strings = new Vector<char *>();
+  char *tldata_cmd = dbev->get_tldata ();
+  strings->store (0, tldata_cmd);
+
+  Vector<int> *ints = new Vector<int>(3);
+  int val;
+  val = dbev->get_tlmode ();
+  ints->store (0, val);
+  val = dbev->get_stack_align ();
+  ints->store (1, val);
+  val = dbev->get_stack_depth ();
+  ints->store (2, val);
+
+  Vector<void*> *objs = new Vector<void*>(2);
+  objs->store (0, strings);
+  objs->store (1, ints);
+  return objs;
+}
+
+//
+// Set timeline setting
+//
+void
+dbeSetTLValue (int dbevindex, const char *tldata_cmd,
+              int entitiy_prop_id, int stackalign, int stackdepth)
+{
+  DbeView *dbev;
+  dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  dbev->set_tldata (tldata_cmd);
+  dbev->set_tlmode (entitiy_prop_id);
+  dbev->set_stack_align (stackalign);
+  dbev->set_stack_depth (stackdepth);
+  return;
+}
+
+//
+// Get founder experiments and their descendants
+//
+Vector<void*> *
+dbeGetExpFounderDescendants ()
+{
+  int size = dbeSession->nexps ();
+  if (size == 0)
+    return NULL;
+  Vector<void*> *table = new Vector<void*>(2);
+  Vector<int> *founderExpIds = new Vector<int>();
+  Vector<Vector<int> *> *subExpIds = new Vector<Vector<int>*>();
+  for (int index = 0; index < size; index++)
+    {
+      Experiment *exp = dbeSession->get_exp (index);
+      if (exp->founder_exp == NULL)
+       {
+         founderExpIds->append (exp->getExpIdx ());
+         Vector<int> *subExps = new Vector<int>();
+         for (int i = 0; i < exp->children_exps->size (); i++)
+           {
+             Experiment * subExp = exp->children_exps->fetch (i);
+             subExps->append (subExp->getExpIdx ());
+           }
+         subExpIds->append (subExps);
+       }
+    }
+  table->store (0, founderExpIds);
+  table->store (1, subExpIds);
+  return table;
+}
+
+//
+// Get experiment selection
+//
+Vector<void*> *
+dbeGetExpSelection (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  int size = dbeSession->nexps ();
+  if (size == 0)
+    return NULL;
+  Vector<void*> *table = new Vector<void*>(3);
+  Vector<char*> *names = new Vector<char*>(size);
+  Vector<bool> *enable = new Vector<bool>(size);
+  Vector<int> *userExpIds = new Vector<int>(size);
+
+  // Get experiment names
+  for (int index = 0; index < size; index++)
+    {
+      Experiment *exp = dbeSession->get_exp (index);
+      char *buf = dbeGetName (dbevindex, index);
+      names->store (index, buf);
+      bool val;
+      val = dbev->get_exp_enable (index);
+      enable->store (index, val);
+      userExpIds->store (index, exp->getUserExpId ());
+    }
+  table->store (0, names);
+  table->store (1, enable);
+  table->store (2, userExpIds);
+  return table;
+}
+
+int
+dbeValidateFilterExpression (char *str_expr)
+{
+  if (str_expr == NULL)
+    return 0;
+  Expression *expr = dbeSession->ql_parse (str_expr);
+  if (expr == NULL)
+    return 0;
+  delete expr;
+  return 1;
+}
+
+Vector<void*> *
+dbeGetFilterKeywords (int /* dbevindex */)
+{
+  Vector <char*> *kwCategory = new Vector<char *>();
+  Vector <char*> *kwCategoryI18N = new Vector<char *>();
+  Vector <char*> *kwDataType = new Vector<char *>();
+  Vector <char*> *kwKeyword = new Vector<char *>();
+  Vector <char*> *kwFormula = new Vector<char *>();
+  Vector <char*> *kwDescription = new Vector<char *>();
+  Vector <void*> *kwEnumDescs = new Vector<void *>();
+
+  Vector<void*> *res = new Vector<void*>(7);
+  res->append (kwCategory);
+  res->append (kwCategoryI18N);
+  res->append (kwDataType);
+  res->append (kwKeyword);
+  res->append (kwFormula);
+  res->append (kwDescription);
+  res->append (kwEnumDescs);
+
+  char *vtypeNames[] = VTYPE_TYPE_NAMES;
+  // section header for global definitions
+  kwCategory->append (dbe_strdup (NTXT ("FK_SECTION")));
+  kwCategoryI18N->append (dbe_strdup (GTXT ("Global Definitions")));
+  kwDataType->append (NULL);
+  kwKeyword->append (NULL);
+  kwFormula->append (NULL);
+  kwDescription->append (NULL);
+  kwEnumDescs->append (NULL);
+  dbeSession->get_filter_keywords (res);
+  MemorySpace::get_filter_keywords (res);
+
+  // loop thru all founder experiments
+  int nexp = dbeSession->nexps ();
+  for (int ii = 0; ii < nexp; ++ii)
+    {
+      Experiment* fexp = dbeSession->get_exp (ii);
+      if (fexp->founder_exp != NULL)
+       continue; // is a child; should be covered when we get to founder
+
+      // section header for each founder
+      // section header for founder experiment
+      kwCategory->append (dbe_strdup (NTXT ("FK_SECTION")));
+      kwCategoryI18N->append (dbe_sprintf (NTXT ("%s [EXPGRID==%d]"),
+                                          fexp->get_expt_name (),
+                                          fexp->groupId));
+      kwDataType->append (NULL);
+      kwKeyword->append (NULL);
+      kwFormula->append (NULL);
+      kwDescription->append (NULL);
+      kwEnumDescs->append (NULL);
+
+      int nchildren = fexp->children_exps->size ();
+      Experiment *exp;
+      // category header: Experiments
+      {
+       char *propUName = dbeSession->getPropUName (PROP_EXPID);
+
+       // store list of subexperiments in kwEnumDescs
+       Vector <char*> *enumDescs = new Vector<char *>();
+       int jj = 0;
+       exp = fexp;
+       while (1)
+         {
+           char * expBasename = get_basename (exp->get_expt_name ());
+           char * targetName = exp->utargname ? exp->utargname
+                   : (char *) GTXT ("(unknown)");
+           enumDescs->append (dbe_sprintf (NTXT ("(%d) -> %s [%s, PID %d]"),
+                                           exp->getUserExpId (), expBasename,
+                                           targetName, exp->getPID ()));
+           if (jj >= nchildren)
+             break;
+           exp = fexp->children_exps->fetch (jj);
+           jj++;
+         }
+       kwCategory->append (dbe_strdup (NTXT ("FK_EXPLIST")));
+       kwCategoryI18N->append (dbe_strdup (GTXT ("Experiments")));
+       kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT32]));
+       kwKeyword->append (dbe_strdup (NTXT ("EXPID")));
+       kwFormula->append (NULL);
+       kwDescription->append (propUName);
+       kwEnumDescs->append (enumDescs);
+      }
+
+      // select representative experiment
+      if (nchildren == 0)
+       exp = fexp; // founder
+      else
+       exp = fexp->children_exps->fetch (0); // first child
+      int expIdx = exp->getExpIdx ();
+      Vector<void*> *data = dbeGetDataDescriptorsV2 (expIdx);
+      if (data == NULL)
+       continue;
+      Vector<int> *dataId = (Vector<int>*)data->fetch (0);
+      Vector<char*> *dataName = (Vector<char*>*)data->fetch (1);
+      Vector<char*> *dataUName = (Vector<char*>*)data->fetch (2);
+      if (dataId == NULL || dataName == NULL)
+       {
+         destroy (data);
+         continue;
+       }
+      // loop thru data descriptors
+      int ndata = dataId->size ();
+      for (int j = 0; j < ndata; ++j)
+       {
+         // category: data name (e.g. Clock Profiling)
+         char * catName = dataName->fetch (j);
+         char * dUname = dataUName ? dataUName->fetch (j) : catName;
+         char * catUname = dUname ? dUname : catName;
+
+         Vector<void*> *props = dbeGetDataPropertiesV2 (expIdx, dataId->fetch (j));
+         if (props == NULL)
+           continue;
+         Vector<char*> *propUName = (Vector<char*>*)props->fetch (1);
+         Vector<int> *propTypeId = (Vector<int> *)props->fetch (2);
+         Vector<char*> *propType = (Vector<char*>*)props->fetch (3);
+         Vector<char*> *propName = (Vector<char*>*)props->fetch (5);
+         Vector<Vector<char*>*> *propStateNames =
+                 (Vector<Vector<char*>*> *)props->fetch (6);
+         Vector<Vector<char*>*> *propStateUNames =
+                 (Vector<Vector<char*>*> *)props->fetch (7);
+         if (propName == NULL || propUName == NULL || propType == NULL
+             || propName->size () <= 0)
+           {
+             destroy (props);
+             continue;
+           }
+         int nprop = propName->size ();
+         for (int k = 0; k < nprop; ++k)
+           {
+             if (propTypeId->fetch (k) == TYPE_OBJ)
+               continue;
+             if (dbe_strcmp (propName->fetch (k), NTXT ("FRINFO")) == 0)
+               continue;
+
+             // store list of states in kwEnumDescs
+             Vector<char*> *enumDescs = new Vector<char *>();
+             Vector<char*>* stateNames = propStateNames->fetch (k);
+             Vector<char*>* stateUNames = propStateUNames->fetch (k);
+             int nStates = stateNames ? stateNames->size () : 0;
+             for (int kk = 0; kk < nStates; ++kk)
+               {
+                 const char *stateName = stateNames->fetch (kk);
+                 if (stateName == NULL || strlen (stateName) == 0)
+                   continue;
+                 const char *stateUName = stateUNames->fetch (kk);
+                 if (stateUName == NULL || strlen (stateUName) == 0)
+                   stateUName = stateName;
+                 enumDescs->append (dbe_sprintf (NTXT ("(%d) -> %s"), kk, stateUName));
+               }
+             kwCategory->append (dbe_strdup (catName));
+             kwCategoryI18N->append (dbe_strdup (catUname));
+             kwDataType->append (dbe_strdup (propType->fetch (k)));
+             kwKeyword->append (dbe_strdup (propName->fetch (k)));
+             kwFormula->append (NULL);
+             kwDescription->append (dbe_strdup (propUName->fetch (k)));
+             kwEnumDescs->append (enumDescs);
+           }
+         destroy (props);
+       }
+      destroy (data);
+    }
+  return (res);
+}
+
+// GetFilters -- returns the list of filters for the indexed experiment
+//     returns false if there's a problem; true otherwise
+//
+Vector<void*> *
+dbeGetFilters (int dbevindex, int nexp)
+{
+  FilterNumeric *filt;
+  int index;
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Vector<FilterNumeric *>*filters = dbev->get_all_filters (nexp);
+  if (filters == NULL)
+    return NULL;
+
+  // return an array of filter data for that experiment
+  Vector <int> *findex = new Vector<int>(); // index of the filters
+  Vector <char*> *shortname = new Vector<char *>();
+  // short name of filter
+  Vector <char*> *i18n_name = new Vector<char *>();
+  // External I18N'd name of filter
+  Vector <char*> *pattern = new Vector<char *>();
+  // current setting string
+  Vector <char*> *status = new Vector<char *>();
+  // current status of filter (%, range, etc.)
+
+  Vec_loop (FilterNumeric *, filters, index, filt)
+  {
+    findex->append (index);
+    shortname->append (dbe_strdup (filt->get_cmd ()));
+    i18n_name->append (dbe_strdup (filt->get_name ()));
+    pattern->append (dbe_strdup (filt->get_pattern ()));
+    status->append (dbe_strdup (filt->get_status ()));
+  }
+  Vector<void*> *res = new Vector<void*>(5);
+  res->store (0, findex);
+  res->store (1, shortname);
+  res->store (2, i18n_name);
+  res->store (3, pattern);
+  res->store (4, status);
+  return (res);
+}
+
+// Set a filter string for a view
+//     Returns NULL if OK, error message if not
+
+char *
+dbeSetFilterStr (int dbevindex, char *filter_str)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  dbev->clear_error_msg ();
+  dbev->clear_warning_msg ();
+  char *ret = dbev->set_filter (filter_str);
+  return ret;
+}
+
+// Get the current filter setting for the view
+char *
+dbeGetFilterStr (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  char *ret = dbev->get_filter ();
+  return ret;
+}
+
+// Update a filters for a single experiment
+// Returns true if any filter->set_pattern() returns true,
+//     implying rereading the data is needed (i.e., a filter changed)
+//
+bool
+dbeUpdateFilters (int dbevindex, Vector<bool> *selected, Vector<char *> *pattern_str)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  dbev->clear_error_msg ();
+  dbev->clear_warning_msg ();
+
+  // Get index of first selected experiment
+  int size = selected->size ();
+  int nselexp = -1;
+  for (int index = 0; index < size; index++)
+    {
+      if (selected->fetch (index) == true)
+       {
+         nselexp = index;
+         break;
+       }
+    }
+  if (nselexp == -1) // No experiment selected
+    return false;
+
+  bool ret = false;
+  for (int j = 0; j < size; j++)
+    {
+      if (selected->fetch (j) == false)
+       continue;
+      bool error;
+      if (dbev->set_pattern (j, pattern_str, &error))
+       ret = true;
+    }
+  dbev->update_advanced_filter ();
+  return ret;
+}
+
+char *
+dbeComposeFilterClause (int dbevindex, int type, int subtype, Vector<int> *selections)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  // ask the cached data to generate the string
+  Hist_data *data;
+  switch (type)
+    {
+    case DSP_FUNCTION:
+      data = dbev->func_data;
+      break;
+    case DSP_DLAYOUT:
+      data = dbev->dlay_data;
+      break;
+    case DSP_DATAOBJ:
+      data = dbev->dobj_data;
+      break;
+    case DSP_MEMOBJ:
+    case DSP_INDXOBJ:
+      data = dbev->get_indxobj_data (subtype);
+      break;
+    case DSP_LINE:
+      data = dbev->line_data;
+      break;
+    case DSP_PC:
+      data = dbev->pc_data;
+      break;
+    case DSP_SOURCE:
+      data = dbev->src_data;
+      break;
+    case DSP_DISASM:
+      data = dbev->dis_data;
+      break;
+    case DSP_IOACTIVITY:
+      data = dbev->iofile_data;
+      break;
+    case DSP_IOVFD:
+      data = dbev->iovfd_data;
+      break;
+    case DSP_IOCALLSTACK:
+      data = dbev->iocs_data;
+      break;
+    case DSP_HEAPCALLSTACK:
+      data = dbev->heapcs_data;
+      break;
+    default:
+      return NULL;
+    }
+  if (data == NULL)
+    return NULL;
+
+  // Get array of object indices, and compose filter string
+  Vector<uint64_t> *obj_ids = data->get_object_indices (selections);
+  if (obj_ids == NULL || obj_ids->size () == 0)
+    return NULL;
+
+  uint64_t sel;
+  int index;
+  int found = 0;
+  char buf[128];
+  StringBuilder sb;
+  sb.append ('(');
+  switch (type)
+    {
+    case DSP_LINE:
+    case DSP_PC:
+    case DSP_SOURCE:
+    case DSP_DISASM:
+    case DSP_FUNCTION:
+      sb.append (NTXT ("LEAF IN "));
+      break;
+    case DSP_MEMOBJ:
+    case DSP_INDXOBJ:
+      sb.append (dbeSession->getIndexSpaceName (subtype));
+      sb.append (NTXT (" IN "));
+      break;
+    }
+  Vec_loop (uint64_t, obj_ids, index, sel)
+  {
+    if (found == 0)
+      {
+       found = 1;
+       sb.append ('(');
+      }
+    else
+      sb.append (NTXT (", "));
+    snprintf (buf, sizeof (buf), NTXT ("%llu"), (long long) sel);
+    sb.append (buf);
+  }
+  if (found == 1)
+    sb.append (')');
+
+  switch (type)
+    {
+    case DSP_DLAYOUT:
+    case DSP_DATAOBJ:
+      sb.append (NTXT (" SOME IN DOBJ"));
+      break;
+    }
+  sb.append (')');
+  return sb.toString ();
+}
+
+//
+// Get load object states
+//
+Vector<void *> *
+dbeGetLoadObjectList (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+  int size = lobjs->size ();
+
+  // Initialize Java boolean array
+  Vector<char *> *names = new Vector<char *>(size);
+  Vector<int> *states = new Vector<int>(size);
+  Vector<int> *indices = new Vector<int>(size);
+  Vector<char *> *paths = new Vector<char *>(size);
+  Vector<int> *isJava = new Vector<int>(size);
+
+  // Get load object states
+  int index;
+  LoadObject *lo;
+  char *lo_name;
+
+  // lobjectsNoJava is a trimmed list of indices provided to front-end skipping the Java
+  // classes. lobjectsNoJava preserves the mapping of the index into the complete lobjs
+  // vector. What front-end sees as lobj[i] is really lobj[lobjectsNoJava[i]];
+
+  // This list is constructed every time GetLoadObjectList() or GetLoadObjectState() is
+  // called. Possibility of further optimization by making it more persistent.
+  // Only consumer of this list is dbeSetLoadObjectState
+  int new_index = 0;
+  if (dbev->lobjectsNoJava == NULL)
+    dbev->lobjectsNoJava = new Vector<int>(1);
+  else
+    dbev->lobjectsNoJava->reset ();
+
+  Vec_loop (LoadObject*, lobjs, index, lo)
+  {
+    // Set 0, 1, or 2 for show/hide/api
+    enum LibExpand expand = dbev->get_lo_expand (lo->seg_idx);
+
+    lo_name = lo->get_name ();
+    if (lo_name != NULL)
+      {
+       size_t len = strlen (lo_name);
+       if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
+         isJava->store (new_index, 1);
+       else
+         isJava->store (new_index, 0);
+      }
+    else
+      isJava->store (new_index, 0);
+    dbev->lobjectsNoJava->append (index);
+
+    names->store (new_index, dbe_sprintf (NTXT ("%s"), lo_name));
+    states->store (new_index, (int) expand);
+    indices->store (new_index, (int) lo->seg_idx);
+    paths->store (new_index, dbe_sprintf (NTXT ("%s"), lo->get_pathname ()));
+    new_index++;
+  }
+  Vector<void*> *res = new Vector<void*>(5);
+  res->store (0, names);
+  res->store (1, states);
+  res->store (2, indices);
+  res->store (3, paths);
+  res->store (4, isJava);
+  delete lobjs;
+  return res;
+}
+
+Vector<int> *
+dbeGetLoadObjectState (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+  int size = lobjs->size ();
+
+  // Initialize Java boolean array
+  Vector<int> *states = new Vector<int>(size);
+  char *lo_name;
+
+  // lobjectsNoJava is a trimmed list of indices provided to front-end skipping the Java
+  // classes. lobjectsNoJava preserves the mapping of the index into the complete lobjs
+  // vector. What front-end sees as lobj[i] is really lobj[lobjectsNoJava[i]];
+
+  // This list is constructed every time GetLoadObjectList() or GetLoadObjectState() is
+  // called. Possibility of further optimization by making it more persistent.
+  // Only consumer of this list is dbeSetLoadObjectState
+  int new_index = 0;
+  if (dbev->lobjectsNoJava == NULL)
+    dbev->lobjectsNoJava = new Vector<int>(1);
+  else
+    dbev->lobjectsNoJava->reset ();
+
+  // Get load object states
+  int index;
+  LoadObject *lo;
+
+  Vec_loop (LoadObject*, lobjs, index, lo)
+  {
+    // Set 0, 1, or 2 for show/hide/api
+    lo_name = lo->get_name ();
+    if (lo_name != NULL)
+      {
+       size_t len = strlen (lo_name);
+       if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
+         continue;
+      }
+    else
+      dbev->lobjectsNoJava->append (index);
+
+    enum LibExpand expand = dbev->get_lo_expand (lo->seg_idx);
+    states->store (new_index, (int) expand);
+    new_index++;
+  }
+  delete lobjs;
+  return states;
+}
+
+// Set load object states
+void
+dbeSetLoadObjectState (int dbevindex, Vector<int> *selected)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+
+  int index;
+  bool changed = false;
+
+  LoadObject *lo;
+  int new_index = 0;
+  dbev->setShowAll ();
+  Vec_loop (LoadObject*, lobjs, index, lo)
+  {
+    if (dbev->lobjectsNoJava != NULL)
+      {
+       // This loadobject is a java class and was skipped
+       if (dbev->lobjectsNoJava->fetch (new_index) != index)
+         continue;
+      }
+    // Get array of settings
+    enum LibExpand expand = (enum LibExpand) selected->fetch (new_index);
+    if (expand == LIBEX_HIDE)
+      {
+       dbev->resetShowAll ();
+       dbeSession->set_lib_visibility_used ();
+      }
+    changed = changed | dbev->set_libexpand (lo->get_pathname (), expand);
+    new_index++;
+  }
+  delete lobjs;
+  if (changed == true)
+    {
+      dbev->setShowHideChanged ();
+      dbev->update_lo_expands ();
+    }
+
+  return;
+}
+
+// Reset load object states
+void
+dbeSetLoadObjectDefaults (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  dbev->set_libdefaults ();
+}
+
+// Get  Machine model
+Vector<char*>*
+dbeGetCPUVerMachineModel (int dbevindex)
+{
+  Vector<char*>* table = new Vector<char*>();
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  char * mach_model = dbev->get_settings ()->get_machinemodel ();
+  if (mach_model != NULL)
+    {
+      table->append (mach_model);
+      return table;
+    }
+  int grsize = dbeSession->expGroups->size ();
+  for (int j = 0; j < grsize; j++)
+    {
+      ExpGroup *gr = dbeSession->expGroups->fetch (j);
+      Vector<Experiment*> *exps = gr->exps;
+      for (int i = 0, sz = exps->size (); i < sz; i++)
+       {
+         Experiment *exp = exps->fetch (i);
+         char *model = exp->machinemodel;
+         if (model != NULL)
+           table->append (dbe_strdup (model));
+       }
+    }
+  return table;
+}
+
+// automatically load machine model if applicable
+void
+dbeDetectLoadMachineModel (int dbevindex)
+{
+  if (dbeSession->is_datamode_available ())
+    {
+      char *model = dbeGetMachineModel ();
+      if (model == NULL)
+       {
+         Vector<char*>* models = dbeGetCPUVerMachineModel (dbevindex);
+         char * machineModel = NTXT ("generic");
+         if (models->size () > 0)
+           {
+             machineModel = models->get (0);
+             for (int i = 1; i < models->size (); i++)
+               {
+                 if (strncmp (models->get (i), machineModel, strlen (machineModel)) == 0)
+                   {
+                     machineModel = NTXT ("generic");
+                     break;
+                   }
+               }
+             dbeLoadMachineModel (machineModel);
+           }
+         delete models;
+       }
+    }
+}
+
+// Managing Memory Objects
+char *
+dbeDefineMemObj (char *name, char *index_expr, char *machinemodel,
+                char *sdesc, char *ldesc)
+{
+  return MemorySpace::mobj_define (name, index_expr, machinemodel, sdesc, ldesc);
+}
+
+char *
+dbeDeleteMemObj (char *name)
+{
+  return MemorySpace::mobj_delete (name);
+}
+
+Vector<void*> *
+dbeGetMemObjects (int /*dbevindex*/)
+{
+  Vector<void*> *res = MemorySpace::getMemObjects ();
+  return res;
+}
+
+// Managing machine model
+char *
+dbeLoadMachineModel (char *name)
+{
+  return dbeSession->load_mach_model (name);
+}
+
+char *
+dbeGetMachineModel ()
+{
+  return dbeSession->get_mach_model ();
+}
+
+Vector <char *> *
+dbeListMachineModels ()
+{
+  return dbeSession->list_mach_models ();
+}
+
+// Managing Index Objects
+char *
+dbeDefineIndxObj (char *name, char *index_expr, char *sdesc, char *ldesc)
+{
+  return dbeSession->indxobj_define (name, NULL, index_expr, sdesc, ldesc);
+}
+
+Vector<void*> *
+dbeGetIndxObjDescriptions (int /*dbevindex*/)
+{
+  Vector<void*> *res = dbeSession->getIndxObjDescriptions ();
+  return res;
+}
+
+Vector<void*> *
+dbeGetCustomIndxObjects (int /*dbevindex*/)
+{
+  Vector<void*> *res = dbeSession->getCustomIndxObjects ();
+  return res;
+}
+
+void
+dbeSetSelObj (int dbevindex, Obj sel_obj_or_ind, int type, int subtype)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Histable *sel_obj;
+  Hist_data *data;
+  int sel_ind = (int) sel_obj_or_ind;
+
+  switch (type)
+    {
+    case DSP_FUNCTION:
+      data = dbev->func_data;
+      break;
+    case DSP_LINE:
+      data = dbev->line_data;
+      break;
+    case DSP_PC:
+      data = dbev->pc_data;
+      break;
+    case DSP_CALLER:
+      data = dbev->callers;
+      break;
+    case DSP_CALLEE:
+      data = dbev->callees;
+      break;
+    case DSP_SOURCE:
+      data = dbev->src_data;
+      break;
+    case DSP_DISASM:
+      data = dbev->dis_data;
+      break;
+    case DSP_DLAYOUT:
+      data = dbev->dlay_data;
+      if (data == NULL)
+       {
+         dbev->sel_binctx = NULL;
+         return;
+       }
+      if (sel_ind >= 0 && sel_ind < dbev->dlay_data->size ())
+       dbev->sel_dobj = dbev->dlay_data->fetch (sel_ind)->obj;
+      return;
+    case DSP_DATAOBJ:
+      data = dbev->dobj_data;
+      if (data == NULL)
+       {
+         dbev->sel_binctx = NULL;
+         return;
+       }
+      if (sel_ind >= 0 && sel_ind < dbev->dobj_data->size ())
+       dbev->sel_dobj = dbev->dobj_data->fetch (sel_ind)->obj;
+      return;
+    case DSP_MEMOBJ:
+    case DSP_INDXOBJ:
+      dbev->set_indxobj_sel (subtype, sel_ind);
+      sel_obj = dbev->get_indxobj_sel (subtype);
+      if (sel_obj && sel_obj->get_type () == Histable::INDEXOBJ)
+       dbev->set_sel_obj (((IndexObject*) sel_obj)->get_obj ());
+      return;
+    case DSP_SOURCE_V2:
+    case DSP_DISASM_V2:
+    case DSP_TIMELINE:
+    case DSP_LEAKLIST:
+    case DSP_RACES:
+    case DSP_DEADLOCKS:
+    case DSP_DUALSOURCE:
+    case DSP_SOURCE_DISASM:
+    case DSP_IOACTIVITY:
+    case DSP_IOVFD:
+    case DSP_IOCALLSTACK:
+    case DSP_HEAPCALLSTACK:
+    case DSP_MINICALLER:
+      dbev->set_sel_obj ((Histable *) sel_obj_or_ind);
+      return;
+    default:
+      // abort();
+      return;
+    }
+  if (type != DSP_SOURCE && type != DSP_DISASM && type != DSP_SOURCE_V2
+      && type != DSP_DISASM_V2)
+    dbev->sel_binctx = NULL;
+
+  if (data == NULL || data->get_status () != Hist_data::SUCCESS
+      || sel_ind >= data->size ())
+    return;
+
+  if (sel_ind >= 0 && sel_ind < data->size ())
+    dbev->set_sel_obj (data->fetch (sel_ind)->obj);
+}
+
+void
+dbeSetSelObjV2 (int dbevindex, uint64_t id)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  dbev->set_sel_obj (dbeSession->findObjectById (id));
+}
+
+Obj
+dbeGetSelObj (int dbevindex, int type, int subtype)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  Histable *sel_obj = NULL;
+  switch (type)
+    {
+    case DSP_FUNCTION:
+      sel_obj = dbev->get_sel_obj (Histable::FUNCTION);
+      break;
+    case DSP_LINE:
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+      sel_obj = dbev->get_sel_obj (Histable::LINE);
+      break;
+    case DSP_PC:
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      sel_obj = dbev->get_sel_obj (Histable::INSTR);
+      break;
+    case DSP_SRC_FILE:
+      sel_obj = dbev->get_sel_obj (Histable::SOURCEFILE);
+      break;
+    case DSP_DATAOBJ:
+    case DSP_DLAYOUT:
+      if (dbev->sel_dobj)
+       sel_obj = dbev->sel_dobj->convertto (Histable::DOBJECT);
+      break;
+    case DSP_MEMOBJ:
+    case DSP_INDXOBJ:
+      sel_obj = dbev->get_indxobj_sel (subtype);
+      break;
+    default:
+      abort ();
+    }
+  Dprintf (DEBUG_DBE, NTXT ("### dbeGetSelObj: Dbe.cc:%d %s (%d) returns %s\n"),
+          __LINE__, dsp_type_to_string (type), type, sel_obj ? sel_obj->dump () : "NULL");
+  return (Obj) sel_obj;
+}
+
+Obj
+dbeConvertSelObj (Obj obj, int type)
+{
+  Histable *sel_obj = (Histable *) obj;
+  Dprintf (DEBUG_DBE, NTXT ("### dbeConvertSelObj: Dbe.cc:%d %s (%d) sel_obj=%s\n"),
+          __LINE__, dsp_type_to_string (type), type, sel_obj ? sel_obj->dump ()
+         : "NULL");
+  if (sel_obj == NULL)
+    return (Obj) NULL;
+  switch (type)
+    {
+    case DSP_FUNCTION:
+      return (Obj) sel_obj->convertto (Histable::FUNCTION);
+    case DSP_LINE:
+      return (Obj) sel_obj->convertto (Histable::LINE);
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+      {
+       SourceFile* srcCtx = NULL;
+       if (sel_obj->get_type () == Histable::INSTR)
+         {
+           DbeInstr* dbei = (DbeInstr *) sel_obj;
+           srcCtx = (SourceFile*) dbei->convertto (Histable::SOURCEFILE);
+         }
+       else if (sel_obj->get_type () == Histable::LINE)
+         {
+           DbeLine * dbel = (DbeLine *) sel_obj;
+           srcCtx = dbel->sourceFile;
+         }
+       sel_obj = sel_obj->convertto (Histable::LINE, srcCtx);
+       Dprintf (DEBUG_DBE, NTXT ("### dbeConvertSelObj: Dbe.cc:%d %s (%d) returns %s\n"),
+                __LINE__, dsp_type_to_string (type), type, sel_obj ? sel_obj->dump () : "NULL");
+       if (sel_obj && sel_obj->get_type () == Histable::LINE)
+         {
+           DbeLine * dbel = (DbeLine *) sel_obj;
+           return (Obj) dbel->dbeline_base;
+         }
+       return (Obj) sel_obj->convertto (Histable::LINE, srcCtx);
+      }
+    case DSP_PC:
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      return (Obj) sel_obj->convertto (Histable::INSTR);
+    case DSP_SRC_FILE:
+      return (Obj) sel_obj->convertto (Histable::SOURCEFILE);
+    default:
+      abort ();
+    }
+  return (Obj) NULL;
+}
+
+uint64_t
+dbeGetSelObjV2 (int dbevindex, char *typeStr)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Histable *obj = NULL;
+  if (typeStr != NULL)
+    {
+      if (streq (typeStr, NTXT ("FUNCTION")))
+       obj = dbev->get_sel_obj (Histable::FUNCTION);
+      else if (streq (typeStr, NTXT ("INSTRUCTION")))
+       obj = dbev->get_sel_obj (Histable::INSTR);
+      else if (streq (typeStr, NTXT ("SOURCELINE")))
+       obj = dbev->get_sel_obj (Histable::LINE);
+      else if (streq (typeStr, NTXT ("SOURCEFILE")))
+       obj = dbev->get_sel_obj (Histable::SOURCEFILE);
+    }
+  Dprintf (DEBUG_DBE, NTXT ("### dbeGetSelObjV2: Dbe.cc:%d %s returns %s\n"),
+          __LINE__, STR (typeStr), obj ? obj->dump () : "NULL");
+  return obj != NULL ? obj->id : (uint64_t) - 1;
+}
+
+Vector<uint64_t> *
+dbeGetSelObjsIO (int dbevindex, Vector<uint64_t> *ids, int type)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Vector<uint64_t> *res = NULL;
+  Vector<uint64_t> *result = new Vector<uint64_t>();
+  for (int i = 0; i < ids->size (); i++)
+    {
+      res = dbeGetSelObjIO (dbevindex, ids->fetch (i), type);
+      if (res != NULL)
+       {
+         result->addAll (res);
+         delete res;
+       }
+    }
+  return result;
+}
+
+Vector<uint64_t> *
+dbeGetSelObjIO (int dbevindex, uint64_t id, int type)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Histable *obj = NULL;
+  Vector<uint64_t> *res = NULL;
+  int size = 0;
+  switch (type)
+    {
+    case DSP_IOACTIVITY:
+      obj = dbev->get_sel_obj_io (id, Histable::IOACTFILE);
+      size = obj != NULL ? ((FileData*) obj)->getVirtualFds ()->size () : 0;
+      if (size)
+       {
+         res = new Vector<uint64_t>();
+         Vector<int64_t> *vfds = ((FileData*) obj)->getVirtualFds ();
+         for (int i = 0; i < size; i++)
+           res->append (vfds->fetch (i));
+       }
+      break;
+    case DSP_IOVFD:
+      obj = dbev->get_sel_obj_io (id, Histable::IOACTVFD);
+      if (obj)
+       {
+         res = new Vector<uint64_t>();
+         res->append (obj->id);
+       }
+      break;
+    case DSP_IOCALLSTACK:
+      obj = dbev->get_sel_obj_io (id, Histable::IOCALLSTACK);
+      if (obj)
+       {
+         Vector<Obj> *instrs = dbeGetStackPCs (dbevindex, obj->id);
+         if (instrs == NULL)
+           return NULL;
+         int stsize = instrs->size ();
+         res = new Vector<uint64_t>(stsize);
+         for (int i = 0; i < stsize; i++)
+           {
+             Histable *objFunc = (DbeInstr*) (instrs->fetch (i));
+             if (objFunc->get_type () != Histable::LINE)
+               {
+                 objFunc = objFunc->convertto (Histable::FUNCTION);
+                 res->insert (0, objFunc->id);
+               }
+           }
+         delete instrs;
+       }
+      break;
+    default:
+      break;
+    }
+  return res;
+}
+
+uint64_t
+dbeGetSelObjHeapTimestamp (int dbevindex, uint64_t id)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Histable *obj = NULL;
+  uint64_t res = 0;
+  Vector<uint64_t> *peakStackIds;
+  Vector<hrtime_t> *peakTimestamps;
+
+  // Find and return the timestamp for the peak
+  bool foundPeakId = false;
+  if (id > 0)
+    {
+      obj = dbev->get_sel_obj_heap (0);
+      if (obj != NULL)
+       {
+         peakStackIds = ((HeapData*) obj)->getPeakStackIds ();
+         peakTimestamps = ((HeapData*) obj)->getPeakTimestamps ();
+         for (int i = 0; i < peakStackIds->size (); i++)
+           {
+             if (id == peakStackIds->fetch (i))
+               {
+                 res = peakTimestamps->fetch (i);
+                 foundPeakId = true;
+                 break;
+               }
+           }
+       }
+    }
+
+  // Return the first timestamp for the peak
+  // if the callstack id is zero or it
+  // doesn't match with the peak stack id
+  if (id == 0 || !foundPeakId)
+    {
+      obj = dbev->get_sel_obj_heap (0);
+      res = obj != NULL ? ((HeapData*) obj)->getPeakTimestamps ()->fetch (0) : 0;
+    }
+  return res;
+}
+
+int
+dbeGetSelObjHeapUserExpId (int dbevindex, uint64_t id)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Histable *obj = NULL;
+  int res = 0;
+  obj = dbev->get_sel_obj_heap (id);
+  res = obj != NULL ? ((HeapData*) obj)->getUserExpId () : 0;
+  return res;
+}
+
+//
+// Get index of selected function/object
+//
+int
+dbeGetSelIndex (int dbevindex, Obj sel_obj, int type, int subtype)
+{
+  Hist_data *data;
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  switch (type)
+    {
+    case DSP_FUNCTION:
+      data = dbev->func_data;
+      break;
+    case DSP_LINE:
+      data = dbev->line_data;
+      break;
+    case DSP_PC:
+      data = dbev->pc_data;
+      break;
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+      data = dbev->src_data;
+      break;
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      data = dbev->dis_data;
+      break;
+    case DSP_DLAYOUT:
+      data = dbev->dlay_data;
+      break;
+    case DSP_DATAOBJ:
+      data = dbev->dobj_data;
+      break;
+    case DSP_MEMOBJ:
+    case DSP_INDXOBJ:
+      data = dbev->get_indxobj_data (subtype);
+      break;
+    default:
+      data = NULL;
+      break;
+    }
+  if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+    return -1;
+
+  Histable *chk_obj = (Histable *) sel_obj;
+  Vector<Hist_data::HistItem*> *histItems = data->get_hist_items ();
+  if (histItems == NULL || chk_obj == NULL)
+    return -1;
+  for (int i = 0, sz = histItems->size (); i < sz; i++)
+    {
+      if (histItems->get (i)->obj == chk_obj)
+       return i;
+      if (histItems->get (i)->obj == NULL)
+       continue;
+      if (histItems->get (i)->obj->get_type () == Histable::LINE
+         && chk_obj->get_type () == Histable::LINE)
+       {
+         if (((DbeLine*) histItems->get (i)->obj)->convertto (Histable::FUNCTION)
+             == ((DbeLine*) chk_obj)->convertto (Histable::FUNCTION)
+             && ((DbeLine*) histItems->get (i)->obj)->lineno
+             == ((DbeLine*) chk_obj)->lineno)
+           return i;
+       }
+      else if (histItems->get (i)->obj->get_type () == Histable::INSTR
+        && chk_obj->get_type () == Histable::INSTR)
+       if (((DbeInstr*) histItems->get (i)->obj)->convertto (Histable::FUNCTION)
+           == ((DbeInstr*) chk_obj)->convertto (Histable::FUNCTION)
+           && ((DbeInstr*) histItems->get (i)->obj)->addr
+           == ((DbeInstr*) chk_obj)->addr)
+         return i;
+    }
+
+  Histable *chk_obj1 = NULL;
+  switch (type)
+    {
+    case DSP_FUNCTION:
+      chk_obj1 = chk_obj->convertto (Histable::FUNCTION);
+      break;
+    case DSP_LINE:
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+      chk_obj1 = chk_obj->convertto (Histable::LINE);
+      break;
+    case DSP_PC:
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      chk_obj1 = chk_obj->convertto (Histable::INSTR);
+      break;
+    }
+  if (chk_obj1 && chk_obj != chk_obj1)
+    for (int i = 0, sz = histItems->size (); i < sz; i++)
+      if (histItems->get (i)->obj == chk_obj1)
+       return i;
+
+  if (type == DSP_LINE)
+    {
+      for (int i = 0, sz = histItems->size (); i < sz; i++)
+       if (histItems->get (i)->obj != NULL
+           && chk_obj->convertto (Histable::FUNCTION)
+           == histItems->get (i)->obj->convertto (Histable::FUNCTION))
+         return i;
+    }
+  else if (type == DSP_PC)
+    {
+      for (int i = 0, sz = histItems->size (); i < sz; i++)
+       if (histItems->get (i)->obj != NULL
+           && (histItems->get (i)->obj)->convertto (Histable::FUNCTION)
+           == (chk_obj)->convertto (Histable::FUNCTION)
+           && ((DbeLine*) histItems->get (i)->obj->convertto (Histable::LINE))->lineno
+           == ((DbeLine*) chk_obj->convertto (Histable::LINE))->lineno)
+         return i;
+      for (int i = 0, sz = histItems->size (); i < sz; i++)
+       if (histItems->get (i)->obj != NULL
+           && (histItems->get (i)->obj)->convertto (Histable::FUNCTION)
+           == (chk_obj)->convertto (Histable::FUNCTION))
+         return i;
+    }
+
+  // If we clicked on an mfunction line in the called-by call mini in user mode for omp
+  // we might not find that function in func data
+  if (dbev->isOmpDisMode () && type == DSP_FUNCTION)
+    {
+      int p = dbeGetSelIndex (dbevindex, sel_obj, DSP_DISASM, subtype);
+      if (p != -1)
+       return p;
+    }
+  return -1;
+}
+
+// Print data
+//
+char *
+dbePrintData (int dbevindex, int type, int subtype, char *printer,
+             char *fname, FILE *outfile)
+{
+  Histable *current_obj;
+  Function *func;
+  Module *module;
+  MetricList *mlist_orig;
+  bool header;
+  Print_params params;
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+
+  // Set print parameters
+  if (printer != NULL)
+    {
+      params.dest = DEST_PRINTER;
+      params.name = printer;
+    }
+  else if (outfile != NULL)
+    {
+      params.dest = DEST_OPEN_FILE;
+      params.openfile = outfile;
+      params.name = NULL;
+    }
+  else
+    {
+      params.dest = DEST_FILE;
+      params.name = fname;
+      if (*(params.name) == '\0')
+       {
+         free (params.name);
+         return dbe_strdup (GTXT ("Please enter the name of the file to which to print"));
+       }
+    }
+  params.ncopies = 1;
+  if (outfile != NULL)
+    header = false;
+  else
+    header = !(type == DSP_SOURCE || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2);
+
+  params.header = header;
+
+  // figure out what kind of metrics to use
+  if (type == DSP_SELF || type == DSP_CALLER || type == DSP_CALLEE
+      || type == DSP_CALLTREE)
+    mlist_orig = dbev->get_metric_list (MET_CALL);
+  else if (type == DSP_DATAOBJ || type == DSP_DLAYOUT || type == DSP_MEMOBJ)
+    mlist_orig = dbev->get_metric_list (MET_DATA);
+  else if (type == DSP_INDXOBJ)
+    mlist_orig = dbev->get_metric_list (MET_INDX);
+  else if (type == DSP_IOACTIVITY || type == DSP_IOVFD
+          || type == DSP_IOCALLSTACK)
+    mlist_orig = dbev->get_metric_list (MET_IO);
+  else if (type == DSP_HEAPCALLSTACK)
+    mlist_orig = dbev->get_metric_list (MET_HEAP);
+  else
+    mlist_orig = dbev->get_metric_list (MET_NORMAL);
+
+  // make a compacted version of the input list
+  // the list will either be moved to the generated data,
+  //   or freed below if it wasn't needed
+  MetricList *mlist = new MetricList (mlist_orig);
+  Hist_data *data = NULL;
+  er_print_common_display *cd = NULL;
+  int ix;
+  // Set data
+  switch (type)
+    {
+    case DSP_FUNCTION:
+    case DSP_LINE:
+    case DSP_PC:
+    case DSP_MEMOBJ:
+    case DSP_INDXOBJ:
+    case DSP_DATAOBJ:
+      data = dbev->get_hist_data (mlist,
+                                 ((type == DSP_FUNCTION) ? Histable::FUNCTION :
+                                  (type == DSP_LINE) ? Histable::LINE :
+                                  (type == DSP_PC) ? Histable::INSTR :
+                                  (type == DSP_INDXOBJ) ? Histable::INDEXOBJ :
+                                  (type == DSP_MEMOBJ) ? Histable::MEMOBJ
+                                  : Histable::DOBJECT),
+                                 subtype, Hist_data::ALL);
+      if (data->get_status () != Hist_data::SUCCESS)
+       return DbeView::status_str (DbeView::DBEVIEW_NO_DATA); // no strdup()
+
+      cd = new er_print_histogram (dbev, data, mlist, MODE_LIST,
+                                  dbev->get_limit (),
+                                  mlist->get_sort_name (), NULL, true, true);
+      break;
+    case DSP_DLAYOUT:
+      {
+       data = dbev->get_hist_data (mlist, Histable::DOBJECT, 0, Hist_data::LAYOUT);
+       if (data->get_status () != Hist_data::SUCCESS)
+         return DbeView::status_str (DbeView::DBEVIEW_NO_DATA); // no strdup()
+       cd = new er_print_histogram (dbev, data, mlist, MODE_ANNOTATED,
+                                    dbev->get_thresh_dis (),
+                                    mlist->get_sort_name (), NULL, true, true);
+       break;
+      }
+
+      // source and disassembly
+    case DSP_SOURCE:
+    case DSP_DISASM:
+    case DSP_SOURCE_V2:
+    case DSP_DISASM_V2:
+      if (dbev->sel_obj == NULL)
+       return NULL;
+      current_obj = dbev->sel_obj->convertto (Histable::FUNCTION);
+      if (current_obj->get_type () != Histable::FUNCTION)
+       return dbe_strdup (GTXT ("Not a real function; no source or disassembly available."));
+      func = (Function*) current_obj->convertto (Histable::FUNCTION);
+      if (func->flags & FUNC_FLAG_SIMULATED)
+       return dbe_strdup (GTXT ("Not a real function; no source or disassembly available."));
+      if (func->get_name () == NULL)
+       return dbe_strdup (GTXT ("Source location not recorded in experiment"));
+      module = func->module;
+      if (module == NULL || module->get_name () == NULL)
+       return dbe_strdup (GTXT ("Object name not recorded in experiment"));
+      ix = module->loadobject->seg_idx;
+      if (dbev->get_lo_expand (ix) == LIBEX_HIDE)
+       return dbe_strdup (GTXT ("No source or disassembly available for hidden object"));
+      cd = new er_print_histogram (dbev, dbev->func_data, mlist, MODE_ANNOTATED,
+                                  type == DSP_DISASM || type == DSP_DISASM_V2,
+                                  mlist->get_sort_name (),
+                                  func, false, false);
+      break;
+
+      // callers-callees
+    case DSP_SELF:
+    case DSP_CALLER:
+    case DSP_CALLEE:
+      if (dbev->sel_obj == NULL)
+       return NULL;
+      current_obj = dbev->sel_obj->convertto (Histable::FUNCTION);
+      cd = new er_print_histogram (dbev, dbev->func_data, mlist, MODE_GPROF, 1,
+                                  mlist->get_sort_name (), current_obj,
+                                  false, false);
+      break;
+
+      // statistics; this won't use the metric list copied above, so delete it
+    case DSP_STATIS:
+      cd = new er_print_experiment (dbev, 0, dbeSession->nexps () - 1,
+                                   true, true, true, true, false);
+      delete mlist;
+      break;
+    case DSP_EXP:
+      cd = new er_print_experiment (dbev, 0, dbeSession->nexps () - 1,
+                                   true, true, false, false, false);
+      delete mlist;
+      break;
+    case DSP_LEAKLIST:
+      cd = new er_print_leaklist (dbev, true, true, dbev->get_limit ());
+      delete mlist;
+      break;
+    case DSP_HEAPCALLSTACK:
+      cd = new er_print_heapactivity (dbev, Histable::HEAPCALLSTACK, false,
+                                     dbev->get_limit ());
+      delete mlist;
+      break;
+    case DSP_IOACTIVITY:
+      cd = new er_print_ioactivity (dbev, Histable::IOACTFILE, false,
+                                   dbev->get_limit ());
+      delete mlist;
+      break;
+    case DSP_IOVFD:
+      cd = new er_print_ioactivity (dbev, Histable::IOACTVFD, false,
+                                   dbev->get_limit ());
+      delete mlist;
+      break;
+
+      // the io call stack
+    case DSP_IOCALLSTACK:
+      cd = new er_print_ioactivity (dbev, Histable::IOCALLSTACK, false,
+                                   dbev->get_limit ());
+      delete mlist;
+      break;
+
+      // some unknown panel -- return an error string
+    default:
+      delete mlist;
+      return dbe_strdup (GTXT ("Print not available"));
+    }
+
+  // Start printing
+  char *buf = NULL;
+
+  // first open the file/device/whatever
+  if (cd->open (&params) == 0)
+    {
+      // now call the actual print routine
+      cd->data_dump ();
+      if (params.dest == DEST_PRINTER)
+       {
+         if (streq ((char *) params.name, NTXT ("-")))
+           {
+             // Special case - return report to the GUI
+             int maxbytes = 2 * 1024 * 1024; // IPC large buffer limit
+             char *report = cd->get_output (maxbytes);
+             delete data;
+             delete cd;
+             return report; // TEMPORARY
+           }
+       }
+      if (cd->print_output () == false)
+       buf = dbe_sprintf (NTXT ("%s: %s"),
+                          GTXT ("Unable to submit print request to"),
+                          params.name);
+    }
+  else
+    // if unable to set up the print, return an error
+    buf = dbe_sprintf (NTXT ("%s: %s"),
+                      GTXT ("Unable to open file"),
+                      params.name);
+
+  // dbe_free((void *) params.name); XXX when should this happen?
+  if (data)
+    if (data->isViewOwned () == false)
+      delete data;
+  delete cd;
+  return buf;
+}
+
+// Set limit for print data
+//
+char *
+dbeSetPrintLimit (int dbevindex, int limit)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  return (dbev->set_limit (limit));
+}
+
+// get limit for print data
+int
+dbeGetPrintLimit (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  int limit = dbev->get_limit ();
+  return limit;
+}
+
+// set printmode for data
+char *
+dbeSetPrintMode (int dbevindex, char * pmode)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  char *r = dbev->set_printmode (pmode);
+  return r;
+}
+
+// get printmode for data
+int
+dbeGetPrintMode (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  return (dbev->get_printmode ());
+}
+
+// get printmode for data
+char *
+dbeGetPrintModeString (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  return ( dbev->get_printmode_str ());
+}
+
+// get print delimiter for csv data
+char
+dbeGetPrintDelim (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  return (dbev->get_printdelimiter ());
+}
+
+// Set Source/Object/Load-Object file names
+static void
+set_file_names (Function *func, char *names[3])
+{
+  Module *module = func->module;
+  LoadObject *loadobject = module->loadobject;
+  if (loadobject == NULL)
+    loadobject = dbeSession->get_Unknown_LoadObject ();
+  free (names[0]);
+  free (names[1]);
+  free (names[2]);
+  SourceFile *sf = func->getDefSrc ();
+  char *src_name = sf->dbeFile->get_location_info ();
+  DbeFile *df = module->dbeFile;
+  if (df == NULL || (df->filetype & DbeFile::F_JAVACLASS) == 0)
+    df = module->loadobject->dbeFile;
+  char *lo_name = df->get_location_info ();
+  char *dot_o_name = lo_name;
+  if (module->dot_o_file)
+    dot_o_name = module->dot_o_file->dbeFile->get_location_info ();
+  names[0] = dbe_sprintf (NTXT ("%s: %s"), GTXT ("Source File"), src_name);
+  names[1] = dbe_sprintf (NTXT ("%s: %s"), GTXT ("Object File"), dot_o_name);
+  names[2] = dbe_sprintf (NTXT ("%s: %s"), GTXT ("Load Object"), lo_name);
+}
+
+// dbeSetFuncData
+//     Master function to generate all Tab data for the analyzer
+//     Returns the index of the selected item in the specified list
+//
+// After calling it to set up, the Analyzer calls dbeGetFuncList
+//     to format the generated data and return the table
+//     Most of the data is destined for a JTable
+//
+int
+dbeSetFuncData (int dbevindex, Obj sel_obj, int type, int subtype)
+{
+  MetricList *_mlist;
+  Histable *org_obj;
+  Hist_data *data = NULL;
+  int index, sel_index;
+  Function *func;
+  char *name;
+  int ix;
+
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  sel_index = -1;
+  dbev->resetOmpDisMode ();
+  dbev->error_msg = dbev->warning_msg = NULL;
+
+  // get metric list, make a compact duplicate
+  _mlist = dbev->get_metric_list (MET_NORMAL);
+  MetricList *mlist = new MetricList (_mlist);
+
+  // Remove old function/obj list data & Get new function/obj list data
+  org_obj = (Histable *) sel_obj;
+
+  // Figure out which "function" data is being asked for, i.e.,
+  //   which of the analyzer displays is asking for data
+  switch (type)
+    {
+      // the various tables: functions, lines, PCs, DataObjects, IndexObjects
+    case DSP_FUNCTION:
+    case DSP_LINE:
+    case DSP_PC:
+    case DSP_DATAOBJ:
+    case DSP_MEMOBJ:
+    case DSP_INDXOBJ:
+      switch (type)
+       {
+       case DSP_FUNCTION:
+         if (dbev->func_data)
+           delete dbev->func_data;
+         dbev->func_data = data = dbev->get_hist_data (mlist,
+                                  Histable::FUNCTION, subtype, Hist_data::ALL);
+         break;
+       case DSP_LINE:
+         if (dbev->line_data)
+           delete dbev->line_data;
+         dbev->line_data = data = dbev->get_hist_data (mlist,
+                                      Histable::LINE, subtype, Hist_data::ALL);
+         break;
+       case DSP_PC:
+         if (dbev->pc_data)
+           delete dbev->pc_data;
+         dbev->pc_data = data = dbev->get_hist_data (mlist,
+                                     Histable::INSTR, subtype, Hist_data::ALL);
+         break;
+       case DSP_DATAOBJ:
+         if (dbev->dobj_data)
+           delete dbev->dobj_data;
+         mlist = dbev->get_metric_list (MET_DATA);
+         dbev->dobj_data = data = dbev->get_hist_data (mlist,
+                                   Histable::DOBJECT, subtype, Hist_data::ALL);
+         break;
+       case DSP_MEMOBJ:
+         mlist = dbev->get_metric_list (MET_DATA);
+         data = dbev->get_hist_data (mlist, Histable::MEMOBJ, subtype,
+                                     Hist_data::ALL);
+         dbev->indx_data->store (subtype, data);
+         break;
+       case DSP_INDXOBJ:
+         mlist = dbev->get_metric_list (MET_INDX);
+         data = dbev->get_hist_data (mlist, Histable::INDEXOBJ, subtype,
+                                     Hist_data::ALL);
+         dbev->indx_data->store (subtype, data);
+         break;
+       default:
+         break;
+       }
+
+      // Set the selection of row item
+      if (data->get_status () == Hist_data::SUCCESS)
+       {
+         // otherwise, look for it
+         sel_index = -1;
+         if (org_obj)
+           {
+             Hist_data::HistItem *hi;
+             Vec_loop (Hist_data::HistItem*, data->get_hist_items (), index, hi)
+             {
+               if (hi->obj == org_obj)
+                 {
+                   sel_index = index;
+                   break;
+                 }
+             }
+             if (sel_index == -1 && (type == DSP_LINE || type == DSP_PC))
+               {
+                 Vec_loop (Hist_data::HistItem*, data->get_hist_items (), index, hi)
+                 {
+                   name = hi->obj->get_name ();
+                   if (strcmp (name, NTXT ("<Total>")) &&
+                       strcmp (name, GTXT ("<Unknown>")))
+                     {
+                       int done = 0;
+                       switch (type)
+                         {
+                         case DSP_LINE:
+                           if (org_obj->convertto (Histable::FUNCTION)
+                                    == hi->obj->convertto (Histable::FUNCTION))
+                             {
+                               sel_index = index;
+                               done = 1;
+                             }
+                           break;
+                         case DSP_PC:
+                           if (hi->obj->convertto (Histable::FUNCTION)
+                               == org_obj->convertto (Histable::FUNCTION)
+                               && ((DbeLine*) hi->obj->convertto (Histable::LINE))->lineno
+                               == ((DbeLine*) org_obj->convertto (Histable::LINE))->lineno)
+                             {
+                               sel_index = index;
+                               done = 1;
+                             }
+                           break;
+                         }
+                       if (done)
+                         break;
+                     }
+                 }
+               }
+             if (sel_index == -1 && type == DSP_PC)
+               {
+                 Vec_loop (Hist_data::HistItem*, data->get_hist_items (), index, hi)
+                 {
+                   name = hi->obj->get_name ();
+                   if (strcmp (name, NTXT ("<Total>")) &&
+                       strcmp (name, GTXT ("<Unknown>")))
+                     {
+                       int done = 0;
+                       if (hi->obj->convertto (Histable::FUNCTION) ==
+                           org_obj->convertto (Histable::FUNCTION))
+                         {
+                           sel_index = index;
+                           done = 1;
+                         }
+                       if (done)
+                         break;
+                     }
+                 }
+               }
+           }
+         if (sel_index == -1)
+           {
+             Hist_data::HistItem *hi;
+             Vec_loop (Hist_data::HistItem*, data->get_hist_items (), index, hi)
+             {
+               name = hi->obj->get_name ();
+               if (strcmp (name, NTXT ("<Total>")) &&
+                   strcmp (name, GTXT ("<Unknown>")))
+                 {
+                   sel_index = index;
+                   break;
+                 }
+             }
+           }
+       }
+      else
+       dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+      return sel_index;
+      // the end of the code for the regular tables
+
+      // Data Layout
+    case DSP_DLAYOUT:
+      if (dbev->dlay_data)
+       delete dbev->dlay_data;
+      dbev->marks->reset ();
+      mlist = dbev->get_metric_list (MET_DATA);
+
+      // initial dobj list ...
+      data = dbev->get_hist_data (mlist, Histable::DOBJECT, subtype,
+                                 Hist_data::LAYOUT);
+      // .. provides metric data for layout
+      dbev->dlay_data = data = dbev->get_data_space ()->get_layout_data (data,
+                                         dbev->marks, dbev->get_thresh_dis ());
+      if (data->get_status () != Hist_data::SUCCESS)
+       dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+      return sel_index;
+
+      // Source or disassembly
+    case DSP_SOURCE_V2:
+    case DSP_DISASM_V2:
+    case DSP_SOURCE:
+    case DSP_DISASM:
+      {
+       if (org_obj == NULL)
+         {
+           dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_SEL_OBJ);
+           return sel_index;
+         }
+       if (org_obj->get_type () != Histable::FUNCTION)
+         {
+           dbev->error_msg = dbe_strdup (
+            GTXT ("Not a real function; no source or disassembly available."));
+           return sel_index;
+         }
+       func = (Function *) org_obj;
+       if (func->flags & FUNC_FLAG_SIMULATED)
+         {
+           dbev->error_msg = dbe_strdup (
+            GTXT ("Not a real function; no source or disassembly available."));
+           return sel_index;
+         }
+       if (func->get_name () == NULL)
+         {
+           dbev->error_msg = dbe_strdup (
+                          GTXT ("Source location not recorded in experiment"));
+           return sel_index;
+         }
+       Module *module = func->module;
+       if ((module == NULL) || (module->get_name () == NULL))
+         {
+           dbev->error_msg = dbe_strdup (
+                              GTXT ("Object name not recorded in experiment"));
+           return sel_index;
+         }
+       ix = module->loadobject->seg_idx;
+       if (dbev->get_lo_expand (ix) == LIBEX_HIDE)
+         {
+           dbev->error_msg = dbe_strdup (
+                GTXT ("No source or disassembly available for hidden object"));
+           return sel_index;
+         }
+
+       if ((type == DSP_DISASM || type == DSP_DISASM_V2)
+            && dbev->get_view_mode () == VMODE_USER
+           && dbeSession->is_omp_available ())
+         dbev->setOmpDisMode ();
+
+       dbev->marks->reset ();
+       SourceFile *srcContext = NULL;
+       switch (dbev->sel_obj->get_type ())
+         {
+         case Histable::FUNCTION:
+           {
+             Function *f = (Function *) dbev->sel_obj;
+             srcContext = f->getDefSrc ();
+             dbev->sel_binctx = f->module;
+             break;
+           }
+         case Histable::LINE:
+           {
+             DbeLine *dl = (DbeLine *) dbev->sel_obj;
+             srcContext = dl->sourceFile;
+             Function *f = dl->func;
+             if (f)
+               dbev->sel_binctx = f;
+             break;
+           }
+         case Histable::INSTR:
+           {
+             Function *f = (Function *) dbev->sel_obj->convertto (Histable::FUNCTION);
+             if (f)
+               {
+                 dbev->sel_binctx = f;
+                 srcContext = f->getDefSrc ();
+               }
+             break;
+           }
+         default:
+           break;
+         }
+       mlist = dbev->get_metric_list (MET_SRCDIS);
+
+       // for source and disassembly the name needs to be invisible,
+       //      but that's handled in the module code
+       if (type == DSP_SOURCE)
+         {
+           if (dbev->src_data)
+             delete dbev->src_data;
+
+           // func_data computation needed for get_totals
+           if (dbev->func_data == NULL)
+             dbev->func_data = data = dbev->get_hist_data (mlist,
+                                  Histable::FUNCTION, subtype, Hist_data::ALL);
+           dbev->marks2dsrc->reset ();
+           dbev->marks2dsrc_inc->reset ();
+           data = dbev->src_data = module->get_data (dbev, mlist,
+                         Histable::LINE, dbev->func_data->get_totals ()->value,
+                         srcContext, func, dbev->marks,
+                         dbev->get_thresh_src (), dbev->get_src_compcom (),
+                         dbev->get_src_visible (), dbev->get_hex_visible (),
+                         false, false, dbev->marks2dsrc, dbev->marks2dsrc_inc);
+           set_file_names (func, dbev->names_src);
+           if (srcContext)
+             {
+               free (dbev->names_src[0]);
+               dbev->names_src[0] = dbe_sprintf (GTXT ("Source File: %s"),
+                                    srcContext->dbeFile->get_location_info ());
+             }
+           Obj obj = (Obj) func->convertto (Histable::LINE, srcContext);
+           sel_index = dbeGetSelIndex (dbevindex, obj, type, subtype);
+         }
+       else
+         { /* type == DSP_DISASM */
+           if (dbev->dis_data)
+             delete dbev->dis_data;
+
+           // func_data computation needed for get_totals
+           if (dbev->func_data == NULL)
+             dbev->func_data = data = dbev->get_hist_data (mlist,
+                                 Histable::FUNCTION, subtype, Hist_data::ALL);
+           dbev->marks2ddis->reset ();
+           dbev->marks2ddis_inc->reset ();
+           data = dbev->dis_data = module->get_data (dbev, mlist,
+                        Histable::INSTR, dbev->func_data->get_totals ()->value,
+                        srcContext, func, dbev->marks, dbev->get_thresh_dis (),
+                        dbev->get_dis_compcom (), dbev->get_src_visible (),
+                        dbev->get_hex_visible (), dbev->get_func_scope (),
+                        false, dbev->marks2ddis, dbev->marks2ddis_inc);
+           set_file_names (func, dbev->names_dis);
+           if (srcContext)
+             {
+               free (dbev->names_dis[0]);
+               dbev->names_dis[0] = dbe_sprintf (GTXT ("Source File: %s"),
+                                   srcContext->dbeFile->get_location_info ());
+             }
+           Obj obj = (Obj) func->convertto (Histable::INSTR);
+           sel_index = dbeGetSelIndex (dbevindex, obj, type, subtype);
+         }
+       return sel_index;
+      }
+
+      // the three cases for caller-callee
+    case DSP_SELF:
+    case DSP_CALLER:
+    case DSP_CALLEE:
+      if (org_obj == NULL)
+       {
+         dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_SEL_OBJ);
+         return sel_index;
+       }
+
+      // Caller data
+      if (dbev->callers)
+       delete dbev->callers;
+      mlist = dbev->get_metric_list (MET_CALL);
+      dbev->callers = dbev->get_hist_data (mlist, Histable::FUNCTION, subtype,
+                                          Hist_data::CALLERS, org_obj);
+      if (dbev->callers->get_status () != Hist_data::SUCCESS)
+       {
+         dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+         return sel_index;
+       }
+
+      // Callee data
+      if (dbev->callees)
+       delete dbev->callees;
+      dbev->callees = dbev->get_hist_data (mlist, Histable::FUNCTION, subtype,
+                                          Hist_data::CALLEES, org_obj);
+      if (dbev->callees->get_status () != Hist_data::SUCCESS)
+       {
+         dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+         return sel_index;
+       }
+
+      // Center Function item
+      if (dbev->fitem_data)
+       delete dbev->fitem_data;
+      dbev->fitem_data = dbev->get_hist_data (mlist, Histable::FUNCTION, subtype,
+                                             Hist_data::SELF, org_obj);
+      if (dbev->fitem_data->get_status () != Hist_data::SUCCESS)
+       {
+         dbev->error_msg = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+         return sel_index;
+       }
+      return sel_index;
+    default:
+      abort ();
+    }
+  return sel_index;
+}
+
+Vector<void*>*
+dbeGetTotals (int dbevindex, int dsptype, int subtype)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  MetricList *mlist = dbev->get_metric_list (dsptype, subtype);
+  Hist_data *data = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+                                        Hist_data::ALL);
+  Hist_data::HistItem *totals = data->get_totals ();
+  Vector<void*> *tbl = new Vector<void*>(mlist->size ());
+  for (long i = 0, sz = mlist->size (); i < sz; i++)
+    {
+      Metric *m = mlist->get (i);
+      switch (m->get_vtype ())
+       {
+       case VT_DOUBLE:
+         {
+           Vector<double> *lst = new Vector<double>(1);
+           lst->append (totals->value[i].d);
+           tbl->append (lst);
+           break;
+         }
+       case VT_INT:
+         {
+           Vector<int> *lst = new Vector<int>(1);
+           lst->append (totals->value[i].i);
+           tbl->append (lst);
+           break;
+         }
+       case VT_LLONG:
+       case VT_ULLONG:
+       case VT_ADDRESS:
+         {
+           Vector<long long> *lst = new Vector<long long>(1);
+           lst->append (totals->value[i].ll);
+           tbl->append (lst);
+           break;
+         }
+       case VT_LABEL:
+         {
+           Vector<char *> *lst = new Vector<char *>(1);
+           Histable::NameFormat nfmt = dbev->get_name_format ();
+           lst->append (dbe_strdup (totals->obj->get_name (nfmt)));
+           tbl->append (lst);
+           break;
+         }
+       default:
+         abort ();
+       }
+    }
+  Vector<void*> *res = new Vector<void*>(2);
+  res->append (dbeGetMetricList (mlist));
+  res->append (tbl);
+  return res;
+}
+
+Vector<void*>*
+dbeGetHotMarks (int dbevindex, int type)
+{
+  Vector<void*>* table = new Vector<void*>(2);
+  Vector<int>* table0 = new Vector<int> ();
+  Vector<int>* table1 = new Vector<int> ();
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    return NULL;
+
+  switch (type)
+    {
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+      for (int i = 0; i < dbev->marks2dsrc->size (); i++)
+       {
+         table0->append (dbev->marks2dsrc->fetch (i).index1);
+         table1->append (dbev->marks2dsrc->fetch (i).index2);
+       }
+      break;
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      for (int i = 0; i < dbev->marks2ddis->size (); i++)
+       {
+         table0->append (dbev->marks2ddis->fetch (i).index1);
+         table1->append (dbev->marks2ddis->fetch (i).index2);
+       }
+      break;
+    default:
+      break;
+    }
+  table->store (0, table0);
+  table->store (1, table1);
+  return table;
+}
+
+Vector<void*>*
+dbeGetHotMarksInc (int dbevindex, int type)
+{
+  Vector<void*>* table = new Vector<void*>(2);
+  Vector<int>* table0 = new Vector<int> ();
+  Vector<int>* table1 = new Vector<int> ();
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    return NULL;
+
+  switch (type)
+    {
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+      for (int i = 0; i < dbev->marks2dsrc_inc->size (); i++)
+       {
+         table0->append (dbev->marks2dsrc_inc->fetch (i).index1);
+         table1->append (dbev->marks2dsrc_inc->fetch (i).index2);
+       }
+      break;
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      for (int i = 0; i < dbev->marks2ddis_inc->size (); i++)
+       {
+         table0->append (dbev->marks2ddis_inc->fetch (i).index1);
+         table1->append (dbev->marks2ddis_inc->fetch (i).index2);
+       }
+      break;
+    default:
+      break;
+    }
+  table->store (0, table0);
+  table->store (1, table1);
+  return table;
+}
+
+Vector<void*>*
+dbeGetSummaryHotMarks (int dbevindex, Vector<Obj> *sel_objs, int type)
+{
+  Vector<void*>* table = new Vector<void*>(2);
+  Vector<int>* table0 = new Vector<int> ();
+  Vector<int>* table1 = new Vector<int> ();
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    return NULL;
+  if (sel_objs == NULL || sel_objs->size () == 0)
+    return NULL;
+
+  Hist_data *data;
+  Vector<int_pair_t> *marks2d;
+  Vector<int_pair_t>* marks2d_inc;
+  switch (type)
+    {
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+      data = dbev->src_data;
+      marks2d = dbev->marks2dsrc;
+      marks2d_inc = dbev->marks2dsrc_inc;
+      break;
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      data = dbev->dis_data;
+      marks2d = dbev->marks2ddis;
+      marks2d_inc = dbev->marks2ddis_inc;
+      break;
+    default:
+      data = NULL;
+      marks2d = NULL;
+      marks2d_inc = NULL;
+      break;
+    }
+  if (data == NULL || data->get_status () != Hist_data::SUCCESS
+      || marks2d_inc == NULL || marks2d == NULL)
+    return NULL;
+
+  MetricList *orig_mlist = data->get_metric_list ();
+  MetricList *prop_mlist = new MetricList (dbev->get_metric_ref (MET_NORMAL));
+  if (prop_mlist && dbev->comparingExperiments ())
+    prop_mlist = dbev->get_compare_mlist (prop_mlist, 0);
+  Metric *mitem;
+  int index, index2;
+  index2 = 0;
+  Vec_loop (Metric*, prop_mlist->get_items (), index, mitem)
+  {
+    if (mitem->get_subtype () == Metric::STATIC)
+      continue;
+
+    for (int i = 0; i < marks2d_inc->size (); i++)
+      {
+       int found = 0;
+       for (int j = 0; j < sel_objs->size (); j++)
+         {
+           int sel_index = (int) sel_objs->fetch (j);
+           int marked_index = marks2d_inc->fetch (i).index1;
+           if (sel_index == marked_index)
+             {
+               found = 1;
+               break;
+             }
+         }
+       if (!found)
+         continue;
+       int mindex = marks2d_inc->fetch (i).index2;
+       Metric *orig_metric = orig_mlist->get_items ()->fetch (mindex);
+       if (orig_metric->get_id () == mitem->get_id ()
+           && mitem->get_subtype () == Metric::INCLUSIVE)
+         {
+           table0->append (index2);
+           table1->append (1);
+         }
+      }
+
+    for (int i = 0; i < marks2d->size (); i++)
+      {
+       int found = 0;
+       for (int j = 0; j < sel_objs->size (); j++)
+         {
+           int sel_index = (int) sel_objs->fetch (j);
+           int marked_index = marks2d->fetch (i).index1;
+           if (sel_index == marked_index)
+             {
+               found = 1;
+               break;
+             }
+         }
+       if (!found)
+         continue;
+       int mindex = marks2d->fetch (i).index2;
+       Metric *orig_metric = orig_mlist->get_items ()->fetch (mindex);
+       if (orig_metric->get_id () == mitem->get_id ()
+           && mitem->get_subtype () == Metric::EXCLUSIVE)
+         {
+           table0->append (index2);
+           table1->append (0);
+         }
+      }
+    if (!(mitem->get_subtype () == Metric::EXCLUSIVE
+         || mitem->get_subtype () == Metric::DATASPACE))
+      index2++;
+  }
+  table->store (0, table0);
+  table->store (1, table1);
+  return table;
+}
+
+// Get a vector of function ids of data(begin, begin + length - 1)
+// Currently only support source/disassembly view
+Vector<uint64_t>*
+dbeGetFuncId (int dbevindex, int type, int begin, int length)
+{
+  Vector<uint64_t>* table = new Vector<uint64_t > ();
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+
+  Hist_data *data;
+  Function* given_func = NULL;
+  switch (type)
+    {
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+      data = dbev->src_data;
+      break;
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      data = dbev->dis_data;
+      break;
+    default:
+      data = NULL;
+      abort ();
+    }
+
+  if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+    return NULL;
+
+  if (begin < 0 || begin + length > data->size ())
+    return NULL;
+
+  switch (type)
+    {
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      {
+       for (int i = begin; i < begin + length; i++)
+         {
+           given_func = NULL;
+           Histable * sel_obj = data->fetch (i)->obj;
+           if (sel_obj != NULL)
+             given_func = (Function*) (sel_obj)->convertto (Histable::FUNCTION, (Histable*) dbev);
+           if (given_func == NULL)
+             table->append (0);
+           else
+             table->append (given_func->id);
+         }
+      }
+      break;
+    default:
+      abort ();
+    }
+  return table;
+}
+
+Vector<void*>*
+dbeGetFuncCallerInfo (int dbevindex, int type, Vector<int>* idxs, int groupId)
+{
+  Vector<void*>* data = new Vector<void*>();
+  if (type == DSP_SOURCE_V2 || type == DSP_DISASM_V2)
+    {
+      Obj sel_func = dbeGetSelObj (dbevindex, DSP_FUNCTION, 0);
+      if (sel_func == 0)
+       return data;
+      Vector<Obj> * cmpObjs = dbeGetComparableObjsV2 (dbevindex, sel_func, type);
+      if (cmpObjs == NULL)
+       return data;
+      DbeView *dbev = dbeSession->getView (dbevindex);
+      int mtype = MET_COMMON | COMPARE_BIT | ((groupId + 1) << GROUP_ID_SHIFT);
+      MetricList *mlist = dbev->get_metric_list ((MetricType) (mtype & MTYPE_MASK),
+                                                (mtype & COMPARE_BIT) != 0,
+                                                mtype >> GROUP_ID_SHIFT);
+      Histable *selObj = (Histable *) cmpObjs->fetch (groupId);
+      int subtype = 0;
+      Hist_data *hist_data = dbev->get_data (mlist, selObj, type, subtype);
+      if (hist_data == NULL)
+       return data;
+    }
+  for (int i = 0; i < idxs->size (); i++)
+    data->append (dbeGetFuncCallerInfoById (dbevindex, type, idxs->fetch (i)));
+  return data;
+}
+
+//
+// Get Table of Caller info:
+// param: idx -- selected AT_FUNC row
+// return: callsite_id, callsite_name (function: file: line)
+Vector<void*>*
+dbeGetFuncCallerInfoById (int dbevindex, int type, int idx)
+{
+  Vector<void*>* table = new Vector<void*>(3);
+  Vector<uint64_t>* table0 = new Vector<uint64_t> ();
+  Vector<int>* table1 = new Vector<int> ();
+  Vector<char*>* table2 = new Vector<char*>();
+
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Hist_data *data;
+  Function* given_func = NULL;
+  Vector<Histable*> *instr_info = NULL;
+  switch (type)
+    {
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+      data = dbev->src_data;
+      break;
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      data = dbev->dis_data;
+      break;
+    default:
+      data = NULL;
+      abort ();
+    }
+  if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+    return NULL;
+
+  if (idx < 0 || idx >= data->size ())
+    return NULL;
+  switch (type)
+    {
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      {
+       Histable * sel_obj = data->fetch (idx)->obj;
+       if (sel_obj == NULL)
+         return NULL;
+       given_func = (Function*) (sel_obj)->convertto (Histable::FUNCTION, (Histable*) dbev);
+       if (given_func == NULL)
+         return NULL;
+       PathTree * ptree = dbev->get_path_tree ();
+       if (ptree == NULL)
+         return NULL;
+       instr_info = ptree->get_clr_instr (given_func);
+       DefaultMap<uint64_t, int> * line_seen = new DefaultMap<uint64_t, int>();
+       for (int j = 0; j < ((Vector<Histable*>*)instr_info)->size (); j++)
+         {
+           Histable *instr = ((Vector<Histable*>*)instr_info)->fetch (j);
+           Function *cur_func = NULL;
+           if (instr->get_type () == Histable::INSTR)
+             cur_func = ((DbeInstr*) instr)->func;
+           else if (instr->get_type () == Histable::LINE)
+             cur_func = ((DbeLine*) instr)->func;
+           if (cur_func == NULL || (cur_func->flags & FUNC_FLAG_SIMULATED))
+               continue; // skip functions like <Total>
+           Histable* line;
+           switch (type)
+             {
+             case DSP_SOURCE:
+             case DSP_SOURCE_V2:
+               if (cur_func != NULL)
+                 {
+                   SourceFile *sourceFile = cur_func->getDefSrc ();
+                   if (sourceFile == NULL ||
+                       (sourceFile->flags & SOURCE_FLAG_UNKNOWN) != 0)
+                     continue; // skip functions like <Function: %s, instructions without line numbers>
+                 }
+               line = instr->convertto (Histable::LINE, NULL);
+               break;
+             case DSP_DISASM:
+             case DSP_DISASM_V2:
+               line = instr->convertto (Histable::INSTR, NULL);
+               break;
+             default:
+               abort ();
+             }
+           uint64_t func_id = cur_func->id;
+           uint64_t line_id = instr->id;
+           int is_null = 0;
+           int line_no = -1;
+           switch (type)
+             {
+             case DSP_SOURCE:
+             case DSP_SOURCE_V2:
+               is_null = (((DbeLine*) line)->func == NULL) ? 1 : 0;
+               if (is_null)
+                 ((DbeLine*) line)->func = cur_func;
+               line_no = ((DbeLine*) line)->lineno;
+               if (line_seen->get (line_id) == 0)
+                 {
+                   line_seen->put (line_id, 1);
+                   table0->append (func_id);
+                   table1->append (line_no);
+                   Histable::NameFormat nfmt = dbev->get_name_format ();
+                   table2->append (dbe_strdup (line->get_name (nfmt)));
+                 }
+               if (is_null)
+                 ((DbeLine*) line)->func = NULL;
+               break;
+             case DSP_DISASM:
+             case DSP_DISASM_V2:
+               is_null = (((DbeInstr*) line)->func == NULL) ? 1 : 0;
+               if (is_null)
+                 ((DbeInstr*) line)->func = cur_func;
+               line_no = ((DbeInstr*) line)->addr;
+               if (line_seen->get (line_id) == 0)
+                 {
+                   line_seen->put (line_id, 1);
+                   table0->append (func_id);
+                   table1->append (line_no);
+                   Histable::NameFormat nfmt = dbev->get_name_format ();
+                   table2->append (dbe_strdup (line->get_name (nfmt)));
+                 }
+               if (is_null)
+                 ((DbeInstr*) line)->func = NULL;
+               break;
+             default:
+               abort ();
+             }
+        }
+       delete line_seen;
+       delete instr_info;
+      }
+      break;
+    default:
+      abort ();
+    }
+  table->store (0, table0);
+  table->store (1, table1);
+  table->store (2, table2);
+  return table;
+}
+
+Vector<void*>*
+dbeGetFuncCalleeInfo (int dbevindex, int type, Vector<int>* idxs, int groupId)
+{
+  Vector<void*>* data = new Vector<void*>();
+  if (type == DSP_SOURCE_V2 || type == DSP_DISASM_V2)
+    {
+      Obj sel_func = dbeGetSelObj (dbevindex, DSP_FUNCTION, 0);
+      if (sel_func == 0)
+       return data;
+      Vector<Obj> * cmpObjs = dbeGetComparableObjsV2 (dbevindex, sel_func, type);
+      if (cmpObjs == NULL)
+       return data;
+      DbeView *dbev = dbeSession->getView (dbevindex);
+      int mtype = MET_COMMON | COMPARE_BIT | ((groupId + 1) << GROUP_ID_SHIFT);
+      MetricList *mlist = dbev->get_metric_list ((MetricType) (mtype & MTYPE_MASK),
+                                                (mtype & COMPARE_BIT) != 0,
+                                                mtype >> GROUP_ID_SHIFT);
+      Histable *selObj = (Histable *) cmpObjs->fetch (groupId);
+      int subtype = 0;
+      Hist_data *hist_data = dbev->get_data (mlist, selObj, type, subtype);
+      if (hist_data == NULL)
+       return data;
+    }
+
+  for (int i = 0; i < idxs->size (); i++)
+    data->append (dbeGetFuncCalleeInfoById (dbevindex, type, idxs->fetch (i)));
+  return data;
+}
+
+//
+// Get Table of Callee info:
+// param: idx -- selected AT_FUNC row
+// return: callsite_row, callee_id, callee_name
+//
+Vector<void*>*
+dbeGetFuncCalleeInfoById (int dbevindex, int type, int idx)
+{
+  Vector<void*>* table = new Vector<void*>(3);
+  Vector<int>* table0 = new Vector<int>();
+  Vector<uint64_t>* table1 = new Vector<uint64_t > ();
+  Vector<char*>* table2 = new Vector<char*>();
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Hist_data *data;
+  Function* given_func = NULL;
+  Vector<Histable*> *instr_info = NULL;
+  Vector<void*> *func_info = NULL;
+
+  switch (type)
+    {
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+      data = dbev->src_data;
+      break;
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      data = dbev->dis_data;
+      break;
+    default:
+      data = NULL;
+      abort ();
+    }
+  if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+    return NULL;
+  if (idx < 0 || idx >= data->size ())
+    return NULL;
+  switch (type)
+    {
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      {
+       Histable * sel_obj = data->fetch (idx)->obj;
+       if (sel_obj == NULL)
+         return NULL;
+       given_func = (Function*) (sel_obj)->convertto (Histable::FUNCTION, (Histable*) dbev);
+       if (given_func == NULL)
+         return NULL;
+       PathTree * ptree = dbev->get_path_tree ();
+       if (ptree == NULL)
+         return NULL;
+       Vector<Histable*> *instrs = NULL;
+       Vector<void*> *callee_instrs = ptree->get_cle_instr (given_func, instrs);
+       func_info = new Vector<void*>();
+       instr_info = new Vector<Histable*>();
+       for (long a = 0, sz_a = callee_instrs ? callee_instrs->size () : 0; a < sz_a; a++)
+         {
+           Vector<Histable*> *temp = ((Vector<Vector<Histable*>*>*)callee_instrs)->get (a);
+           DefaultMap<Function*, int> * func_seen = new DefaultMap<Function*, int>();
+           Histable* instr0 = (Histable*) instrs->fetch (a);
+           for (long b = 0, sz_b = temp ? temp->size () : 0; b < sz_b; b++)
+             {
+               Histable *instr = temp->get (b);
+               if (instr->get_type () == Histable::INSTR)
+                 {
+                   Function* func1 = ((DbeInstr *) instr)->func;
+                   func_seen->put (func1, 1);
+                 }
+               else if (instr->get_type () == Histable::LINE)
+                 {
+                   Function* func1 = ((DbeLine *) instr)->func;
+                   func_seen->put (func1, 1);
+                 }
+             }
+           Vector<Function*> *funcs = func_seen->keySet ();
+           delete func_seen;
+           if (funcs->size () > 0)
+             {
+               instr_info->append (instr0);
+               func_info->append (funcs);
+             }
+         }
+       delete instrs;
+       destroy (callee_instrs);
+
+       DefaultMap<uint64_t, Vector<int>* > * instr_idxs = new DefaultMap<uint64_t, Vector<int>* >();
+       DefaultMap<uint64_t, int> * func_idxs = new DefaultMap<uint64_t, int>();
+       for (long j = 0, sz_j = instr_info ? instr_info->size () : 0; j < sz_j; j++)
+         {
+           Histable *instr = instr_info->get (j);
+           Function *cur_func = NULL;
+           if (instr->get_type () == Histable::INSTR)
+             cur_func = ((DbeInstr*) instr)->func;
+           else if (instr->get_type () == Histable::LINE)
+             cur_func = ((DbeLine*) instr)->func;
+           if (cur_func != NULL && (cur_func->flags & FUNC_FLAG_SIMULATED))
+             continue; // skip functions like <Total>
+           Histable* line;
+           switch (type)
+             {
+             case DSP_SOURCE:
+             case DSP_SOURCE_V2:
+               if (cur_func != NULL)
+                 {
+                   SourceFile *sourceFile = cur_func->getDefSrc ();
+                   if (sourceFile == NULL ||
+                       (sourceFile->flags & SOURCE_FLAG_UNKNOWN) != 0)
+                     // skip functions like <Function: %s, instructions without line numbers>
+                     continue;
+                 }
+               line = instr->convertto (Histable::LINE, NULL);
+               if (type == DSP_SOURCE_V2)
+                 line = dbev->get_compare_obj (line);
+               break;
+             case DSP_DISASM:
+             case DSP_DISASM_V2:
+               line = instr;
+               if (type == DSP_DISASM_V2)
+                 line = dbev->get_compare_obj (line);
+               break;
+             default:
+               abort ();
+             }
+           if (func_idxs->get (line->id) == 0)
+             {
+               func_idxs->put (line->id, 1);
+               Vector<int> *temp_idx = new Vector<int>();
+               temp_idx->append (j);
+               instr_idxs->put (line->id, temp_idx);
+             }
+           else
+             {
+               Vector<int> *temp_idx = instr_idxs->get (line->id);
+               temp_idx->append (j);
+             }
+         }
+       for (long i = 0; i < data->size (); i++)
+         {
+           Histable* line = data->fetch (i)->obj;
+           if (line == NULL)
+             continue;
+           Vector<int> * instr_idx = instr_idxs->get (line->id);
+           if (instr_idx == NULL)
+             continue;
+           for (long j = 0; j < instr_idx->size (); j++)
+             {
+               Vector<void*>* callee_funcs_vec = (Vector<void*>*)func_info;
+               if (callee_funcs_vec->size () == 0)
+                 continue;
+               Vector<Function*>* callee_funcs_value = (Vector<Function*>*)callee_funcs_vec->fetch (instr_idx->fetch (j));
+               for (int k = 0; callee_funcs_value != NULL && k < callee_funcs_value->size (); k++)
+                 {
+                   uint64_t funcobj_id = ((Function*) callee_funcs_value->fetch (k))->id;
+                   int old_size = table0->size ();
+                   if (old_size > 0 && i == table0->fetch (old_size - 1)
+                       && funcobj_id == table1->fetch (old_size - 1))
+                     continue;
+                   table0->append (i);
+                   table1->append (funcobj_id);
+                   table2->append (dbe_strdup (((Function*) callee_funcs_value->fetch (k))->get_name ()));
+                 }
+             }
+         }
+       delete instr_idxs;
+       delete func_idxs;
+       destroy (func_info);
+       delete instr_info;
+      }
+      break;
+    default:
+      abort ();
+    }
+  table->store (0, table0);
+  table->store (1, table1);
+  table->store (2, table2);
+  return table;
+}
+
+//
+// Get Table of Function List data with only total values
+//
+Vector<void*> *
+dbeGetFuncListMini (int dbevindex, int type, int /*subtype*/)
+{
+  Hist_data *data;
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  switch (type)
+    {
+    case DSP_FUNCTION:
+      data = dbev->func_data;
+      break;
+    default:
+      data = NULL;
+      break;
+    }
+  if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+    return NULL;
+
+  MetricList *mlist = data->get_metric_list ();
+
+  // Get table size: count visible metrics
+  int nvisible = 0;
+  for (long i = 0, sz = mlist->size (); i < sz; i++)
+    {
+      Metric *m = mlist->get (i);
+      if (m->is_visible () || m->is_tvisible () || m->is_pvisible ())
+       nvisible++;
+    }
+  Vector<void*> *table = new Vector<void*>(nvisible + 1);
+
+  // Fill function list elements
+  Hist_data::HistItem *totals = data->get_totals ();
+  for (long i = 0, sz = mlist->size (); i < sz; i++)
+    {
+      Metric *m = mlist->get (i);
+      if (!m->is_visible () && !m->is_tvisible () && !m->is_pvisible ())
+       continue;
+      TValue res;
+      TValue *v = data->get_value (&res, i, totals);
+      if ((m->get_visbits () & VAL_RATIO) != 0)
+       {
+         Vector<double> *col = new Vector<double>(1);
+         double d = (v->tag != VT_LABEL) ? v->to_double () : 100.; // NaN
+         col->append (d);
+         table->append (col);
+         continue;
+       }
+      switch (m->get_vtype ())
+       {
+       case VT_INT:
+         {
+           Vector<int> *col = new Vector<int>(1);
+           col->append (v->i);
+           table->append (col);
+           break;
+         }
+       case VT_ADDRESS:
+       case VT_ULLONG:
+       case VT_LLONG:
+         {
+           Vector<long long> *col = new Vector<long long>(1);
+           col->append (v->ll);
+           table->append (col);
+           break;
+         }
+       case VT_LABEL:
+         {
+           Vector<char *> *col = new Vector<char *>(1);
+           col->append (dbe_strdup (v->l));
+           table->append (col);
+           break;
+         }
+       case VT_DOUBLE:
+       default:
+         {
+           Vector<double> *col = new Vector<double>(1);
+           col->append (v->d);
+           table->append (col);
+           break;
+         }
+       }
+    }
+  table->append (NULL);
+  return table;
+}
+
+// Get Table of Function List data
+Vector<void*> *
+dbeGetFuncList (int dbevindex, int type, int subtype)
+{
+  MetricList *mlist;
+  Metric *mitem;
+  int nitems, nvisible;
+  int index, index2, nv;
+  char *cell;
+  Vector<int> *ji_list;
+  Hist_data *data;
+  Hist_data::HistItem *item;
+
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+
+  // fprintf(stderr, NTXT("XXX dbeGetFuncList, FuncListDisp_type = %d\n"), type);
+  switch (type)
+    {
+    case DSP_FUNCTION:
+      data = dbev->func_data;
+      break;
+    case DSP_LINE:
+      data = dbev->line_data;
+      break;
+    case DSP_PC:
+      data = dbev->pc_data;
+      break;
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+      data = dbev->src_data;
+      break;
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      data = dbev->dis_data;
+      break;
+    case DSP_SELF:
+      data = dbev->fitem_data;
+      break;
+    case DSP_CALLER:
+      data = dbev->callers;
+      break;
+    case DSP_CALLEE:
+      data = dbev->callees;
+      break;
+    case DSP_DLAYOUT:
+      data = dbev->dlay_data;
+      break;
+    case DSP_DATAOBJ:
+      data = dbev->dobj_data;
+      break;
+    case DSP_MEMOBJ:
+    case DSP_INDXOBJ:
+      data = dbev->get_indxobj_data (subtype);
+      break;
+    default:
+      data = NULL;
+      break;
+    }
+  if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+    return NULL;
+  mlist = data->get_metric_list ();
+
+  // Get table size: count visible metrics
+  nitems = data->size ();
+  nvisible = 0;
+  Vec_loop (Metric*, mlist->get_items (), index, mitem)
+  {
+    if (mitem->is_visible () || mitem->is_tvisible () || mitem->is_pvisible ())
+      nvisible++;
+  }
+
+  // Initialize Java String array
+  Vector<void*> *table = new Vector<void*>(nvisible + 1);
+
+  // Mark Hi-value metric items for annotated src/dis/layout
+  if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_DLAYOUT
+      || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2)
+    {
+      ji_list = new Vector<int>(nitems);
+
+      if (dbev->marks->size () > 0)
+       index = dbev->marks->fetch (0);
+      else
+       index = -1;
+      int mindex = 0;
+      for (index2 = 0; index2 < nitems; index2++)
+       {
+         item = data->fetch (index2);
+         if (index2 == index)
+           {
+             ji_list->store (index2, -item->type);
+             if (++mindex < dbev->marks->size ())
+               index = dbev->marks->fetch (mindex);
+             else
+               index = -1;
+           }
+         else
+           ji_list->store (index2, item->type);
+       }
+      table->store (nvisible, ji_list);
+    }
+  else
+    table->store (nvisible, NULL);
+
+  // Fill function list elements
+  nv = 0;
+
+  Vec_loop (Metric*, mlist->get_items (), index, mitem)
+  {
+    if (!mitem->is_visible () && !mitem->is_tvisible () &&
+       !mitem->is_pvisible ())
+      continue;
+
+    // Fill values
+    switch (mitem->get_vtype ())
+      {
+      case VT_LABEL:
+       {
+         Vector<char*> *jobjects = new Vector<char*>(nitems);
+         char *buf = NULL;
+         size_t bufsz = 0;
+         int lspace = 0;
+         if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2
+             || type == DSP_DISASM_V2)
+           {
+             // if this is source or disassembly, where we'll insert
+             //        a preface into the output line, figure out how wide
+             //        it needs to be
+             // first, scan all the lines, to get the maximum line number
+             bufsz = 1024;
+             buf = (char *) malloc (bufsz);
+             int max_lineno = 0;
+             int hidx;
+             Hist_data::HistItem *hitem;
+             Vec_loop (Hist_data::HistItem*, data, hidx, hitem)
+             {
+               if (!hitem->obj)
+                 continue;
+               if (hitem->obj->get_type () == Histable::LINE &&
+                   ((DbeLine*) hitem->obj)->lineno > max_lineno)
+                 max_lineno = ((DbeLine*) hitem->obj)->lineno;
+               else if (hitem->obj->get_type () == Histable::INSTR
+                        && ((DbeInstr*) hitem->obj)->lineno > max_lineno)
+                 max_lineno = ((DbeInstr*) hitem->obj)->lineno;
+             }
+
+             // we have the maximum integer over all linenumbers in the file
+             //        figure out how many digits are needed
+             lspace = snprintf (buf, bufsz, NTXT ("%d"), max_lineno);
+           }
+         for (index2 = 0; index2 < nitems; index2++)
+           {
+             item = data->fetch (index2);
+             if (type == DSP_DLAYOUT)
+               cell = dbe_strdup (((DataObject*) (item->obj))->get_offset_name ());
+             else if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2)
+               {
+                 // This code is duplicated in output.cc, yet it's
+                 // intended for presentation purpose and thus is
+                 // potentially different for er_print and analyzer.
+                 switch (item->type)
+                   {
+                   case Module::AT_SRC_ONLY:
+                   case Module::AT_SRC:
+                     if (item->obj == NULL)
+                       snprintf (buf, bufsz, NTXT (" %*c. "), lspace, ' ');
+                     else
+                       snprintf (buf, bufsz, NTXT (" %*d. "), lspace, ((DbeLine*) item->obj)->lineno);
+                     break;
+                   case Module::AT_FUNC:
+                   case Module::AT_QUOTE:
+                     snprintf (buf, bufsz, NTXT ("%*c"), lspace + 3, ' ');
+                     break;
+                   case Module::AT_DIS:
+                   case Module::AT_DIS_ONLY:
+                     if (item->obj == NULL || ((DbeInstr*) item->obj)->lineno == -1)
+                       snprintf (buf, bufsz, NTXT ("%*c[%*s] "), lspace + 3, ' ', lspace, NTXT ("?"));
+                     else
+                       snprintf (buf, bufsz, NTXT ("%*c[%*d] "), lspace + 3, ' ', lspace,
+                                 ((DbeInstr*) item->obj)->lineno);
+                     break;
+                   case Module::AT_COM:
+                   case Module::AT_EMPTY:
+                     *buf = (char) 0;
+                     break;
+                   }
+                 // get the line's text
+                 char *s = item->value[index].l;
+                 if (s != NULL)
+                   {
+                     // copy the string expanding all tabulations
+                     // (JTable doesn't render them)
+                     char *d = buf + strlen (buf);
+                     char c;
+                     size_t column = 0;
+                     do
+                       {
+                         c = *s++;
+                         if (c == '\t')
+                           {
+                             do
+                               {
+                                 *d++ = ' ';
+                                 column++;
+                               }
+                             while (column & 07);
+                           }
+                         else
+                           {
+                             *d++ = c;
+                             column++;
+                           }
+                         if (column + 32 > bufsz)
+                           {
+                             // Reallocate the buffer
+                             size_t curlen = d - buf;
+                             bufsz += 1024;
+                             char *buf_new = (char *) malloc (bufsz);
+                             strncpy (buf_new, buf, curlen);
+                             buf_new[curlen] = '\0';
+                             free (buf);
+                             buf = buf_new;
+                             d = buf + curlen;
+                           }
+                       }
+                     while (c != (char) 0);
+                   }
+                 cell = dbe_strdup (buf);
+                 free (item->value[index].l);
+                 item->value[index].l = NULL; //YXXX missing from dbeGetFuncListV2
+               }
+             else
+               {
+                 // omazur: why don't we have it as metric value
+                 Histable::NameFormat nfmt = dbev->get_name_format ();
+                 cell = dbe_strdup (item->obj->get_name (nfmt));
+               }
+             jobjects->store (index2, cell);
+           }
+         if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2
+             || type == DSP_DISASM_V2)
+           free (buf);
+         table->store (nv++, jobjects);
+         break;
+       }
+      default:
+       table->store (nv++, dbeGetTableDataOneColumn (data, index));
+       break;
+      }
+  }
+  return table;
+}
+
+Vector<Obj> *
+dbeGetComparableObjsV2 (int /* dbevindex */, Obj sel_obj, int type)
+{
+  long grsize = dbeSession->expGroups->size ();
+  Vector<Obj> *res = new Vector<Obj> (grsize + 1);
+  for (long j = 0; j < grsize; j++)
+    res->append ((Obj) NULL);
+  res->append (sel_obj);
+  Histable *obj = (Histable *) sel_obj;
+  if (obj == NULL)
+    return res;
+  Function *func = (Function *) obj->convertto (Histable::FUNCTION);
+  if (func == NULL)
+    return res;
+  Vector<Histable *> *cmpObjs = func->get_comparable_objs ();
+  if (cmpObjs == NULL || cmpObjs->size () != grsize)
+    return res;
+
+  Histable::Type conv_type = (type == DSP_SOURCE || type == DSP_SOURCE_V2) ?
+         Histable::LINE : Histable::INSTR;
+  switch (obj->get_type ())
+    {
+    case Histable::FUNCTION:
+      for (long j = 0; j < grsize; j++)
+       res->store (j, (Obj) cmpObjs->get (j));
+      return res;
+    case Histable::INSTR:
+    case Histable::LINE:
+      {
+       SourceFile *srcContext = (SourceFile *) obj->convertto (Histable::SOURCEFILE);
+       char *bname = get_basename (srcContext->get_name ());
+       for (long j = 0; j < grsize; j++)
+         {
+           Function *func1 = (Function *) cmpObjs->get (j);
+           if (func == func1)
+             {
+               if (conv_type == Histable::LINE)
+                 res->store (j, (Obj) obj);
+               else
+                 res->store (j, (Obj) obj->convertto (conv_type, srcContext));
+               continue;
+             }
+           if (func1 == NULL)
+             continue;
+           Vector<SourceFile*> *sources = func1->get_sources ();
+           SourceFile *sf = NULL;
+           for (long j1 = 0, sz1 = sources ? sources->size () : 0; j1 < sz1; j1++)
+             {
+               SourceFile *sf1 = sources->get (j1);
+               if (sf1 == srcContext)
+                 { // the same file
+                   sf = srcContext;
+                   break;
+                 }
+               else if (sf == NULL)
+                 {
+                   char *bname1 = get_basename (sf1->get_name ());
+                   if (dbe_strcmp (bname, bname1) == 0)
+                     sf = sf1;
+                 }
+             }
+           res->store (j, (Obj) func1->convertto (conv_type, srcContext));
+         }
+       break;
+      }
+    default:
+      break;
+    }
+  return res;
+}
+
+// Get Table of Function List data
+Vector<void *> *
+dbeGetFuncListV2 (int dbevindex, int mtype, Obj sel_obj, int type, int subtype)
+{
+  Metric *mitem;
+  int nitems, nvisible;
+  int index, index2, nv;
+  char *cell;
+  Hist_data::HistItem *item;
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  dbev->error_msg = dbev->warning_msg = NULL;
+  MetricList *mlist = dbev->get_metric_list ((MetricType) (mtype & MTYPE_MASK),
+                                            (mtype & COMPARE_BIT) != 0,
+                                            mtype >> GROUP_ID_SHIFT);
+  Histable *selObj = (Histable *) sel_obj;
+  int old_compare_mode = dbev->get_compare_mode ();
+  if ((mtype & COMPARE_BIT) != 0)
+    dbev->reset_compare_mode (CMP_DISABLE);
+  Hist_data *data = dbev->get_data (mlist, selObj, type, subtype);
+  dbev->reset_compare_mode (old_compare_mode);
+  if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+    return NULL;
+  nitems = data->size ();
+  nvisible = mlist->get_items ()->size ();
+
+  // Initialize Java String array
+  Vector<void*> *table = new Vector<void*>(nvisible + 3);
+  // Mark Hi-value metric items for annotated src/dis/layout
+  if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_DLAYOUT
+      || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2)
+    {
+      Vector<int> *types = new Vector<int>(nitems);
+      Vector<Obj> *ids = new Vector<Obj > (nitems);
+      if (dbev->marks->size () > 0)
+       index = dbev->marks->fetch (0);
+      else
+       index = -1;
+      int mindex = 0;
+      for (int i = 0; i < nitems; i++)
+       {
+         item = data->fetch (i);
+         ids->store (i, (Obj) item->obj);
+         if (i == index)
+           {
+             types->store (i, -item->type);
+             if (++mindex < dbev->marks->size ())
+               index = dbev->marks->fetch (mindex);
+             else
+               index = -1;
+           }
+         else
+           types->store (i, item->type);
+       }
+      table->store (nvisible, types);
+      table->store (nvisible + 1, ids);
+    }
+  else
+    {
+      table->store (nvisible, NULL);
+      table->store (nvisible + 1, NULL);
+    }
+
+  // Fill function list elements
+  nv = 0;
+  Vec_loop (Metric*, mlist->get_items (), index, mitem)
+  {
+    if (!mitem->is_visible () && !mitem->is_tvisible () &&
+       !mitem->is_pvisible ())
+      continue;
+
+    // Fill values
+    switch (mitem->get_vtype ())
+      {
+      default:
+       table->store (nv++, dbeGetTableDataOneColumn (data, index));
+       break;
+      case VT_LABEL:
+       Vector<char*> *jobjects = new Vector<char*>(nitems);
+       char *buf = NULL;
+       size_t bufsz = 0;
+       int lspace = 0;
+       if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2
+           || type == DSP_DISASM_V2)
+         {
+           // if this is source or disassembly, where we'll insert
+           //  a preface into the output line, figure out how wide
+           //  it needs to be
+           // first, scan all the lines, to get the maximum line number
+           bufsz = 1024;
+           buf = (char *) malloc (bufsz);
+           int max_lineno = 0;
+           int hidx;
+           Hist_data::HistItem *hitem;
+           Vec_loop (Hist_data::HistItem*, data, hidx, hitem)
+           {
+             if (!hitem->obj)
+               continue;
+             if (hitem->obj->get_type () == Histable::LINE &&
+                 ((DbeLine*) hitem->obj)->lineno > max_lineno)
+               max_lineno = ((DbeLine*) hitem->obj)->lineno;
+             else if (hitem->obj->get_type () == Histable::INSTR
+                      && ((DbeInstr*) hitem->obj)->lineno > max_lineno)
+               max_lineno = ((DbeInstr*) hitem->obj)->lineno;
+           }
+
+           // we have the maximum integer over all linenumbers in the file
+           //  figure out how many digits are needed
+           lspace = snprintf (buf, bufsz, NTXT ("%d"), max_lineno);
+         }
+
+       for (index2 = 0; index2 < nitems; index2++)
+         {
+           item = data->fetch (index2);
+           if (type == DSP_DLAYOUT)
+             cell = dbe_strdup (((DataObject*) (item->obj))->get_offset_name ());
+           else if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2 || type == DSP_DISASM_V2)
+             {
+               // This code is duplicated in output.cc, yet it's
+               // intended for presentation purpose and thus is
+               // potentially different for er_print and analyzer.
+               switch (item->type)
+                 {
+                 case Module::AT_SRC_ONLY:
+                 case Module::AT_SRC:
+                   if (item->obj == NULL)
+                     snprintf (buf, bufsz, NTXT (" %*c. "), lspace, ' ');
+                   else
+                     snprintf (buf, bufsz, NTXT (" %*d. "), lspace,
+                               ((DbeLine*) item->obj)->lineno);
+                   break;
+                 case Module::AT_FUNC:
+                 case Module::AT_QUOTE:
+                   snprintf (buf, bufsz, NTXT ("%*c"), lspace + 3, ' ');
+                   break;
+                 case Module::AT_DIS:
+                 case Module::AT_DIS_ONLY:
+                   if (item->obj == NULL || ((DbeInstr*) item->obj)->lineno == -1)
+                     snprintf (buf, bufsz, NTXT ("%*c[%*s] "), lspace + 3, ' ',
+                               lspace, NTXT ("?"));
+                   else
+                     snprintf (buf, bufsz, NTXT ("%*c[%*d] "), lspace + 3, ' ',
+                               lspace,
+                               ((DbeInstr*) item->obj)->lineno);
+                   break;
+                 case Module::AT_COM:
+                 case Module::AT_EMPTY:
+                   *buf = (char) 0;
+                   break;
+                 }
+               // get the line's text
+               char *s = item->value[index].l;
+               if (s != NULL)
+                 {
+                   // copy the string expanding all tabulations
+                   // (JTable doesn't render them)
+                   char *d = buf + strlen (buf);
+                   char c;
+                   size_t column = 0;
+                   do
+                     {
+                       c = *s++;
+                       if (c == '\t')
+                         {
+                           do
+                             {
+                               *d++ = ' ';
+                               column++;
+                             }
+                           while (column & 07);
+                         }
+                       else
+                         {
+                           *d++ = c;
+                           column++;
+                         }
+                       if (column + 32 > bufsz)
+                         {
+                           // Reallocate the buffer
+                           size_t curlen = d - buf;
+                           bufsz += 1024;
+                           char *buf_new = (char *) malloc (bufsz);
+                           strncpy (buf_new, buf, curlen);
+                           buf_new[curlen] = '\0';
+                           free (buf);
+                           buf = buf_new;
+                           d = buf + curlen;
+                         }
+                     }
+                   while (c != (char) 0);
+                 }
+               cell = dbe_strdup (buf);
+             }
+           else
+             {
+               Histable::NameFormat nfmt = dbev->get_name_format ();
+               cell = dbe_strdup (item->obj->get_name (nfmt));
+             }
+           jobjects->store (index2, cell);
+         }
+
+       if (type == DSP_SOURCE || type == DSP_DISASM || type == DSP_SOURCE_V2
+           || type == DSP_DISASM_V2)
+         free (buf);
+       table->store (nv++, jobjects);
+       break;
+      }
+  }
+  table->append (dbeGetMetricList (mlist));
+  return table;
+} // dbeGetFuncListV2
+
+//
+// Get Table DataV2
+//
+Vector<void*> *
+dbeGetTableDataV2 (int dbevindex, char *mlistStr, char *modeStr, char *typeStr,
+                  char *subtypeStr, Vector<uint64_t> *ids)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+
+  // Process metric list specification
+  if (mlistStr == NULL)
+    return NULL;
+  bool met_call = false;
+  MetricList *mlist = NULL;
+  if (streq (mlistStr, NTXT ("MET_NORMAL")))
+    mlist = dbev->get_metric_list (MET_NORMAL);
+  else if (streq (mlistStr, NTXT ("MET_CALL")))
+    {
+      met_call = true;
+      mlist = dbev->get_metric_list (MET_CALL);
+    }
+  else if (streq (mlistStr, NTXT ("MET_CALL_AGR")))
+    mlist = dbev->get_metric_list (MET_CALL_AGR);
+  else if (streq (mlistStr, NTXT ("MET_DATA")))
+    mlist = dbev->get_metric_list (MET_DATA);
+  else if (streq (mlistStr, NTXT ("MET_INDX")))
+    mlist = dbev->get_metric_list (MET_INDX);
+  else if (streq (mlistStr, NTXT ("MET_IO")))
+    mlist = dbev->get_metric_list (MET_IO);
+  else if (streq (mlistStr, NTXT ("MET_HEAP")))
+    mlist = dbev->get_metric_list (MET_HEAP);
+  else
+    return NULL;
+
+  // Process mode specification
+  if (modeStr == NULL)
+    return NULL;
+  Hist_data::Mode mode = (Hist_data::Mode)0;
+  if (streq (modeStr, NTXT ("CALLERS")))
+    mode = Hist_data::CALLERS;
+  else if (streq (modeStr, NTXT ("CALLEES")))
+    mode = Hist_data::CALLEES;
+  else if (streq (modeStr, NTXT ("SELF")))
+    mode = Hist_data::SELF;
+  else if (streq (modeStr, NTXT ("ALL")))
+    mode = Hist_data::ALL;
+  else
+    return NULL;
+
+  // Process type specification
+  if (typeStr == NULL)
+    return NULL;
+  Histable::Type type = Histable::OTHER;
+  if (streq (typeStr, NTXT ("FUNCTION")))
+    type = Histable::FUNCTION;
+  else if (streq (typeStr, NTXT ("INDEXOBJ")))
+    type = Histable::INDEXOBJ;
+  else if (streq (typeStr, NTXT ("IOACTFILE")))
+    type = Histable::IOACTFILE;
+  else if (streq (typeStr, NTXT ("IOACTVFD")))
+    type = Histable::IOACTVFD;
+  else if (streq (typeStr, NTXT ("IOCALLSTACK")))
+    type = Histable::IOCALLSTACK;
+  else if (streq (typeStr, NTXT ("HEAPCALLSTACK")))
+    type = Histable::HEAPCALLSTACK;
+  else if (streq (typeStr, NTXT ("LINE")))
+    type = Histable::LINE;
+  else if (streq (typeStr, NTXT ("INSTR")))
+    type = Histable::INSTR;
+  else
+    // XXX Accepting objects other than above may require a different
+    // implementation of the id -> Histable mapping below
+    return NULL;
+
+  // Process subtype specification
+  int subtype = 0;
+  if (subtypeStr != NULL)
+    subtype = atoi (subtypeStr);
+  Vector<Histable*> *hobjs = NULL;
+  if (ids != NULL)
+    {
+      hobjs = new Vector<Histable*>();
+      for (int i = 0; i < ids->size (); ++i)
+       {
+         Histable::Type obj_type = type;
+         if ((obj_type == Histable::LINE || obj_type == Histable::INSTR)
+             && subtype == 0)
+           obj_type = Histable::FUNCTION;
+         Histable *hobj = dbeSession->findObjectById (obj_type, subtype, ids->fetch (i));
+         if ((obj_type == Histable::LINE || obj_type == Histable::INSTR)
+             && subtype == 0 && hobj == NULL)
+           return NULL;
+         hobjs->append (hobj);
+       }
+    }
+
+  PathTree::PtreeComputeOption flag = PathTree::COMPUTEOPT_NONE;
+  if (dbev->isOmpDisMode () && type == Histable::FUNCTION
+      && mode == Hist_data::CALLEES && met_call)
+    flag = PathTree::COMPUTEOPT_OMP_CALLEE;
+
+  Hist_data *data = dbev->get_hist_data (mlist, type, subtype, mode, hobjs, NULL, NULL, flag);
+  return dbeGetTableDataV2Data (dbev, data);
+}
+
+static Vector<void*> *
+dbeGetTableDataV2Data (DbeView * /*dbev*/, Hist_data *data)
+{
+  if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+    return NULL;
+  MetricList *mlist;
+  mlist = data->get_metric_list ();
+  int nitems = data->size ();
+
+  // Initialize Java String array
+  Vector<void*> *table = new Vector<void*>(mlist->size () + 1);
+
+  // Fill function list elements
+  for (long i = 0, sz = mlist->size (); i < sz; i++)
+    {
+      Metric *mitem = mlist->get (i);
+      if (!mitem->is_visible () && !mitem->is_tvisible () &&
+         !mitem->is_pvisible ())
+       continue;
+      table->append (dbeGetTableDataOneColumn (data, i));
+    }
+
+  // Add an array of Histable IDs
+  Vector<uint64_t> *idList = new Vector<uint64_t>(nitems);
+  for (int i = 0; i < nitems; ++i)
+    {
+      Hist_data::HistItem *item = data->fetch (i);
+      if (item->obj->get_type () == Histable::LINE
+         || item->obj->get_type () == Histable::INSTR)
+       idList->store (i, (uint64_t) (item->obj));
+      else
+       idList->store (i, item->obj->id);
+    }
+  table->append (idList);
+  return table;
+} // dbeGetTableData
+
+//YXXX try to use the following to consolidate similar cut/paste code
+
+static Vector<void*> *
+dbeGetTableDataOneColumn (Hist_data *data, int met_ind)
+{
+  // Allocates a vector and fills it with metric values for one column
+  TValue res;
+  Metric *m = data->get_metric_list ()->get (met_ind);
+  if ((m->get_visbits () & VAL_RATIO) != 0)
+    {
+      Vector<double> *col = new Vector<double>(data->size ());
+      for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+       {
+         TValue *v = data->get_value (&res, met_ind, row);
+         double d = (v->tag != VT_LABEL) ? v->to_double () : 100.; // NaN
+         col->append (d);
+       }
+      return (Vector<void*> *) col;
+    }
+
+  switch (m->get_vtype ())
+    {
+    case VT_DOUBLE:
+      {
+       Vector<double> *col = new Vector<double>(data->size ());
+       for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+         {
+           TValue *v = data->get_value (&res, met_ind, row);
+           col->append (v->d);
+         }
+       return (Vector<void*> *) col;
+      }
+    case VT_INT:
+      {
+       Vector<int> *col = new Vector<int>(data->size ());
+       for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+         {
+           TValue *v = data->get_value (&res, met_ind, row);
+           col->append (v->i);
+         }
+       return (Vector<void*> *) col;
+      }
+    case VT_ULLONG:
+    case VT_LLONG:
+      {
+       Vector<long long> *col = new Vector<long long>(data->size ());
+       for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+         {
+           TValue *v = data->get_value (&res, met_ind, row);
+           col->append (v->ll);
+         }
+       return (Vector<void*> *) col;
+      }
+    case VT_ADDRESS:
+      {
+       Vector<long long> *col = new Vector<long long>(data->size ());
+       for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+         {
+           TValue *v = data->get_value (&res, met_ind, row);
+           // set the highest bit to mark this jlong as
+           // a VT_ADDRESS (rather than a regular VT_LLONG)
+           col->append (v->ll | 0x8000000000000000ULL);
+         }
+       return (Vector<void*> *) col;
+      }
+    case VT_LABEL:
+      {
+       Vector<char *> *col = new Vector<char *>(data->size ());
+       for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+         {
+           TValue *v = data->get_value (&res, met_ind, row);
+           col->append (dbe_strdup (v->l));
+         }
+       return (Vector<void*> *) col;
+      }
+    default:
+      return NULL;
+    }
+}
+
+static Vector<void*> *
+dbeGetTableDataOneColumn (DbeView *dbev, Vector<Hist_data::HistItem*> *data,
+                         ValueTag vtype, int metricColumnNumber)
+// Allocates a vector and fills it with metric values for one column
+{
+  Vector<void*> *column_data = NULL;
+  int nitems = data->size (); // number of rows
+  int index = metricColumnNumber;
+  switch (vtype)
+    {
+    case VT_DOUBLE:
+      {
+       Vector<double> *jd_list = new Vector<double>(nitems);
+       for (int index2 = 0; index2 < nitems; index2++)
+         {
+           Hist_data::HistItem *item = data->fetch (index2);
+           jd_list->store (index2, item->value[index].d);
+         }
+       column_data = (Vector<void*> *)jd_list;
+       break;
+      }
+    case VT_INT:
+      {
+       Vector<int> *ji_list = new Vector<int>(nitems);
+       for (int index2 = 0; index2 < nitems; index2++)
+         {
+           Hist_data::HistItem *item = data->fetch (index2);
+           ji_list->store (index2, item->value[index].i);
+         }
+       column_data = (Vector<void*> *)ji_list;
+       break;
+      }
+    case VT_ULLONG:
+    case VT_LLONG:
+      {
+       Vector<long long> *jl_list = new Vector<long long>(nitems);
+       for (int index2 = 0; index2 < nitems; index2++)
+         {
+           Hist_data::HistItem *item = data->fetch (index2);
+           jl_list->store (index2, item->value[index].ll);
+         }
+       column_data = (Vector<void*> *)jl_list;
+       break;
+      }
+    case VT_ADDRESS:
+      {
+       Vector<long long> *jl_list = new Vector<long long>(nitems);
+       for (int index2 = 0; index2 < nitems; index2++)
+         {
+           Hist_data::HistItem *item = data->fetch (index2);
+
+           // set the highest bit to mark this jlong as
+           // a VT_ADDRESS (rather than a regular VT_LLONG)
+           uint64_t addr = item->value[index].ll;
+           addr |= 0x8000000000000000ULL;
+           jl_list->store (index2, addr);
+         }
+       column_data = (Vector<void*> *)jl_list;
+       break;
+      }
+    case VT_LABEL:
+      {
+       Vector<char*> *jobjects = new Vector<char*>(nitems);
+       for (int index2 = 0; index2 < nitems; index2++)
+         {
+           Hist_data::HistItem *item = data->fetch (index2);
+
+           // omazur: why don't we have it as metric value
+           Histable::NameFormat nfmt = dbev->get_name_format ();
+           char *str = dbe_strdup (item->obj->get_name (nfmt));
+           jobjects->store (index2, str);
+         }
+       column_data = (Vector<void*> *)jobjects;
+       break;
+      }
+    default:
+      abort ();
+    }
+  return column_data;
+}
+
+int
+dbeGetCallTreeNumLevels (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  PathTree * ptree = dbev->get_path_tree ();
+  if (ptree == NULL)
+    return 0;
+  return ptree->get_ftree_depth ();
+}
+
+Vector<void*>*
+dbeGetCallTreeLevel (int dbevindex, char *mcmd, int level)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  PathTree * ptree = dbev->get_path_tree ();
+  if (ptree == NULL)
+    return NULL;
+  if (mcmd == NULL)
+    return NULL;
+  BaseMetric *bm = dbeSession->find_base_reg_metric (mcmd);
+  if (bm == NULL)
+    return NULL;
+  return ptree->get_ftree_level (bm, level);
+}
+
+Vector<void*>*
+dbeGetCallTreeLevels (int dbevindex, char *mcmd)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  PathTree * ptree = dbev->get_path_tree ();
+  if (ptree == NULL)
+    return NULL;
+  if (mcmd == NULL)
+    return NULL;
+  BaseMetric *bm = dbeSession->find_base_reg_metric (mcmd);
+  if (bm == NULL)
+    return NULL;
+
+  int depth = ptree->get_ftree_depth ();
+  Vector<void*> *results = new Vector<void*>(depth);
+  for (int ii = 0; ii < depth; ii++)
+    results->append (ptree->get_ftree_level (bm, ii));
+  return results;
+}
+
+Vector<void*>*
+dbeGetCallTreeLevelFuncs (int dbevindex, int start_level, int end_level)
+{ // (0,-1) -> all levels
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  PathTree * ptree = dbev->get_path_tree ();
+  if (ptree == NULL)
+    return NULL;
+
+  int depth = ptree->get_ftree_depth ();
+  if (start_level < 0)
+    start_level = 0;
+  if (end_level < 0 || end_level >= depth)
+    end_level = depth - 1;
+
+  Histable::NameFormat nfmt = dbev->get_name_format (); //YXXX or fixed format?
+  Vector<char*> *funcNames = new Vector<char*>();
+  Vector<long long> *funcIds = new Vector<long long>();
+  Vector<Obj> *funcObjs = new Vector<Obj>();
+
+  if (start_level == 0 && end_level == depth - 1)
+    return dbeGetCallTreeFuncs (dbevindex);
+  else
+    {
+      for (int ii = start_level; ii <= end_level; ii++)
+       {
+         Vector<void*> *info = ptree->get_ftree_level (NULL, ii); /*no metric*/
+         if (!info)
+           continue;
+         Vector<long long> *fids = (Vector<long long> *)info->get (2);
+         if (!fids)
+           continue;
+         int index;
+         long long fid;
+         Vec_loop (long long, fids, index, fid)
+         {
+           funcIds->append (fid);
+           Histable *obj = dbeSession->findObjectById (fid);
+           char * fname = obj ? dbe_strdup (obj->get_name (nfmt)) : NULL;
+           funcNames->append (fname);
+           funcObjs->append ((unsigned long) obj); // avoiding sign extension
+         }
+         destroy (info);
+       }
+    }
+  Vector<void*> *results = new Vector<void*>(3);
+  results->append (funcIds);
+  results->append (funcNames);
+  results->append (funcObjs);
+  return results;
+}
+
+Vector<void*> *
+dbeGetCallTreeFuncs (int dbevindex)
+{ // does not require ptree->get_ftree_level() to be computed
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  PathTree * ptree = dbev->get_path_tree ();
+  if (ptree == NULL)
+    return 0;
+  Vector<Function*>* funcs = ptree->get_funcs (); // Unique functions in tree
+  if (funcs == NULL)
+    return NULL;
+
+  long sz = funcs->size ();
+  Vector<void*> *results = new Vector<void*>(3);
+  Vector<long long> *funcIds = new Vector<long long>(sz);
+  Vector<char*> *funcNames = new Vector<char*>(sz);
+  Vector<Obj> *funcObjs = new Vector<Obj>(sz);
+
+  int index;
+  Function * func;
+  Histable::NameFormat nfmt = dbev->get_name_format (); //YXXX or fixed format?
+  Vec_loop (Function *, funcs, index, func)
+  {
+    funcIds->append (func->id); // do we need IDs?
+    char *fname = dbe_strdup (func->get_name (nfmt));
+    funcNames->append (fname);
+    funcObjs->append ((unsigned long) func); // avoiding sign extension
+  }
+  results->put (0, funcIds);
+  results->put (1, funcNames);
+  results->put (2, funcObjs);
+  destroy (funcs);
+  return results;
+}
+
+Vector<void*>*
+dbeGetCallTreeChildren (int dbevindex, char *mcmd, Vector<int /*NodeIdx*/>*node_idxs)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  if (node_idxs == NULL || node_idxs->size () == 0)
+    return NULL;
+  long sz = node_idxs->size ();
+  PathTree * ptree = dbev->get_path_tree ();
+  if (ptree == NULL)
+    return NULL;
+  if (mcmd == NULL)
+    return NULL;
+  BaseMetric *bm = dbeSession->find_base_reg_metric (mcmd);
+  if (bm == NULL)
+    return NULL;
+
+  Vector<void*> *results = new Vector<void*>(sz);
+  for (long ii = 0; ii < sz; ii++)
+    {
+      PathTree::NodeIdx nodeIdx = node_idxs->get (ii); // upcasted from int
+      results->append (ptree->get_ftree_node_children (bm, nodeIdx));
+    }
+  return results;
+}
+
+Vector<int> *
+dbeGetGroupIds (int /*dbevindex*/)
+{
+  Vector<ExpGroup*> *groups = dbeSession->expGroups;
+  int sz = groups->size ();
+  Vector<int> *grIds = new Vector<int>(sz);
+  for (int i = 0; i < sz; i++)
+    grIds->store (i, groups->fetch (i)->groupId);
+  return grIds;
+}
+
+//
+// Get label for name column
+//
+Vector<char*> *
+dbeGetNames (int dbevindex, int type, Obj sel_obj)
+{
+  char *s0, *s1, *s2;
+  bool need_strdup = true;
+  switch (type)
+    {
+    case DSP_SOURCE_V2:
+    case DSP_DISASM_V2:
+    case DSP_SOURCE:
+    case DSP_DISASM:
+      {
+       if (sel_obj)
+         {
+           Histable *selObj = (Histable*) sel_obj;
+           Function *func = (Function *) selObj->convertto (Histable::FUNCTION);
+           if (func)
+             {
+               char *names[3] = {NULL, NULL, NULL};
+               set_file_names (func, names);
+               s0 = names[0];
+               s1 = names[1];
+               s2 = names[2];
+               need_strdup = false;
+               break;
+             }
+         }
+       DbeView *dbev = dbeSession->getView (dbevindex);
+       char **names = type == DSP_SOURCE || type == DSP_SOURCE_V2 ? dbev->names_src : dbev->names_dis;
+       s0 = names[0];
+       s1 = names[1];
+       s2 = names[2];
+       break;
+      }
+    case DSP_LINE:
+      s0 = GTXT ("Lines");
+      s1 = GTXT ("Function, line # in \"sourcefile\"");
+      s2 = NTXT ("");
+      break;
+    case DSP_PC:
+      s0 = GTXT ("PCs");
+      s1 = GTXT ("Function + offset");
+      s2 = NTXT ("");
+      break;
+    case DSP_DLAYOUT:
+      s0 = GTXT ("Name");
+      s1 = GTXT ("* +offset .element");
+      s2 = NTXT ("");
+      break;
+    default:
+      s0 = GTXT ("Name");
+      s1 = s2 = NTXT ("");
+      break;
+    }
+  if (need_strdup)
+    {
+      s0 = dbe_strdup (s0);
+      s1 = dbe_strdup (s1);
+      s2 = dbe_strdup (s2);
+    }
+  Vector<char*> *table = new Vector<char*>(3);
+  table->store (0, s0);
+  table->store (1, s1);
+  table->store (2, s2);
+  return table;
+}
+
+//
+// Get Total/Maximum element of Function List
+//
+Vector<void*> *
+dbeGetTotalMax (int dbevindex, int type, int subtype)
+{
+  Hist_data *data;
+  int index;
+  Hist_data::HistItem *total_item, *maximum_item;
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+
+  switch (type)
+    {
+    case DSP_LINE:
+      data = dbev->line_data;
+      break;
+    case DSP_PC:
+      data = dbev->pc_data;
+      break;
+    case DSP_CALLER:
+      data = dbev->callers;
+      break;
+    case DSP_SELF:
+    case DSP_CALLEE:
+      data = dbev->callees;
+      break;
+    case DSP_DLAYOUT:
+      data = dbev->dlay_data;
+      break;
+    case DSP_DATAOBJ:
+      data = dbev->dobj_data;
+      break;
+    case DSP_MEMOBJ:
+      data = dbev->get_indxobj_data (subtype);
+      break;
+    case DSP_INDXOBJ:
+      data = dbev->get_indxobj_data (subtype);
+      break;
+    case DSP_FUNCTION: // annotated src/dis use func total/max
+    case DSP_SOURCE:
+    case DSP_DISASM:
+    case DSP_SOURCE_V2:
+    case DSP_DISASM_V2:
+      data = dbev->func_data;
+      break;
+    default:
+      abort ();
+    }
+  if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+    return NULL;
+
+  // Get list size
+  // XXX -- the original list has all items, visible or not;
+  // XXX -- the one from Hist_data has only visible items,
+  // XXX --    and should be the only ones computed
+  // XXX --    Analyzer got confused (yesterday), when we used the shorter list
+  // XXX -- Why can we fetch total/max for metrics never
+  // XXX --    computed without core dumping?
+  MetricList *mlist2 = data->get_metric_list ();
+  int size = mlist2->get_items ()->size ();
+
+  // Initialize Java array
+  Vector<void*> *total_max = new Vector<void*>(2);
+  Vector<double> *total = new Vector<double>(size);
+  Vector<double> *maximum = new Vector<double>(size);
+
+  // Fill total/maximum element
+  total_item = data->get_totals ();
+  maximum_item = data->get_maximums ();
+
+  for (index = 0; index < size; index++)
+    {
+      total->store (index, total_item->value[index].to_double ());
+      maximum->store (index, maximum_item->value[index].to_double ());
+    }
+  total_max->store (0, total);
+  total_max->store (1, maximum);
+  return total_max;
+}
+
+//
+// Get Table of Overview List
+Vector<void*> *
+dbeGetStatisOverviewList (int dbevindex)
+{
+  int size;
+  Ovw_data **data;
+  Ovw_data::Ovw_item labels, *totals;
+  int nitems;
+  int index, index2;
+
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  dbev->error_msg = dbev->warning_msg = NULL;
+
+  size = dbeSession->nexps ();
+  totals = new Ovw_data::Ovw_item[size + 1];
+  data = new Ovw_data*[size + 1];
+  data[0] = new Ovw_data ();
+
+  for (index = 1; index <= size; index++)
+    {
+      data[index] = dbev->get_ovw_data (index - 1);
+      if (data[index] == NULL)
+       {
+         Ovw_data::reset_item (&totals[index]); // set contents to zeros
+         continue;
+       }
+      data[0]->sum (data[index]);
+      totals[index] = data[index]->get_totals (); //shallow copy!
+    }
+  totals[0] = data[0]->get_totals ();
+
+  // Get table size
+  labels = data[0]->get_labels ();
+  nitems = labels.size + 4;
+
+  // Initialize Java String array
+  Vector<void*> *table = new Vector<void*>(size + 4);
+  Vector<char*> *jobjects = new Vector<char*>(nitems);
+
+  // Set the label
+  jobjects->store (0, dbe_strdup (GTXT ("Start Time (sec.)")));
+  jobjects->store (1, dbe_strdup (GTXT ("End Time (sec.)")));
+  jobjects->store (2, dbe_strdup (GTXT ("Duration (sec.)")));
+  jobjects->store (3, dbe_strdup (GTXT ("Total Thread Time (sec.)")));
+  jobjects->store (4, dbe_strdup (GTXT ("Average number of Threads")));
+
+  for (index2 = 5; index2 < nitems; index2++)
+    jobjects->store (index2, dbe_strdup (labels.values[index2 - 4].l));
+  table->store (0, jobjects);
+
+  // Set the data
+  for (index = 0; index <= size; index++)
+    {
+      Vector<double> *jd_list = new Vector<double>(nitems);
+      jd_list->store (0, tstodouble (totals[index].start));
+      jd_list->store (1, tstodouble (totals[index].end));
+      jd_list->store (2, tstodouble (totals[index].duration));
+      jd_list->store (3, tstodouble (totals[index].tlwp));
+      jd_list->store (4, totals[index].nlwp);
+      for (index2 = 5; index2 < nitems; index2++)
+       jd_list->store (index2, tstodouble (totals[index].values[index2 - 4].t));
+      table->store (index + 1, jd_list);
+    }
+  for (index = 0; index <= size; index++)
+    delete data[index];
+  delete[] data;
+  delete[] totals;
+  return table;
+}
+
+// Get Table of Statistics List
+Vector<void*> *
+dbeGetStatisList (int dbevindex)
+{
+  int size;
+  Stats_data **data;
+  int nitems;
+  int index, index2;
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  dbev->error_msg = dbev->warning_msg = NULL;
+  if ((size = dbeSession->nexps ()) == 0)
+    return NULL;
+
+  // Get statistics data
+  data = (Stats_data **) malloc ((size + 1) * sizeof (Stats_data *));
+  data[0] = new Stats_data ();
+  for (index = 1; index <= size; index++)
+    {
+      data[index] = dbev->get_stats_data (index - 1);
+      if (data[index] == NULL)
+       continue;
+      data[0]->sum (data[index]);
+    }
+
+  // Get table size
+  nitems = data[0]->size ();
+
+  // Initialize Java String array
+  Vector<void*> *table = new Vector<void*>(size + 2);
+  Vector<char*> *jobjects = new Vector<char*>(nitems);
+
+  // Set the label
+  for (index2 = 0; index2 < nitems; index2++)
+    jobjects->store (index2, dbe_strdup (data[0]->fetch (index2).label));
+  table->store (0, jobjects);
+
+  // Set the data
+  for (index = 0; index <= size; index++)
+    {
+      Vector<double> *jd_list = new Vector<double>(nitems);
+      for (index2 = 0; index2 < nitems; index2++)
+       {
+         double val = 0;
+         if (data[index])
+           val = data[index]->fetch (index2).value.to_double ();
+         jd_list->store (index2, val);
+       }
+      table->store (index + 1, jd_list);
+    }
+  if (data)
+    {
+      for (index = 0; index <= size; index++)
+       delete data[index];
+      free (data);
+    }
+  return table;
+}
+
+
+//
+// Set summary list
+//
+static void
+setSummary (Vector<Histable*> *objs, Vector<int> *saligns,
+           Vector<char> *mnemonic, Vector<char*> *jlabels, Vector<char*> *jvalues)
+{
+  char *sname = NULL, *oname = NULL, *lname = NULL, *alias = NULL,
+         *mangle = NULL, *address = NULL, *size = NULL,
+         *name_0 = NULL, *sname_0 = NULL, *oname_0 = NULL, *lname_0 = NULL,
+         *alias_0 = NULL, *mangle_0 = NULL;
+  Function *func, *last_func = NULL;
+  int one_func = 1;
+
+  // Get the source/object/load-object files & aliases
+  long long ll_size = 0;
+  for (long i = 0; i < objs->size (); i++)
+    {
+      Histable *current_obj = objs->fetch (i);
+      Histable::Type htype = current_obj->get_type ();
+      if (htype == Histable::LOADOBJECT)
+       lname = ((LoadObject *) current_obj)->dbeFile->get_location_info ();
+      else if ((func = (Function*) current_obj->convertto (Histable::FUNCTION)) != NULL)
+       {
+         if (one_func && last_func != NULL && last_func != func)
+           one_func = 0;
+         last_func = func;
+         sname = NULL;
+         DbeLine *dbeline = (DbeLine*) current_obj->convertto (Histable::LINE);
+         if (dbeline)
+           {
+             SourceFile *sf;
+             if (dbeline->lineno == 0 && dbeline->include != NULL)
+               sf = dbeline->include;
+             else if (dbeline->sourceFile != NULL)
+               sf = dbeline->sourceFile;
+             else
+               sf = func->getDefSrc ();
+             if (sf)
+               sname = sf->dbeFile->get_location_info ();
+           }
+         char *func_name = func->get_name ();
+         mangle = func->get_mangled_name ();
+         if (mangle && streq (func_name, mangle))
+           mangle = NULL;
+         Module *module = func->module;
+         if (module != NULL)
+           {
+             module->read_stabs ();
+             if (sname == NULL || strlen (sname) == 0)
+               {
+                 SourceFile *sf = module->getMainSrc ();
+                 sname = sf->dbeFile->get_location_info ();
+               }
+             DbeFile *df = module->dbeFile;
+             if (df == NULL || (df->filetype & DbeFile::F_JAVACLASS) == 0)
+               df = module->loadobject->dbeFile;
+             lname = df->get_location_info ();
+             oname = lname;
+             if (module->dot_o_file)
+               oname = module->dot_o_file->dbeFile->get_location_info ();
+           }
+
+         if (htype == Histable::INSTR && dbeSession->is_datamode_available ())
+           alias = ((DbeInstr*) current_obj)->get_descriptor ();
+       }
+
+      char *name = current_obj->get_name ();
+      if (i == 0)
+       {
+         name_0 = name;
+         lname_0 = lname;
+         sname_0 = sname;
+         oname_0 = oname;
+         mangle_0 = mangle;
+         alias_0 = alias;
+         if (objs->size () == 1)
+           {
+             uint64_t addr = current_obj->get_addr ();
+             address = dbe_sprintf (NTXT ("%lld:0x%08llX"),
+                                    (long long) ADDRESS_SEG (addr),
+                                    (long long) ADDRESS_OFF (addr));
+           }
+       }
+      else
+       {
+         if (name_0 != name)
+           name_0 = NULL;
+         if (lname_0 != lname)
+           lname_0 = NULL;
+         if (sname_0 != sname)
+           sname_0 = NULL;
+         if (oname_0 != oname)
+           oname_0 = NULL;
+         if (mangle_0 != mangle)
+           mangle_0 = NULL;
+         if (alias_0 != alias)
+           alias_0 = NULL;
+       }
+      if (current_obj->get_size () == -1)
+       {
+         if (size == NULL)
+           size = dbe_strdup (GTXT ("(Unknown)"));
+       }
+      else
+       ll_size += current_obj->get_size ();
+    }
+  if (size == NULL)
+    size = dbe_sprintf (NTXT ("%lld"), ll_size);
+  if (name_0 == NULL)
+    {
+      if (objs->size () > 1)
+       {
+         char *func_name = last_func == NULL ? NULL :
+                 (one_func == 0 ? NULL : last_func->get_name ());
+         name_0 = dbe_sprintf (NTXT ("%s%s%s (%lld %s)"),
+                               func_name == NULL ? "" : func_name,
+                               func_name == NULL ? "" : ": ",
+                               GTXT ("Multiple Selection"),
+                               (long long) objs->size (),
+                               GTXT ("objects"));
+       }
+    }
+  else
+    name_0 = dbe_strdup (name_0);
+
+  // Set the name area
+  saligns->store (0, TEXT_LEFT);
+  mnemonic->store (0, 'N');
+  jlabels->store (0, dbe_strdup (GTXT ("Name")));
+  jvalues->store (0, name_0);
+
+  saligns->store (1, TEXT_LEFT);
+  mnemonic->store (1, 'P');
+  jlabels->store (1, dbe_strdup (GTXT ("PC Address")));
+  jvalues->store (1, address);
+
+  saligns->store (2, TEXT_LEFT);
+  mnemonic->store (2, 'z');
+  jlabels->store (2, dbe_strdup (GTXT ("Size")));
+  jvalues->store (2, size);
+
+  saligns->store (3, TEXT_RIGHT);
+  mnemonic->store (3, 'r');
+  jlabels->store (3, dbe_strdup (GTXT ("Source File")));
+  jvalues->store (3, dbe_strdup (sname_0));
+
+  saligns->store (4, TEXT_RIGHT);
+  mnemonic->store (4, 'b');
+  jlabels->store (4, dbe_strdup (GTXT ("Object File")));
+  jvalues->store (4, dbe_strdup (oname_0));
+
+  saligns->store (5, TEXT_LEFT);
+  mnemonic->store (5, 'j');
+  jlabels->store (5, dbe_strdup (GTXT ("Load Object")));
+  jvalues->store (5, dbe_strdup (lname_0));
+
+  saligns->store (6, TEXT_LEFT);
+  mnemonic->store (6, 'm');
+  jlabels->store (6, dbe_strdup (GTXT ("Mangled Name")));
+  jvalues->store (6, dbe_strdup (mangle_0));
+
+  saligns->store (7, TEXT_LEFT);
+  mnemonic->store (7, 'A');
+  jlabels->store (7, dbe_strdup (GTXT ("Aliases")));
+  jvalues->store (7, dbe_strdup (alias_0));
+}
+
+// Set memory-object summary list
+//
+static void
+setMemSummary (Vector<Histable*> *objs, Vector<int> *saligns,
+              Vector<char> *mnemonic, Vector<char*> *jlabels,
+              Vector<char*> *jvalues)
+{
+  saligns->store (0, TEXT_LEFT);
+  mnemonic->store (0, 'M');
+  jlabels->store (0, dbe_strdup (GTXT ("Memory Object")));
+  if (objs->size () == 1)
+    {
+      Histable *current_obj = objs->fetch (0);
+      jvalues->store (0, dbe_strdup (current_obj->get_name ()));
+    }
+  else
+    {
+      char *name = dbe_sprintf (NTXT ("%s (%lld %s)"),
+                               GTXT ("Multiple Selection"),
+                               (long long) objs->size (), GTXT ("objects"));
+      jvalues->store (0, name);
+    }
+}
+
+// Set index-object summary list
+//
+static void
+setIndxSummary (Vector<Histable*> *objs, Vector<int> *saligns,
+               Vector<char> *mnemonic, Vector<char*> *jlabels,
+               Vector<char*> *jvalues)
+{
+  saligns->store (0, TEXT_LEFT);
+  mnemonic->store (0, 'I');
+  jlabels->store (0, dbe_strdup (GTXT ("Index Object")));
+
+  if (objs->size () == 1)
+    {
+      Histable *current_obj = objs->fetch (0);
+      jvalues->store (0, dbe_strdup (current_obj->get_name ()));
+    }
+  else
+    {
+      char *name = dbe_sprintf (NTXT ("%s (%lld %s)"), GTXT ("Multiple Selection"),
+                               (long long) objs->size (), GTXT ("objects"));
+      jvalues->store (0, name);
+    }
+}
+
+// Set I/O activity summary list
+//
+static void
+setIOActivitySummary (Vector<Histable*> *objs, Vector<int> *saligns,
+                     Vector<char> *mnemonic, Vector<char*> *jlabels,
+                     Vector<char*> *jvalues)
+{
+  saligns->store (0, TEXT_LEFT);
+  mnemonic->store (0, 'O');
+  jlabels->store (0, dbe_strdup (GTXT ("I/O Activity")));
+  if (objs->size () == 1)
+    {
+      Histable *current_obj = objs->fetch (0);
+      jvalues->store (0, dbe_strdup (current_obj->get_name ()));
+    }
+  else
+    {
+      char *name = dbe_sprintf (NTXT ("%s (%lld %s)"), GTXT ("Multiple Selection"),
+                               (long long) objs->size (), GTXT ("objects"));
+      jvalues->store (0, name);
+    }
+}
+
+// Set heap activity summary list
+//
+static void
+setHeapActivitySummary (Vector<Histable*> *objs, Vector<int> *saligns,
+                       Vector<char> *mnemonic, Vector<char*> *jlabels,
+                       Vector<char*> *jvalues)
+{
+  saligns->store (0, TEXT_LEFT);
+  mnemonic->store (0, 'O');
+  jlabels->store (0, dbe_strdup (GTXT ("Heap Activity")));
+
+  if (objs->size () == 1)
+    {
+      Histable *current_obj = objs->fetch (0);
+      jvalues->store (0, dbe_strdup (current_obj->get_name ()));
+    }
+  else
+    {
+      char *name = dbe_sprintf (NTXT ("%s (%lld %s)"), GTXT ("Multiple Selection"),
+                               (long long) objs->size (), GTXT ("objects"));
+      jvalues->store (0, name);
+    }
+}
+
+//
+// Set data-object summary list
+//
+static void
+setDataSummary (Vector<Histable*> *objs, Vector<int> *saligns,
+               Vector<char> *mnemonic, Vector<char*> *jlabels,
+               Vector<char*> *jvalues)
+{
+  char *name, *type, *member, *elist;
+  DataObject *dobj;
+  Vector<DataObject *> *delem;
+  Histable *scope;
+  int index;
+  char *size, *offset, *elements, *scopename;
+
+  // Get the data object elements
+  member = elist = type = size = offset = elements = scopename = NULL;
+
+  if (objs->size () == 1)
+    {
+      Histable *current_obj = objs->fetch (0);
+      name = dbe_strdup (current_obj->get_name ());
+      dobj = (DataObject *) current_obj;
+      type = dobj->get_typename ();
+      scope = dobj->get_scope ();
+      delem = dbeSession->get_dobj_elements (dobj);
+      if (type == NULL)
+       type = GTXT ("(Synthetic)");
+      if (!scope)
+       scopename = dbe_strdup (GTXT ("(Global)"));
+      else
+       {
+         switch (scope->get_type ())
+           {
+           case Histable::FUNCTION:
+             scopename = dbe_sprintf (NTXT ("%s(%s)"),
+                                      ((Function*) scope)->module->get_name (),
+                                      scope->get_name ());
+             break;
+           case Histable::LOADOBJECT:
+           case Histable::MODULE:
+           default:
+             scopename = dbe_strdup (scope->get_name ());
+             break;
+           }
+       }
+
+      if (dobj->get_offset () != -1)
+       {
+         if (dobj->get_parent ())
+           member = dbe_strdup (dobj->get_parent ()->get_name ());
+         offset = dbe_sprintf (NTXT ("%lld"), (long long) dobj->get_offset ());
+       }
+      size = dbe_sprintf ("%lld", (long long) dobj->get_size ());
+
+      if (delem->size () > 0)
+       {
+         elements = dbe_sprintf (NTXT ("%lld"), (long long) delem->size ());
+         StringBuilder sb_tmp, sb;
+         sb.append (GTXT ("Offset Size  Name\n"));
+         for (index = 0; index < delem->size (); index++)
+           {
+             DataObject *ditem = delem->fetch (index);
+             sb_tmp.sprintf (NTXT ("%6lld %5lld  %s\n"),
+                             (long long) ditem->get_offset (),
+                             (long long) ditem->get_size (), ditem->get_name ());
+             sb.append (&sb_tmp);
+           }
+         if (sb.charAt (sb.length () - 1) == '\n')
+           sb.setLength (sb.length () - 1);
+         elist = sb.toString ();
+       }
+    }
+  else
+    name = dbe_sprintf (NTXT ("%s (%lld %s)"), GTXT ("Multiple Selection"),
+                       (long long) objs->size (), GTXT ("objects"));
+
+  saligns->store (0, TEXT_LEFT);
+  mnemonic->store (0, 'D');
+  jlabels->store (0, dbe_strdup (GTXT ("Data Object")));
+  jvalues->store (0, name);
+
+  saligns->store (1, TEXT_LEFT);
+  mnemonic->store (1, 'S');
+  jlabels->store (1, dbe_strdup (GTXT ("Scope")));
+  jvalues->store (1, scopename);
+
+  saligns->store (2, TEXT_LEFT);
+  mnemonic->store (2, 'T');
+  jlabels->store (2, dbe_strdup (GTXT ("Type")));
+  jvalues->store (2, dbe_strdup (type));
+
+  saligns->store (3, TEXT_LEFT);
+  mnemonic->store (3, 'M');
+  jlabels->store (3, dbe_strdup (GTXT ("Member of")));
+  jvalues->store (3, member);
+
+  saligns->store (4, TEXT_LEFT);
+  mnemonic->store (4, 'O');
+  jlabels->store (4, dbe_strdup (GTXT ("Offset")));
+  jvalues->store (4, offset);
+
+  saligns->store (5, TEXT_LEFT);
+  mnemonic->store (5, 'z');
+  jlabels->store (5, dbe_strdup (GTXT ("Size")));
+  jvalues->store (5, size);
+
+  saligns->store (6, TEXT_LEFT);
+  mnemonic->store (6, 'E');
+  jlabels->store (6, dbe_strdup (GTXT ("Elements")));
+  jvalues->store (6, elements);
+
+  saligns->store (7, TEXT_LEFT);
+  mnemonic->store (7, 'L');
+  jlabels->store (7, dbe_strdup (GTXT ("List")));
+  jvalues->store (7, elist);
+}
+
+#define SUMMARY_NAME 8
+#define DSUMMARY_NAME 8
+#define LSUMMARY_NAME   7
+#define IMSUMMARY_NAME   1
+
+Vector<void*> *
+dbeGetSummaryV2 (int dbevindex, Vector<Obj> *sel_objs, int type, int subtype)
+{
+  if (sel_objs == NULL || sel_objs->size () == 0)
+    return NULL;
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  Vector<Histable*>*objs = new Vector<Histable*>(sel_objs->size ());
+  for (int i = 0; i < sel_objs->size (); i++)
+    {
+      Histable *obj = (Histable *) sel_objs->fetch (i);
+      if (obj == NULL)
+       continue;
+      char *nm = obj->get_name ();
+      if (streq (nm, NTXT ("<Total>")))
+       {
+         // Special case for 'Total'.
+         // Multi selection which includes 'Total' is only 'Total'
+         objs->reset ();
+         objs->append (obj);
+         break;
+       }
+      objs->append (obj);
+    }
+  if (objs->size () == 0)
+    return NULL;
+
+  // Set name area
+  int nname = SUMMARY_NAME;
+  Vector<int> *saligns = new Vector<int>(nname);
+  Vector<char>*mnemonic = new Vector<char>(nname);
+  Vector<char*> *jlabels = new Vector<char*>(nname);
+  Vector<char*> *jvalues = new Vector<char*>(nname);
+  Vector<void*> *name_objs = new Vector<void*>(4);
+  name_objs->store (0, saligns);
+  name_objs->store (1, mnemonic);
+  name_objs->store (2, jlabels);
+  name_objs->store (3, jvalues);
+  setSummary (objs, saligns, mnemonic, jlabels, jvalues);
+
+  MetricList *prop_mlist = new MetricList (dbev->get_metric_ref (MET_NORMAL));
+  if (prop_mlist && dbev->comparingExperiments ())
+    prop_mlist = dbev->get_compare_mlist (prop_mlist, 0);
+
+  int nitems = prop_mlist->get_items ()->size ();
+
+  // Set the metrics area
+  jlabels = new Vector<char*>(nitems);
+  Vector<double> *clock_list = new Vector<double>(nitems);
+  Vector<double> *excl_list = new Vector<double>(nitems);
+  Vector<double> *ep_list = new Vector<double>(nitems);
+  Vector<double> *incl_list = new Vector<double>(nitems);
+  Vector<double> *ip_list = new Vector<double>(nitems);
+  Vector<int> *vtype = new Vector<int>(nitems);
+
+  // Initialize Java String array
+  Vector<void*> *metric_objs = new Vector<void*>(8);
+  metric_objs->store (0, jlabels);
+  metric_objs->store (1, clock_list);
+  metric_objs->store (2, excl_list);
+  metric_objs->store (3, ep_list);
+  metric_objs->store (4, incl_list);
+  metric_objs->store (5, ip_list);
+  metric_objs->store (6, vtype);
+
+  int last_init = -1;
+  for (int i = 0; i < objs->size (); i++)
+    {
+      Histable *obj = objs->fetch (i);
+      // Get the data to be displayed
+      Hist_data *data = dbev->get_hist_data (prop_mlist, obj->get_type (), subtype,
+                                            Hist_data::SELF, obj, dbev->sel_binctx, objs);
+
+      if (data->get_status () != Hist_data::SUCCESS)
+       {
+         if (type != DSP_DLAYOUT)
+           { // For data_layout, rows with zero metrics are OK
+             delete data;
+             continue;
+           }
+       }
+      TValue *values = NULL;
+      if (data->get_status () == Hist_data::SUCCESS)
+       {
+         Hist_data::HistItem *hi = data->fetch (0);
+         if (hi)
+           values = hi->value;
+       }
+      Hist_data::HistItem *total = data->get_totals ();
+      int index2 = 0;
+      char *tstr = GTXT (" Time");
+      char *estr = GTXT ("Exclusive ");
+      size_t len = strlen (estr);
+
+      // get the metric list from the data
+      MetricList *mlist = data->get_metric_list ();
+      int index;
+      Metric *mitem;
+      double clock;
+      Vec_loop (Metric*, mlist->get_items (), index, mitem)
+      {
+       if (mitem->get_subtype () == Metric::STATIC)
+         continue;
+       if (last_init < index2)
+         {
+           last_init = index2;
+           jlabels->store (index2, NULL);
+           clock_list->store (index2, 0.0);
+           excl_list->store (index2, 0.0);
+           ep_list->store (index2, 0.0);
+           incl_list->store (index2, 0.0);
+           ip_list->store (index2, 0.0);
+           vtype->store (index2, 0);
+         }
+       double dvalue = (values != NULL) ? values[index].to_double () : 0.0;
+       double dtotal = total->value[index].to_double ();
+       if (mitem->is_time_val ())
+         clock = 1.e+6 * dbeSession->get_clock (-1);
+       else
+         clock = 0.0;
+
+       clock_list->store (index2, clock);
+       if ((mitem->get_subtype () == Metric::EXCLUSIVE) ||
+           (mitem->get_subtype () == Metric::DATASPACE))
+         {
+           if (i == 0)
+             {
+               char *sstr = mitem->get_name ();
+               if (!strncmp (sstr, estr, len))
+                 sstr += len;
+               char *buf, *lstr = strstr (sstr, tstr);
+               if (lstr)
+                 buf = dbe_strndup (sstr, lstr - sstr);
+               else
+                 buf = dbe_strdup (sstr);
+               jlabels->store (index2, buf);
+               vtype->store (index2, mitem->get_vtype ());
+             }
+           dvalue += excl_list->fetch (index2);
+           double percent = dtotal == 0.0 ? dtotal : (dvalue / dtotal) * 100;
+           excl_list->store (index2, dvalue);
+           ep_list->store (index2, percent);
+         }
+       else
+         {
+           dvalue += incl_list->fetch (index2);
+           if (dvalue > dtotal)
+             dvalue = dtotal; // temporary correction
+           double percent = dtotal == 0.0 ? dtotal : (dvalue / dtotal) * 100;
+           incl_list->store (index2, dvalue);
+           ip_list->store (index2, percent);
+           index2++;
+         }
+      }
+      delete data;
+    }
+  delete prop_mlist;
+  Vector<void*> *summary = new Vector<void*>(2);
+  summary->store (0, name_objs);
+  summary->store (1, metric_objs);
+  return summary;
+}
+
+// Get Summary List
+Vector<void*> *
+dbeGetSummary (int dbevindex, Vector<Obj> *sel_objs, int type, int subtype)
+{
+  bool is_data, is_mem, is_indx, is_iodata, is_heapdata;
+  Hist_data::HistItem *total;
+  MetricList *prop_mlist; // as passed to get_hist_data
+  MetricList *mlist; // as stored in the data
+  Metric *mitem;
+  int i, nname, nitems, index, index2;
+  TValue *values;
+  double dvalue, clock;
+  Hist_data *data;
+  Vector<double> *percent_scale;
+
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  if (sel_objs == NULL || sel_objs->size () == 0)
+    return NULL;
+
+  is_mem = false;
+  is_data = false;
+  is_indx = false;
+  is_iodata = false;
+  is_heapdata = false;
+  nname = SUMMARY_NAME;
+  Vector<Histable*>*objs = new Vector<Histable*>(sel_objs->size ());
+  if (type == DSP_TIMELINE)
+    objs->append ((Histable *) sel_objs->fetch (0));
+  else
+    {
+      switch (type)
+       {
+       case DSP_FUNCTION:
+         data = dbev->func_data;
+         break;
+       case DSP_LINE:
+         data = dbev->line_data;
+         break;
+       case DSP_PC:
+         data = dbev->pc_data;
+         break;
+       case DSP_SELF:
+         data = dbev->fitem_data;
+         break;
+       case DSP_SOURCE:
+       case DSP_SOURCE_V2:
+         data = dbev->src_data;
+         break;
+       case DSP_DISASM:
+       case DSP_DISASM_V2:
+         data = dbev->dis_data;
+         break;
+       case DSP_DLAYOUT:
+         is_data = true;
+         nname = LSUMMARY_NAME;
+         data = dbev->dlay_data;
+         break;
+       case DSP_DATAOBJ:
+         is_data = true;
+         nname = DSUMMARY_NAME;
+         data = dbev->dobj_data;
+         break;
+       case DSP_MEMOBJ:
+         is_data = true;
+         is_mem = true;
+         nname = IMSUMMARY_NAME;
+         data = dbev->get_indxobj_data (subtype);
+         break;
+       case DSP_INDXOBJ:
+         is_indx = true;
+         nname = IMSUMMARY_NAME;
+         data = dbev->get_indxobj_data (subtype);
+         break;
+       case DSP_IOACTIVITY:
+         is_iodata = true;
+         nname = IMSUMMARY_NAME;
+         data = dbev->iofile_data;
+         break;
+       case DSP_IOVFD:
+         is_iodata = true;
+         nname = IMSUMMARY_NAME;
+         data = dbev->iovfd_data;
+         break;
+       case DSP_IOCALLSTACK:
+         is_iodata = true;
+         nname = IMSUMMARY_NAME;
+         data = dbev->iocs_data;
+         break;
+       case DSP_HEAPCALLSTACK:
+         is_heapdata = true;
+         nname = IMSUMMARY_NAME;
+         data = dbev->heapcs_data;
+         break;
+       default:
+         data = NULL;
+         break;
+       }
+      if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+       return NULL;
+
+      Hist_data::HistItem *current_item;
+      for (i = 0; i < sel_objs->size (); i++)
+       {
+         int sel_index = (int) sel_objs->fetch (i);
+         if (type != DSP_IOACTIVITY && type != DSP_IOVFD &&
+             type != DSP_IOCALLSTACK && type != DSP_HEAPCALLSTACK)
+           {
+             if (sel_index < 0 || sel_index >= data->size ())
+               continue;
+             current_item = data->fetch (sel_index);
+             if (current_item->obj == NULL)
+               continue;
+           }
+         else
+           {
+             if (sel_index < 0)
+               continue;
+             bool found = false;
+             for (int j = 0; j < data->size (); j++)
+               {
+                 current_item = data->fetch (j);
+                 if ((current_item->obj != NULL) && (current_item->obj->id == sel_index))
+                   {
+                     found = true;
+                     break;
+                   }
+               }
+             if (!found)
+               continue;
+           }
+         char *nm = current_item->obj->get_name ();
+         if (streq (nm, NTXT ("<Total>")))
+           {
+             // Special case for 'Total'.
+             // Multi selection which includes 'Total' is only 'Total'
+             objs->reset ();
+             objs->append (current_item->obj);
+             break;
+           }
+         objs->append (current_item->obj);
+       }
+    }
+  if (objs->size () == 0)
+    return NULL;
+
+  // Set name area
+  Vector<int> *saligns = new Vector<int>(nname);
+  Vector<char>*mnemonic = new Vector<char>(nname);
+  Vector<char*> *jlabels = new Vector<char*>(nname);
+  Vector<char*> *jvalues = new Vector<char*>(nname);
+  Vector<void*> *name_objs = new Vector<void*>(4);
+  name_objs->store (0, saligns);
+  name_objs->store (1, mnemonic);
+  name_objs->store (2, jlabels);
+  name_objs->store (3, jvalues);
+  if (is_mem)
+    setMemSummary (objs, saligns, mnemonic, jlabels, jvalues);
+  else if (is_indx)
+    setIndxSummary (objs, saligns, mnemonic, jlabels, jvalues);
+  else if (is_data)
+    setDataSummary (objs, saligns, mnemonic, jlabels, jvalues);
+  else if (is_iodata)
+    setIOActivitySummary (objs, saligns, mnemonic, jlabels, jvalues);
+  else if (is_heapdata)
+    setHeapActivitySummary (objs, saligns, mnemonic, jlabels, jvalues);
+  else
+    setSummary (objs, saligns, mnemonic, jlabels, jvalues);
+
+  // Get the reference metrics
+  if (is_data)
+    prop_mlist = new MetricList (dbev->get_metric_ref (MET_DATA));
+  else if (is_indx)
+    prop_mlist = new MetricList (dbev->get_metric_ref (MET_INDX));
+  else if (is_iodata)
+    prop_mlist = new MetricList (dbev->get_metric_ref (MET_IO));
+  else if (is_heapdata)
+    prop_mlist = new MetricList (dbev->get_metric_ref (MET_HEAP));
+  else
+    prop_mlist = new MetricList (dbev->get_metric_ref (MET_NORMAL));
+
+  // XXXX a workaround to avoid aggregated data for compare mode, only show base experiment data
+  if (prop_mlist && dbev->comparingExperiments ())
+    prop_mlist = dbev->get_compare_mlist (prop_mlist, 0);
+  nitems = prop_mlist->get_items ()->size ();
+
+  // Set the metrics area
+  jlabels = new Vector<char*>(nitems);
+  Vector<double> *clock_list = new Vector<double>(nitems);
+  Vector<double> *excl_list = new Vector<double>(nitems);
+  Vector<double> *ep_list = new Vector<double>(nitems);
+  Vector<double> *incl_list = new Vector<double>(nitems);
+  Vector<double> *ip_list = new Vector<double>(nitems);
+  Vector<int> *vtype = new Vector<int>(nitems);
+
+  // Initialize Java String array
+  Vector<void*> *metric_objs = new Vector<void*>(8);
+  metric_objs->store (0, jlabels);
+  metric_objs->store (1, clock_list);
+  metric_objs->store (2, excl_list);
+  metric_objs->store (3, ep_list);
+  metric_objs->store (4, incl_list);
+  metric_objs->store (5, ip_list);
+  metric_objs->store (6, vtype);
+  percent_scale = new Vector<double>();
+  int last_init = -1;
+  for (i = 0; i < objs->size (); i++)
+    {
+      Histable *current_obj = objs->fetch (i);
+      // Get the data to be displayed
+      data = dbev->get_hist_data (prop_mlist, current_obj->get_type (), subtype,
+                                 Hist_data::SELF, current_obj, dbev->sel_binctx, objs);
+      if (data->get_status () != Hist_data::SUCCESS)
+       {
+         if (type != DSP_DLAYOUT)
+           { // For data_layout, rows with zero metrics are OK
+             delete data;
+             continue;
+           }
+       }
+      Hist_data::HistItem *hi = data->fetch (0);
+      values = hi ? hi->value : NULL;
+      total = data->get_totals ();
+      index2 = 0;
+
+      // get the metric list from the data
+      mlist = data->get_metric_list ();
+
+      // We loop over the metrics in mlist.
+      // We construct index2, which tells us
+      // the corresponding entry in the metric_objs lists.
+      // We need this mapping multiple times.
+      // So, if you change the looping in any way here,
+      // do so as well in other similar loops.
+      // All such loops are marked so:
+      // See discussion on "mlist-to-index2 mapping".
+
+      Vec_loop (Metric*, mlist->get_items (), index, mitem)
+      {
+       if (mitem->get_subtype () == Metric::STATIC)
+         continue;
+       if (last_init < index2)
+         {
+           last_init = index2;
+           jlabels->store (index2, NULL);
+           clock_list->store (index2, 0.0);
+           excl_list->store (index2, 0.0);
+           ep_list->store (index2, 0.0);
+           incl_list->store (index2, 0.0);
+           ip_list->store (index2, 0.0);
+           vtype->store (index2, 0);
+         }
+       dvalue = (values != NULL) ? values[index].to_double () : 0.0;
+       double dtotal = total->value[index].to_double ();
+       percent_scale->store (index, dtotal == 0. ? 0. : 100. / dtotal);
+       if (mitem->is_time_val ())
+         clock = 1.e+6 * dbeSession->get_clock (-1);
+       else
+         clock = 0.0;
+
+       clock_list->store (index2, clock);
+       if (mitem->get_subtype () == Metric::EXCLUSIVE ||
+           mitem->get_subtype () == Metric::DATASPACE)
+         {
+           if (i == 0)
+             {
+               char *sstr = mitem->get_username ();
+               char *buf = dbe_strdup (sstr);
+               jlabels->store (index2, buf);
+               vtype->store (index2, mitem->get_vtype ());
+             }
+           dvalue += excl_list->fetch (index2);
+           double percent = dvalue * percent_scale->fetch (index);
+           excl_list->store (index2, dvalue);
+           ep_list->store (index2, percent);
+           if (is_data || is_indx || is_iodata || is_heapdata)
+             // move to next row, except if there's inclusive data, too
+             index2++;
+         }
+       else
+         {
+           dvalue += incl_list->fetch (index2);
+           if (dvalue > dtotal && mitem->get_type () != BaseMetric::DERIVED)
+             dvalue = dtotal; // temporary correction
+           double percent = dvalue * percent_scale->fetch (index);
+           incl_list->store (index2, dvalue);
+           ip_list->store (index2, percent);
+           index2++;
+         }
+      }
+      delete data;
+    }
+
+  // for multi-selection, we have to recompute the derived metrics
+  if (objs->size () > 1 &&
+      dbev->get_derived_metrics () != NULL &&
+      dbev->get_derived_metrics ()->get_items () != NULL &&
+      dbev->get_derived_metrics ()->get_items ()->size () > 0)
+    {
+      // See discussion on "mlist-to-index2 mapping".
+      Vector<Metric*> *mvec = new Vector<Metric*>(nitems);
+      index2 = 0;
+      Vec_loop (Metric*, prop_mlist->get_items (), index, mitem)
+      {
+       if (mitem->get_subtype () == Metric::STATIC)
+         continue;
+       if (mitem->get_subtype () == Metric::EXCLUSIVE ||
+           mitem->get_subtype () == Metric::DATASPACE)
+         {
+           mvec->store (index2, mitem);
+           if (is_data || is_indx || is_iodata || is_heapdata)
+             index2++;
+         }
+       else
+         {
+           assert (strcmp (mvec->fetch (index2)->get_cmd (), mitem->get_cmd ()) == 0);
+           index2++;
+         }
+      }
+      int *map = dbev->get_derived_metrics ()->construct_map (mvec, BaseMetric::EXCLUSIVE, mvec->fetch (0)->get_expr_spec ());
+      if (map != NULL)
+       {
+         int nmetrics = mvec->size ();
+         double *evalues = (double *) malloc (nmetrics * sizeof (double));
+         double *ivalues = (double *) malloc (nmetrics * sizeof (double));
+         for (index2 = 0; index2 < nmetrics; index2++)
+           {
+             evalues[index2] = excl_list->fetch (index2);
+             ivalues[index2] = incl_list->fetch (index2);
+           }
+
+         // evaluate derived metrics
+         dbev->get_derived_metrics ()->eval (map, evalues);
+         dbev->get_derived_metrics ()->eval (map, ivalues);
+         for (index2 = 0; index2 < nmetrics; index2++)
+           {
+             excl_list->store (index2, evalues[index2]);
+             incl_list->store (index2, ivalues[index2]);
+           }
+
+         // recompute percentages for derived metrics    EUGENE maybe all percentage computations should be moved here
+         // See discussion on "mlist-to-index2 mapping".
+         index2 = 0;
+         Vec_loop (Metric*, prop_mlist->get_items (), index, mitem)
+         {
+           if (mitem->get_subtype () == Metric::STATIC)
+             continue;
+           if (mitem->get_subtype () == Metric::EXCLUSIVE ||
+               mitem->get_subtype () == Metric::DATASPACE)
+             {
+               if (mitem->get_type () == BaseMetric::DERIVED)
+                 ep_list->store (index2, excl_list->fetch (index2) * percent_scale->fetch (index));
+               if (is_data || is_indx || is_iodata || is_heapdata)
+                 index2++;
+             }
+           else
+             {
+               if (mitem->get_type () == BaseMetric::DERIVED)
+                 ip_list->store (index2, incl_list->fetch (index2) * percent_scale->fetch (index));
+               index2++;
+             }
+         }
+         free (evalues);
+         free (ivalues);
+         free (map);
+       }
+      delete mvec;
+    }
+  delete prop_mlist;
+  Vector<void*> *summary = new Vector<void*>(2);
+  summary->store (0, name_objs);
+  summary->store (1, metric_objs);
+  delete objs;
+  delete percent_scale;
+  return summary;
+}
+
+char *
+dbeGetExpName (int /*dbevindex*/, char *dir_name)
+{
+  char *ret;
+  char *warn;
+  if (col_ctr == NULL)
+    col_ctr = new Coll_Ctrl (1); // Potential race condition?
+  if (dir_name != NULL)
+    {
+      ret = col_ctr->set_directory (dir_name, &warn);
+      // note that the warning and error msgs are written to stderr, not returned to caller
+      if (warn != NULL)
+       fprintf (stderr, NTXT ("%s"), warn);
+      if (ret != NULL)
+       fprintf (stderr, NTXT ("%s"), ret);
+    }
+  return dbe_strdup (col_ctr->get_expt ());
+}
+
+// === CollectDialog HWC info ===
+
+Vector<Vector<char*>*> *
+dbeGetHwcSets (int /*dbevindex*/, bool forKernel)
+{
+  Vector<Vector<char*>*> *list = new Vector<Vector<char*>*>(2);
+  char * defctrs = hwc_get_default_cntrs2 (forKernel, 1);
+  Vector<char*> *i18n = new Vector<char*>(1); // User name
+  Vector<char*> *name = new Vector<char*>(1); // Internal name
+  if (NULL != defctrs)
+    {
+      i18n->store (0, strdup (defctrs));
+      name->store (0, strdup (NTXT ("default")));
+    }
+  list->store (0, i18n);
+  list->store (1, name);
+  return list;
+}
+
+static Vector<void*> *
+dbeGetHwcs (Hwcentry **hwcs)
+{
+  int sz;
+  for (sz = 0; hwcs && hwcs[sz]; sz++)
+    ;
+  Vector<void*> *list = new Vector<void*>(9);
+  Vector<char*> *i18n = new Vector<char*>(sz);
+  Vector<char*> *name = new Vector<char*>(sz);
+  Vector<char*> *int_name = new Vector<char*>(sz);
+  Vector<char*> *metric = new Vector<char*>(sz);
+  Vector<long long> *val = new Vector<long long>(sz);
+  Vector<int> *timecvt = new Vector<int>(sz);
+  Vector<int> *memop = new Vector<int>(sz);
+  Vector<char*> *short_desc = new Vector<char*>(sz);
+  Vector<Vector<int>*> *reglist_v = new Vector<Vector<int>*>(sz);
+  Vector<bool> *supportsAttrs = new Vector<bool>(sz);
+  Vector<bool> *supportsMemspace = new Vector<bool>(sz);
+
+  for (int i = 0; i < sz; i++)
+    {
+      Hwcentry *ctr = hwcs[i];
+      Vector<int> *registers = new Vector<int>(MAX_PICS);
+      regno_t *reglist = ctr->reg_list;
+      for (int k = 0; !REG_LIST_EOL (reglist[k]) && k < MAX_PICS; k++)
+       registers->store (k, reglist[k]);
+
+      i18n->store (i, dbe_strdup (hwc_i18n_metric (ctr)));
+      name->store (i, dbe_strdup (ctr->name));
+      int_name->store (i, dbe_strdup (ctr->int_name));
+      metric->store (i, dbe_strdup (ctr->metric));
+      val->store (i, ctr->val); // signed promotion from int
+      timecvt->store (i, ctr->timecvt);
+      memop->store (i, ctr->memop);
+      reglist_v->store (i, registers);
+      short_desc->store (i, dbe_strdup (ctr->short_desc));
+      supportsAttrs->store (i, true);
+      supportsMemspace->store (i, ABST_MEMSPACE_ENABLED (ctr->memop));
+    }
+  list->store (0, i18n);
+  list->store (1, name);
+  list->store (2, int_name);
+  list->store (3, metric);
+  list->store (4, val);
+  list->store (5, timecvt);
+  list->store (6, memop);
+  list->store (7, short_desc);
+  list->store (8, reglist_v);
+  list->store (9, supportsAttrs);
+  list->store (10, supportsMemspace);
+  return list;
+}
+
+Vector<void *> *
+dbeGetHwcsAll (int /*dbevindex*/, bool forKernel)
+{
+  Vector<void*> *list = new Vector<void*>(2);
+  list->store (0, dbeGetHwcs (hwc_get_std_ctrs (forKernel)));
+  list->store (1, dbeGetHwcs (hwc_get_raw_ctrs (forKernel)));
+  return list;
+}
+
+Vector<char*> *
+dbeGetHwcHelp (int /*dbevindex*/, bool forKernel)
+{
+  Vector<char*> *strings = new Vector<char*>(32);
+  FILE *f = tmpfile ();
+  hwc_usage_f (forKernel, f, "", 0, 0, 1); // writes to f
+  fflush (f);
+  fseek (f, 0, SEEK_SET);
+#define MAX_LINE_LEN 2048
+  char buff[MAX_LINE_LEN];
+  int ii = 0;
+  while (fgets (buff, MAX_LINE_LEN, f))
+    strings->store (ii++, dbe_strdup (buff));
+  fclose (f);
+  return strings;
+}
+
+Vector<char*> *
+dbeGetHwcAttrList (int /*dbevindex*/, bool forKernel)
+{
+  char ** attr_list = hwc_get_attrs (forKernel); // Get Attribute list
+  int size;
+  for (size = 0; attr_list && attr_list[size]; size++)
+    ;
+
+  Vector<char*> *name = new Vector<char*>(size);
+  for (int i = 0; i < size; i++)
+    name->store (i, dbe_strdup (attr_list[i]));
+  return name;
+}
+
+//Get maximum number of simultaneous counters
+int
+dbeGetHwcMaxConcurrent (int /*dbevindex*/, bool forKernel)
+{
+  return hwc_get_max_concurrent (forKernel);
+}
+
+// === End CollectDialog HWC info ===
+
+
+//  Instruction-frequency data
+Vector<char*> *
+dbeGetIfreqData (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  if (!dbeSession->is_ifreq_available ())
+    return NULL;
+  int size = dbeSession->nexps ();
+  if (size == 0)
+    return NULL;
+
+  // Initialize Java String array
+  Vector<char*> *list = new Vector<char*>();
+  for (int i = 0; i < size; i++)
+    {
+      Experiment *exp = dbeSession->get_exp (i);
+      if (exp->broken || !dbev->get_exp_enable (i) || !exp->ifreqavail)
+       continue;
+      // write a header for the experiment
+      list->append (dbe_sprintf (GTXT ("Instruction frequency data from experiment %s\n\n"),
+                                exp->get_expt_name ()));
+      // add its instruction frequency messages
+      char *ifreq = pr_mesgs (exp->fetch_ifreq (), NTXT (""), NTXT (""));
+      list->append (ifreq);
+    }
+  return list;
+}
+
+//   LeakList related methods
+//
+Vector<void*> *
+dbeGetLeakListInfo (int dbevindex, bool leakflag)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  MetricList *origmlist = dbev->get_metric_list (MET_NORMAL);
+  MetricList *nmlist = new MetricList (origmlist);
+  if (leakflag)
+    nmlist->set_metrics (NTXT ("e.heapleakbytes:e.heapleakcnt:name"), true,
+                        dbev->get_derived_metrics ());
+  else
+    nmlist->set_metrics (NTXT ("e.heapallocbytes:e.heapalloccnt:name"), true,
+                        dbev->get_derived_metrics ());
+  MetricList *mlist = new MetricList (nmlist);
+  delete nmlist;
+
+  CStack_data *lam = dbev->get_cstack_data (mlist);
+  if (lam == NULL || lam->size () == 0)
+    {
+      delete lam;
+      delete mlist;
+      return NULL;
+    }
+  Vector<Vector<Obj>*> *evalue = new Vector<Vector<Obj>*>(lam->size ());
+  Vector<Vector<Obj>*> *pcstack = new Vector<Vector<Obj>*>(lam->size ());
+  Vector<Vector<Obj>*> *offstack = new Vector<Vector<Obj>*>(lam->size ());
+  Vector<Vector<Obj>*> *fpcstack = new Vector<Vector<Obj>*>(lam->size ());
+  Vector<Vector<Obj>*> *sumval = new Vector<Vector<Obj>*>(lam->size ());
+
+  int index;
+  CStack_data::CStack_item *lae;
+  Vec_loop (CStack_data::CStack_item*, lam->cstack_items, index, lae)
+  {
+    Vector<Obj> *jivals = NULL;
+    if (lae != NULL)
+      {
+       jivals = new Vector<Obj>(4);
+       jivals->store (0, (Obj) (index + 1));
+       jivals->store (1, (Obj) lae->value[1].ll);
+       jivals->store (2, (Obj) lae->value[0].ll);
+       jivals->store (3, (Obj) (leakflag ? 1 : 2));
+      }
+    evalue->store (index, jivals);
+    int snum = lae->stack->size ();
+    Vector<Obj> *jivals1 = new Vector<Obj>(snum);
+    Vector<Obj> *jivals2 = new Vector<Obj>(snum);
+    Vector<Obj> *jivals3 = new Vector<Obj>(snum);
+    if (lae->stack != NULL)
+      {
+       for (int i = lae->stack->size () - 1; i >= 0; i--)
+         {
+           DbeInstr *instr = lae->stack->fetch (i);
+           jivals1->store (i, (Obj) instr);
+           jivals2->store (i, (Obj) instr->func);
+           jivals3->store (i, (Obj) instr->addr);
+         }
+      }
+    fpcstack->store (index, jivals1);
+    pcstack->store (index, jivals2);
+    offstack->store (index, jivals3);
+    lae++;
+  }
+  Vector<Obj> *jivals4 = new Vector<Obj>(3);
+  jivals4->store (0, (Obj) lam->size ());
+  jivals4->store (1, (Obj) lam->total->value[1].ll);
+  jivals4->store (2, (Obj) lam->total->value[0].ll);
+  sumval->store (0, jivals4);
+  delete lam;
+  delete mlist;
+  Vector<void*> *earray = new Vector<void*>(5);
+  earray->store (0, evalue);
+  earray->store (1, pcstack);
+  earray->store (2, offstack);
+  earray->store (3, fpcstack);
+  earray->store (4, sumval);
+  return earray;
+}
+
+// Map timeline address to function instr
+//
+Obj
+dbeGetObject (int dbevindex, Obj sel_func, Obj sel_pc)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+   abort ();
+  if (sel_pc)
+    return sel_pc;
+  return sel_func;
+}
+
+char *
+dbeGetName (int /*dbevindex*/, int exp_id)
+// This function's name is not descriptive enough - it returns a string
+//   containing the full experiment name with path, process name, and PID.
+// There are various dbe functions that provide experiment name and experiment
+// details, and they should probably be consolidated/refactored. (TBR)
+// For another example of similar output formatting, see dbeGetExpName().
+{
+  int id = (exp_id < 0) ? 0 : exp_id;
+  Experiment *exp = dbeSession->get_exp (id);
+  if (exp == NULL)
+    return NULL;
+  char *buf =
+         dbe_sprintf (NTXT ("%s [%s, PID %d]"),
+                      exp->get_expt_name (),
+                      exp->utargname != NULL ? exp->utargname : GTXT ("(unknown)"),
+                      exp->getPID ());
+  return buf;
+}
+
+Vector<char*> *
+dbeGetExpVerboseName (Vector<int> *exp_ids)
+{
+  int len = exp_ids->size ();
+  Vector<char*> *list = new Vector<char*>(len);
+  for (int i = 0; i < len; i++)
+    {
+      char * verboseName = dbeGetName (0, exp_ids->fetch (i)); // no strdup()
+      list->store (i, verboseName);
+    }
+  return list;
+}
+
+long long
+dbeGetStartTime (int /*dbevindex*/, int exp_id)
+{
+  int id = (exp_id < 0) ? 0 : exp_id;
+  Experiment *exp = dbeSession->get_exp (id);
+  return exp ? exp->getStartTime () : (long long) 0;
+}
+
+long long
+dbeGetRelativeStartTime (int /*dbevindex*/, int exp_id)
+{
+  int id = (exp_id < 0) ? 0 : exp_id;
+  Experiment *exp = dbeSession->get_exp (id);
+  return exp ? exp->getRelativeStartTime () : (long long) 0;
+}
+
+long long
+dbeGetEndTime (int /*dbevindex*/, int exp_id)
+{
+  int id = (exp_id < 0) ? 0 : exp_id;
+  Experiment *exp = dbeSession->get_exp (id);
+
+  // Experiment::getEndTime was initially implemented as
+  // returning exp->last_event. To preserve the semantics
+  // new Experiment::getLastEvent() is used here.
+  return exp ? exp->getLastEvent () : (long long) 0;
+}
+
+int
+dbeGetClock (int /*dbevindex*/, int exp_id)
+{
+  return dbeSession->get_clock (exp_id);
+}
+
+long long
+dbeGetWallStartSec (int /*dbevindex*/, int exp_id)
+{
+  int id = (exp_id < 0) ? 0 : exp_id;
+  Experiment *exp = dbeSession->get_exp (id);
+  return exp ? exp->getWallStartSec () : 0ll;
+}
+
+char *
+dbeGetHostname (int /*dbevindex*/, int exp_id)
+{
+  int id = (exp_id < 0) ? 0 : exp_id;
+  Experiment *exp = dbeSession->get_exp (id);
+  return exp ? dbe_strdup (exp->hostname) : NULL;
+}
+
+static DataView *
+getTimelinePackets (int dbevindex, int exp_id, int data_id, int entity_prop_id)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  const int sortprop_count = 3;
+  const int sortprops[sortprop_count] = {
+    PROP_HWCTAG, // aux
+    entity_prop_id,
+    PROP_TSTAMP
+  };
+  DataView *packets = dbev->get_filtered_events (exp_id, data_id,
+                                                sortprops, sortprop_count);
+  return packets;
+}
+
+static long
+getIdxByVals (DataView * packets, int aux, int entity_prop_val,
+             uint64_t time, DataView::Relation rel)
+{
+  const int sortprop_count = 3;
+  Datum tval[sortprop_count];
+  tval[0].setUINT32 (aux);
+  tval[1].setUINT32 (entity_prop_val); //CPUID, LWPID, THRID are downsized to 32
+  tval[2].setUINT64 (time);
+  long idx = packets->getIdxByVals (tval, rel);
+  return idx;
+}
+
+static bool
+isValidIdx (DataView * packets, int entity_prop_id,
+           int aux, int entity_prop_val, long idx)
+{
+  if (idx < 0 || idx >= packets->getSize ())
+    return false;
+  int pkt_aux = packets->getIntValue (PROP_HWCTAG, idx);
+  if (pkt_aux != aux)
+    return false;
+  if (entity_prop_id == PROP_EXPID)
+    return true; // not a packet property; we know the packet is in this experiment
+  if (entity_prop_id == PROP_NONE)
+    return true; // not a packet property; we know the packet is in this experiment
+  int pkt_ent = packets->getIntValue (entity_prop_id, idx);
+  if (pkt_ent != entity_prop_val)
+    return false;
+  return true;
+}
+
+static bool
+hasInvisbleTLEvents (Experiment *exp, VMode view_mode)
+{
+  if (exp->has_java && view_mode == VMODE_USER)
+    return true;
+  return false;
+}
+
+static bool
+isVisibleTLEvent (Experiment *exp, VMode view_mode, DataView* packets, long idx)
+{
+  if (hasInvisbleTLEvents (exp, view_mode))
+    {
+      JThread *jthread = (JThread*) packets->getObjValue (PROP_JTHREAD, idx);
+      if (jthread == JTHREAD_NONE || (jthread != NULL && jthread->is_system ()))
+       return false;
+    }
+  return true;
+}
+
+static long
+getTLVisibleIdxByStepping (Experiment *exp, VMode view_mode, int entity_prop_id,
+                          DataView * packets, int aux, int entity_prop_val,
+                          long idx, long move_count, int direction)
+{
+  assert (move_count >= 0);
+  assert (direction == 1 || direction == -1 || direction == 0);
+  if (direction == 0 /* precise hit required */)
+    move_count = 0;
+  do
+    {
+      if (!isValidIdx (packets, entity_prop_id, aux, entity_prop_val, idx))
+       return -1;
+      if (isVisibleTLEvent (exp, view_mode, packets, idx))
+       {
+         if (move_count <= 0)
+           break;
+         move_count--;
+       }
+      if (direction == 0)
+       return -1;
+      idx += direction;
+    }
+  while (1);
+  return idx;
+}
+
+static long
+getTLVisibleIdxByVals (Experiment *exp, VMode view_mode, int entity_prop_id,
+                      DataView * packets,
+                      int aux, int entity_prop_val, uint64_t time, DataView::Relation rel)
+{
+  long idx = getIdxByVals (packets, aux, entity_prop_val, time, rel);
+  if (!hasInvisbleTLEvents (exp, view_mode))
+    return idx;
+  if (idx < 0)
+    return idx;
+  if (rel == DataView::REL_EQ)
+    return -1; // would require bi-directional search... not supported for now
+  int direction = (rel == DataView::REL_LT || rel == DataView::REL_LTEQ) ? -1 : 1;
+  idx = getTLVisibleIdxByStepping (exp, view_mode, entity_prop_id, packets,
+                                  aux, entity_prop_val,
+                                  idx, 0 /* first match */, direction);
+  return idx;
+}
+
+// In thread mode, the entity name for non Java thread should be the 1st func
+// from the current thread's stack. See #4961315
+static char*
+getThreadRootFuncName (int, int, int, int, VMode)
+{
+  return NULL; // until we figure out what we want to show... YXXX
+}
+
+Vector<void*> *
+dbeGetEntityProps (int dbevindex) //YXXX TBD, should this be exp-specific?
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Vector<int> *prop_id = new Vector<int>();
+  Vector<char*> *prop_name = new Vector<char*>();
+  Vector<char*> *prop_uname = new Vector<char*>();
+  Vector<char*> *prop_cname = new Vector<char*>(); //must match TLModeCmd vals!
+
+  prop_id->append (PROP_NONE);
+  prop_name->append (dbe_strdup (GTXT ("NONE")));
+  prop_uname->append (dbe_strdup (GTXT ("Unknown")));
+  prop_cname->append (dbe_strdup (NTXT ("unknown")));
+
+  prop_id->append (PROP_LWPID);
+  prop_name->append (dbe_strdup (GTXT ("LWPID")));
+  prop_uname->append (dbe_strdup (GTXT ("LWP")));
+  prop_cname->append (dbe_strdup (NTXT ("lwp")));
+
+  prop_id->append (PROP_THRID);
+  prop_name->append (dbe_strdup (GTXT ("THRID")));
+  prop_uname->append (dbe_strdup (GTXT ("Thread")));
+  prop_cname->append (dbe_strdup (NTXT ("thread")));
+
+  prop_id->append (PROP_CPUID);
+  prop_name->append (dbe_strdup (GTXT ("CPUID")));
+  prop_uname->append (dbe_strdup (GTXT ("CPU")));
+  prop_cname->append (dbe_strdup (NTXT ("cpu")));
+
+  prop_id->append (PROP_EXPID);
+  prop_name->append (dbe_strdup (GTXT ("EXPID")));
+  prop_uname->append (dbe_strdup (GTXT ("Process"))); // placeholder...
+  // ...until we finalize how to expose user-level Experiments, descendents
+  prop_cname->append (dbe_strdup (NTXT ("experiment")));
+  Vector<void*> *darray = new Vector<void*>();
+  darray->store (0, prop_id);
+  darray->store (1, prop_name);
+  darray->store (2, prop_uname);
+  darray->store (3, prop_cname);
+  return darray;
+}
+
+Vector<void*> *
+dbeGetEntities (int dbevindex, int exp_id, int entity_prop_id)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Experiment *exp = dbeSession->get_exp (exp_id);
+  if (exp == NULL)
+    return NULL;
+
+  // Recognize and skip faketime experiments
+  if (exp->timelineavail == false)
+    return NULL;
+  Vector<Histable*> *tagObjs = exp->getTagObjs ((Prop_type) entity_prop_id);
+  int total_nelem;
+  if (tagObjs)
+    total_nelem = (int) tagObjs->size ();
+  else
+    total_nelem = 0;
+  const VMode view_mode = dbev->get_view_mode ();
+  bool show_java_threadnames = (entity_prop_id == PROP_THRID &&
+                               view_mode != VMODE_MACHINE);
+  // allocate the structures for the return
+  Vector<int> *entity_prop_vals = new Vector<int>();
+  Vector<char*> *jthr_names = new Vector<char*>();
+  Vector<char*> *jthr_g_names = new Vector<char*>();
+  Vector<char*> *jthr_p_names = new Vector<char*>();
+
+  // now walk the tagObjs from the experiment, and check for filtering
+  for (int tagObjsIdx = 0; tagObjsIdx < total_nelem; tagObjsIdx++)
+    {
+      int entity_prop_val = (int) ((Other *) tagObjs->fetch (tagObjsIdx))->tag;
+      entity_prop_vals->append (entity_prop_val);
+      char *jname, *jgname, *jpname;
+      JThread *jthread = NULL;
+      bool has_java_threadnames = false;
+      if (show_java_threadnames)
+       {
+         jthread = exp->get_jthread (entity_prop_val);
+         has_java_threadnames = (jthread != JTHREAD_DEFAULT
+                                 && jthread != JTHREAD_NONE);
+       }
+      if (!has_java_threadnames)
+       {
+         jname = jgname = jpname = NULL;
+         if (entity_prop_id == PROP_THRID || entity_prop_id == PROP_LWPID)
+           // if non Java thread, set thread name to the 1st func
+           // from the current thread's stack. see #4961315
+           jname = getThreadRootFuncName (dbevindex, exp_id, entity_prop_id,
+                                          entity_prop_val, view_mode);
+       }
+      else
+       {
+         jname = dbe_strdup (jthread->name);
+         jgname = dbe_strdup (jthread->group_name);
+         jpname = dbe_strdup (jthread->parent_name);
+       }
+      jthr_names->append (jname);
+      jthr_g_names->append (jgname);
+      jthr_p_names->append (jpname);
+    }
+  Vector<char*> *entity_prop_name_v = new Vector<char*>();
+  char* entity_prop_name = dbeSession->getPropName (entity_prop_id);
+  entity_prop_name_v->append (entity_prop_name);
+  Vector<void*> *darray = new Vector<void*>(5);
+  darray->store (0, entity_prop_vals);
+  darray->store (1, jthr_names);
+  darray->store (2, jthr_g_names);
+  darray->store (3, jthr_p_names);
+  darray->store (4, entity_prop_name_v); // vector only has 1 element
+  return darray;
+}
+
+// TBR: dbeGetEntities() can be set to private now that we have dbeGetEntitiesV2()
+Vector<void*> *
+dbeGetEntitiesV2 (int dbevindex, Vector<int> *exp_ids, int entity_prop_id)
+{
+  int sz = exp_ids->size ();
+  Vector<void*> *res = new Vector<void*>(sz);
+  for (int ii = 0; ii < sz; ii++)
+    {
+      int expIdx = exp_ids->fetch (ii);
+      Vector<void*>* ents = dbeGetEntities (dbevindex, expIdx, entity_prop_id);
+      res->store (ii, ents);
+    }
+  return res;
+}
+
+//YXXX old-tl packets still used for details
+static Vector<void*> *
+getTLDetailValues (int dbevindex, Experiment * exp, int data_id,
+                  VMode view_mode, DataView *packets, long idx)
+{
+  Vector<long long> *value = new Vector<long long>(15);
+  long i = idx;
+  if (data_id == DATA_SAMPLE || data_id == DATA_GCEVENT)
+    {
+      //YXXX DATA_SAMPLE not handled but could be.
+    }
+  Obj stack = (unsigned long) getStack (view_mode, packets, i);
+  Vector<Obj> *funcs = stack ? dbeGetStackFunctions (dbevindex, stack) : NULL;
+  Function *func = (Function*)
+         getStackPC (0, view_mode, packets, i)->convertto (Histable::FUNCTION);
+  // Fill common data
+  value->store (0, packets->getIntValue (PROP_LWPID, i));
+  value->store (1, packets->getIntValue (PROP_THRID, i));
+  value->store (2, packets->getIntValue (PROP_CPUID, i));
+  value->store (3, packets->getLongValue (PROP_TSTAMP, i));
+  value->store (4, (unsigned long) stack);
+  value->store (5, (unsigned long) func);
+
+  // Fill specific data
+  switch (data_id)
+    {
+    case DATA_CLOCK:
+      value->store (6, packets->getIntValue (PROP_MSTATE, i));
+      {
+       hrtime_t interval = exp->get_params ()->ptimer_usec * 1000LL // nanoseconds
+               * packets->getLongValue (PROP_NTICK, i);
+       value->store (7, interval);
+      }
+      value->store (8, packets->getIntValue (PROP_OMPSTATE, i));
+      value->store (9, packets->getLongValue (PROP_EVT_TIME, i)); // visual duration
+      break;
+    case DATA_SYNCH:
+      value->store (6, packets->getLongValue (PROP_EVT_TIME, i));
+      value->store (7, packets->getLongValue (PROP_SOBJ, i));
+      break;
+    case DATA_HWC:
+      value->store (6, packets->getLongValue (PROP_HWCINT, i));
+      value->store (7, packets->getLongValue (PROP_VADDR, i)); // data vaddr
+      value->store (8, packets->getLongValue (PROP_PADDR, i)); // data paddr
+      value->store (9, packets->getLongValue (PROP_VIRTPC, i)); // pc paddr
+      value->store (10, packets->getLongValue (PROP_PHYSPC, i)); // pc vaddr
+      break;
+    case DATA_RACE:
+      value->store (6, packets->getIntValue (PROP_RTYPE, i));
+      value->store (7, packets->getIntValue (PROP_RID, i));
+      value->store (8, packets->getLongValue (PROP_RVADDR, i));
+      break;
+    case DATA_DLCK:
+      value->store (6, packets->getIntValue (PROP_DTYPE, i));
+      value->store (7, packets->getIntValue (PROP_DLTYPE, i));
+      value->store (8, packets->getIntValue (PROP_DID, i));
+      value->store (9, packets->getLongValue (PROP_DVADDR, i));
+      break;
+    case DATA_HEAP:
+    case DATA_HEAPSZ:
+      value->store (6, packets->getIntValue (PROP_HTYPE, i));
+      value->store (7, packets->getLongValue (PROP_HSIZE, i));
+      value->store (8, packets->getLongValue (PROP_HVADDR, i));
+      value->store (9, packets->getLongValue (PROP_HOVADDR, i));
+      value->store (10, packets->getLongValue (PROP_HLEAKED, i));
+      value->store (11, packets->getLongValue (PROP_HFREED, i));
+      value->store (12, packets->getLongValue (PROP_HCUR_ALLOCS, i)); // signed int64_t
+      value->store (13, packets->getLongValue (PROP_HCUR_LEAKS, i));
+      break;
+    case DATA_IOTRACE:
+      value->store (6, packets->getIntValue (PROP_IOTYPE, i));
+      value->store (7, packets->getIntValue (PROP_IOFD, i));
+      value->store (8, packets->getLongValue (PROP_IONBYTE, i));
+      value->store (9, packets->getLongValue (PROP_EVT_TIME, i));
+      value->store (10, packets->getIntValue (PROP_IOVFD, i));
+      break;
+    }
+  Vector<void*> *result = new Vector<void*>(5);
+  result->store (0, value);
+  result->store (1, funcs); // Histable::Function*
+  result->store (2, funcs ? dbeGetFuncNames (dbevindex, funcs) : 0); // formatted func names
+  result->store (3, stack ? dbeGetStackPCs (dbevindex, stack) : 0); // Histable::DbeInstr*
+  result->store (4, stack ? dbeGetStackNames (dbevindex, stack) : 0); // formatted pc names
+  return result;
+}
+
+Vector<void*> *
+dbeGetTLDetails (int dbevindex, int exp_id, int data_id,
+                int entity_prop_id, Obj event_id)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Experiment *exp = dbeSession->get_exp (exp_id < 0 ? 0 : exp_id);
+  if (exp == NULL)
+    return NULL;
+  DataView *packets =
+         getTimelinePackets (dbevindex, exp_id, data_id, entity_prop_id);
+  if (!packets)
+    return NULL;
+
+  VMode view_mode = dbev->get_view_mode ();
+  long idx = (long) event_id;
+  Vector<void*> *values = getTLDetailValues (dbevindex, exp, data_id, view_mode, packets, idx);
+  return values;
+}
+
+Vector<Obj> *
+dbeGetStackFunctions (int dbevindex, Obj stack)
+{
+  Vector<Obj> *instrs = dbeGetStackPCs (dbevindex, stack);
+  if (instrs == NULL)
+    return NULL;
+  int stsize = instrs->size ();
+  Vector<Obj> *jivals = new Vector<Obj>(stsize);
+  for (int i = 0; i < stsize; i++)
+    {
+      Histable *obj = (Histable*) instrs->fetch (i);
+      // if ( obj->get_type() != Histable::LINE ) {//YXXX what is this?
+      // Remove the above check: why not do this conversion for lines -
+      // otherwise filtering in timeline by function stack in omp user mode is broken
+      obj = obj->convertto (Histable::FUNCTION);
+      jivals->store (i, (Obj) obj);
+    }
+  delete instrs;
+  return jivals;
+}
+
+Vector<void*> *
+dbeGetStacksFunctions (int dbevindex, Vector<Obj> *stacks)
+{
+  long sz = stacks->size ();
+  Vector<void*> *res = new Vector<void*>(sz);
+  for (int ii = 0; ii < sz; ii++)
+    {
+      Obj stack = stacks->fetch (ii);
+      Vector<Obj> *jivals = dbeGetStackFunctions (dbevindex, stack);
+      res->store (ii, jivals);
+    }
+  return res;
+}
+
+Vector<Obj> *
+dbeGetStackPCs (int dbevindex, Obj stack)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  if (stack == 0)
+    return NULL;
+
+  bool show_all = dbev->isShowAll ();
+  Vector<Histable*> *instrs = CallStack::getStackPCs ((void *) stack, !show_all);
+  int stsize = instrs->size ();
+  int istart = 0;
+  bool showAll = dbev->isShowAll ();
+  for (int i = 0; i < stsize - 1; i++)
+    {
+      Function *func = (Function*) instrs->fetch (i)->convertto (Histable::FUNCTION);
+      int ix = func->module->loadobject->seg_idx;
+      if (showAll && dbev->get_lo_expand (ix) == LIBEX_API)
+       // truncate stack here:  LIBRARY_VISIBILITY if we are using API only but no hide
+       istart = i;
+    }
+  stsize = stsize - istart;
+  Vector<Obj> *jlvals = new Vector<Obj>(stsize);
+  for (int i = 0; i < stsize; i++)
+    {
+      Histable *instr = instrs->fetch (i + istart);
+      jlvals->store (i, (Obj) instr);
+    }
+  delete instrs;
+  return jlvals;
+}
+
+Vector<char*> *
+dbeGetStackNames (int dbevindex, Obj stack)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  Vector<Obj> *instrs = dbeGetStackPCs (dbevindex, stack);
+  if (instrs == NULL)
+    return NULL;
+  int stsize = instrs->size ();
+  Vector<char*> *list = new Vector<char*>(stsize);
+  bool showAll = dbev->isShowAll ();
+  for (int i = 0; i < stsize; i++)
+    {
+      Histable* instr = (Histable*) instrs->fetch (i);
+      if (!showAll)
+       {
+         // LIBRARY_VISIBILITY
+         Function *func = (Function*) instr->convertto (Histable::FUNCTION);
+         LoadObject *lo = ((Function*) func)->module->loadobject;
+         if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE)
+           {
+             list->store (i, dbe_strdup (lo->get_name ()));
+             continue;
+           }
+       }
+      list->store (i, dbe_strdup (instr->get_name (dbev->get_name_format ())));
+    }
+  delete instrs;
+  return list;
+}
+
+Vector<void*> *
+dbeGetSamples (int dbevindex, int exp_id, int64_t lo_idx, int64_t hi_idx)
+{
+  DataView * packets =
+         getTimelinePackets (dbevindex, exp_id, DATA_SAMPLE, PROP_EXPID);
+  if (packets == NULL || packets->getSize () == 0)
+    return NULL;
+  long lo;
+  if (lo_idx < 0)
+    lo = 0;
+  else
+    lo = (long) lo_idx;
+
+  long long max = packets->getSize () - 1;
+  long hi;
+  if (hi_idx < 0 || hi_idx > max)
+    hi = (long) max;
+  else
+    hi = (long) hi_idx;
+
+  Vector<Vector<long long>*> *sarray = new Vector<Vector<long long>*>;
+  Vector<long long>* starts = new Vector<long long>;
+  Vector<long long>* ends = new Vector<long long>;
+  Vector<long long>* rtimes = new Vector<long long>;
+  Vector<char*> *startNames = new Vector<char*>;
+  Vector<char*> *endNames = new Vector<char*>;
+  Vector<int> *sampId = new Vector<int>;
+
+  for (long index = lo; index <= hi; index++)
+    {
+      Sample *sample = (Sample*) packets->getObjValue (PROP_SMPLOBJ, index);
+      PrUsage *prusage = sample->get_usage ();
+      if (prusage == NULL)
+       prusage = new PrUsage;
+      Vector<long long> *states = prusage->getMstateValues ();
+      sarray->append (states);
+      starts->append (sample->get_start_time ());
+      ends->append (sample->get_end_time ());
+      rtimes->append (prusage->pr_rtime);
+      startNames->append (dbe_strdup (sample->get_start_label ()));
+      endNames->append (dbe_strdup (sample->get_end_label ()));
+      sampId->append (sample->get_number ());
+    }
+  Vector<void *> *res = new Vector<void*>(6);
+  res->store (0, sarray);
+  res->store (1, starts);
+  res->store (2, ends);
+  res->store (3, rtimes);
+  res->store (4, startNames);
+  res->store (5, endNames);
+  res->store (6, sampId);
+  return res;
+}
+
+Vector<void*> *
+dbeGetGCEvents (int dbevindex, int exp_id, int64_t lo_idx, int64_t hi_idx)
+{
+  DataView *packets =
+         getTimelinePackets (dbevindex, exp_id, DATA_GCEVENT, PROP_EXPID);
+  if (packets == NULL || packets->getSize () == 0)
+    return NULL;
+
+  long lo;
+  if (lo_idx < 0)
+    lo = 0;
+  else
+    lo = (long) lo_idx;
+  long long max = packets->getSize () - 1;
+  long hi;
+  if (hi_idx < 0 || hi_idx > max)
+    hi = (long) max;
+  else
+    hi = (long) hi_idx;
+
+  Vector<long long>* starts = new Vector<long long>;
+  Vector<long long>* ends = new Vector<long long>;
+  Vector<int> *eventId = new Vector<int>;
+  for (long index = lo; index <= hi; index++)
+    {
+      GCEvent *gcevent = (GCEvent*) packets->getObjValue (PROP_GCEVENTOBJ, index);
+      if (gcevent)
+       {
+         starts->append (gcevent->start);
+         ends->append (gcevent->end);
+         eventId->append (gcevent->id);
+       }
+    }
+  Vector<void *> *res = new Vector<void*>(3);
+  res->store (0, starts);
+  res->store (1, ends);
+  res->store (2, eventId);
+  return res;
+}
+
+Vector<Vector<char*>*>*
+dbeGetIOStatistics (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  Hist_data *hist_data;
+  Hist_data::HistItem *hi;
+  FileData *fDataTotal;
+
+  hist_data = dbev->iofile_data;
+  if (hist_data == NULL)
+    return NULL;
+  hi = hist_data->fetch (0);
+  fDataTotal = (FileData*) hi->obj;
+
+  Vector<char*> *writeStat = new Vector<char*>;
+  Vector<char*> *readStat = new Vector<char*>;
+  Vector<char*> *otherStat = new Vector<char*>;
+  Vector<char*> *errorStat = new Vector<char*>;
+
+  writeStat->append (dbe_strdup (GTXT ("Write Statistics")));
+  readStat->append (dbe_strdup (GTXT ("Read Statistics")));
+  otherStat->append (dbe_strdup (GTXT ("Other I/O Statistics")));
+  errorStat->append (dbe_strdup (GTXT ("I/O Error Statistics")));
+
+  StringBuilder sb;
+  if (fDataTotal->getWriteCnt () > 0)
+    {
+      if (fDataTotal->getW0KB1KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("0KB - 1KB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW0KB1KBCnt ());
+         writeStat->append (sb.toString ());
+       }
+      if (fDataTotal->getW1KB8KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1KB - 8KB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW1KB8KBCnt ());
+         writeStat->append (sb.toString ());
+       }
+      if (fDataTotal->getW8KB32KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("8KB - 32KB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW8KB32KBCnt ());
+         writeStat->append (sb.toString ());
+       }
+      if (fDataTotal->getW32KB128KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("32KB - 128KB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW32KB128KBCnt ());
+         writeStat->append (sb.toString ());
+       }
+      if (fDataTotal->getW128KB256KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("128KB - 256KB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW128KB256KBCnt ());
+         writeStat->append (sb.toString ());
+       }
+      if (fDataTotal->getW256KB512KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("256KB - 512KB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW256KB512KBCnt ());
+         writeStat->append (sb.toString ());
+       }
+      if (fDataTotal->getW512KB1000KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("512KB - 1000KB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW512KB1000KBCnt ());
+         writeStat->append (sb.toString ());
+       }
+      if (fDataTotal->getW1000KB10MBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1000KB - 10MB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW1000KB10MBCnt ());
+         writeStat->append (sb.toString ());
+       }
+      if (fDataTotal->getW10MB100MBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("10MB - 100MB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW10MB100MBCnt ());
+         writeStat->append (sb.toString ());
+       }
+      if (fDataTotal->getW100MB1GBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("100MB - 1GB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW100MB1GBCnt ());
+         writeStat->append (sb.toString ());
+       }
+      if (fDataTotal->getW1GB10GBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1GB - 10GB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW1GB10GBCnt ());
+         writeStat->append (sb.toString ());
+       }
+      if (fDataTotal->getW10GB100GBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("10GB - 100GB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW10GB100GBCnt ());
+         writeStat->append (sb.toString ());
+       }
+      if (fDataTotal->getW100GB1TBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("100GB - 1TB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW100GB1TBCnt ());
+         writeStat->append (sb.toString ());
+       }
+      if (fDataTotal->getW1TB10TBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1TB - 10TB"));
+         writeStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getW1TB10TBCnt ());
+         writeStat->append (sb.toString ());
+       }
+
+      sb.sprintf (GTXT ("Longest write"));
+      writeStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%.6f (secs.)"),
+                 (double) (fDataTotal->getWSlowestBytes () / (double) NANOSEC));
+      writeStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Smallest write bytes"));
+      writeStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getWSmallestBytes ()));
+      writeStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Largest write bytes"));
+      writeStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getWLargestBytes ()));
+      writeStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Total time"));
+      writeStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%.6f (secs.)"),
+                 (double) (fDataTotal->getWriteTime () / (double) NANOSEC));
+      writeStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Total calls"));
+      writeStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getWriteCnt ()));
+      writeStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Total bytes"));
+      writeStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%lld"), (long long) (fDataTotal->getWriteBytes ()));
+      writeStat->append (sb.toString ());
+    }
+
+  if (fDataTotal->getReadCnt () > 0)
+    {
+      if (fDataTotal->getR0KB1KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("0KB - 1KB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR0KB1KBCnt ());
+         readStat->append (sb.toString ());
+       }
+      if (fDataTotal->getR1KB8KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1KB - 8KB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR1KB8KBCnt ());
+         readStat->append (sb.toString ());
+       }
+      if (fDataTotal->getR8KB32KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("8KB - 32KB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR8KB32KBCnt ());
+         readStat->append (sb.toString ());
+       }
+      if (fDataTotal->getR32KB128KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("32KB - 128KB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR32KB128KBCnt ());
+         readStat->append (sb.toString ());
+       }
+      if (fDataTotal->getR128KB256KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("128KB - 256KB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR128KB256KBCnt ());
+         readStat->append (sb.toString ());
+       }
+      if (fDataTotal->getR256KB512KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("256KB - 512KB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR256KB512KBCnt ());
+         readStat->append (sb.toString ());
+       }
+      if (fDataTotal->getR512KB1000KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("512KB - 1000KB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR512KB1000KBCnt ());
+         readStat->append (sb.toString ());
+       }
+      if (fDataTotal->getR1000KB10MBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1000KB - 10MB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR1000KB10MBCnt ());
+         readStat->append (sb.toString ());
+       }
+      if (fDataTotal->getR10MB100MBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("10MB - 100MB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR10MB100MBCnt ());
+         readStat->append (sb.toString ());
+       }
+      if (fDataTotal->getR100MB1GBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("100MB - 1GB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR100MB1GBCnt ());
+         readStat->append (sb.toString ());
+       }
+      if (fDataTotal->getR1GB10GBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1GB - 10GB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR1GB10GBCnt ());
+         readStat->append (sb.toString ());
+       }
+      if (fDataTotal->getR10GB100GBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("10GB - 100GB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR10GB100GBCnt ());
+         readStat->append (sb.toString ());
+       }
+      if (fDataTotal->getR100GB1TBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("100GB - 1TB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR100GB1TBCnt ());
+         readStat->append (sb.toString ());
+       }
+      if (fDataTotal->getR1TB10TBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1TB - 10TB"));
+         readStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), fDataTotal->getR1TB10TBCnt ());
+         readStat->append (sb.toString ());
+       }
+
+      sb.sprintf (GTXT ("Longest read"));
+      readStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%.6f (secs.)"),
+                 (double) (fDataTotal->getRSlowestBytes () / (double) NANOSEC));
+      readStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Smallest read bytes"));
+      readStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getRSmallestBytes ()));
+      readStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Largest read bytes"));
+      readStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getRLargestBytes ()));
+      readStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Total time"));
+      readStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%.6f (secs.)"),
+                 (double) (fDataTotal->getReadTime () / (double) NANOSEC));
+      readStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Total calls"));
+      readStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getReadCnt ()));
+      readStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Total bytes"));
+      readStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%lld"), (long long) (fDataTotal->getReadBytes ()));
+      readStat->append (sb.toString ());
+    }
+
+  if (fDataTotal->getOtherCnt () > 0)
+    {
+      sb.sprintf (GTXT ("Total time"));
+      otherStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%.6f (secs.)"),
+                 (double) (fDataTotal->getOtherTime () / (double) NANOSEC));
+      otherStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Total calls"));
+      otherStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getOtherCnt ()));
+      otherStat->append (sb.toString ());
+    }
+
+  if (fDataTotal->getErrorCnt () > 0)
+    {
+      sb.sprintf (GTXT ("Total time"));
+      errorStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%.6f (secs.)"),
+                 (double) (fDataTotal->getErrorTime () / (double) NANOSEC));
+      errorStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Total calls"));
+      errorStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (fDataTotal->getErrorCnt ()));
+      errorStat->append (sb.toString ());
+    }
+  Vector<Vector<char*>*>* statisticsData = new Vector<Vector<char*>*>(4);
+  statisticsData->store (0, writeStat);
+  statisticsData->store (1, readStat);
+  statisticsData->store (2, otherStat);
+  statisticsData->store (3, errorStat);
+  return statisticsData;
+}
+
+Vector<Vector<char*>*>*
+dbeGetHeapStatistics (int dbevindex)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  Hist_data *hist_data;
+  Hist_data::HistItem *hi;
+  HeapData *hDataTotal;
+  hist_data = dbev->heapcs_data;
+  if (hist_data == NULL)
+    return NULL;
+
+  hi = hist_data->fetch (0);
+  hDataTotal = (HeapData*) hi->obj;
+  Vector<char*> *memoryUsage = new Vector<char*>;
+  Vector<char*> *allocStat = new Vector<char*>;
+  Vector<char*> *leakStat = new Vector<char*>;
+
+  memoryUsage->append (dbe_strdup (GTXT ("Process With Highest Peak Memory Usage")));
+  allocStat->append (dbe_strdup (GTXT ("Memory Allocations Statistics")));
+  leakStat->append (dbe_strdup (GTXT ("Memory Leaks Statistics")));
+  StringBuilder sb;
+  if (hDataTotal->getPeakMemUsage () > 0)
+    {
+      sb.sprintf (GTXT ("Heap size bytes"));
+      memoryUsage->append (sb.toString ());
+      sb.sprintf (NTXT ("%lld"), (long long) (hDataTotal->getPeakMemUsage ()));
+      memoryUsage->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Experiment Id"));
+      memoryUsage->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getUserExpId ()));
+      memoryUsage->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Process Id"));
+      memoryUsage->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getPid ()));
+      memoryUsage->append (sb.toString ());
+
+      Vector<hrtime_t> *pTimestamps;
+      pTimestamps = hDataTotal->getPeakTimestamps ();
+      if (pTimestamps != NULL)
+       {
+         for (int i = 0; i < pTimestamps->size (); i++)
+           {
+             sb.sprintf (GTXT ("Time of peak"));
+             memoryUsage->append (sb.toString ());
+             sb.sprintf (NTXT ("%.3f (secs.)"), (double) (pTimestamps->fetch (i) / (double) NANOSEC));
+             memoryUsage->append (sb.toString ());
+           }
+       }
+    }
+
+  if (hDataTotal->getAllocCnt () > 0)
+    {
+      if (hDataTotal->getA0KB1KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("0KB - 1KB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA0KB1KBCnt ());
+         allocStat->append (sb.toString ());
+       }
+      if (hDataTotal->getA1KB8KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1KB - 8KB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA1KB8KBCnt ());
+         allocStat->append (sb.toString ());
+       }
+      if (hDataTotal->getA8KB32KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("8KB - 32KB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA8KB32KBCnt ());
+         allocStat->append (sb.toString ());
+       }
+      if (hDataTotal->getA32KB128KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("32KB - 128KB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA32KB128KBCnt ());
+         allocStat->append (sb.toString ());
+       }
+      if (hDataTotal->getA128KB256KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("128KB - 256KB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA128KB256KBCnt ());
+         allocStat->append (sb.toString ());
+       }
+      if (hDataTotal->getA256KB512KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("256KB - 512KB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA256KB512KBCnt ());
+         allocStat->append (sb.toString ());
+       }
+      if (hDataTotal->getA512KB1000KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("512KB - 1000KB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA512KB1000KBCnt ());
+         allocStat->append (sb.toString ());
+       }
+      if (hDataTotal->getA1000KB10MBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1000KB - 10MB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA1000KB10MBCnt ());
+         allocStat->append (sb.toString ());
+       }
+      if (hDataTotal->getA10MB100MBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("10MB - 100MB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA10MB100MBCnt ());
+         allocStat->append (sb.toString ());
+       }
+      if (hDataTotal->getA100MB1GBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("100MB - 1GB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA100MB1GBCnt ());
+         allocStat->append (sb.toString ());
+       }
+      if (hDataTotal->getA1GB10GBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1GB - 10GB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA1GB10GBCnt ());
+         allocStat->append (sb.toString ());
+       }
+      if (hDataTotal->getA10GB100GBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("10GB - 100GB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA10GB100GBCnt ());
+         allocStat->append (sb.toString ());
+       }
+      if (hDataTotal->getA100GB1TBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("100GB - 1TB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA100GB1TBCnt ());
+         allocStat->append (sb.toString ());
+       }
+      if (hDataTotal->getA1TB10TBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1TB - 10TB"));
+         allocStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getA1TB10TBCnt ());
+         allocStat->append (sb.toString ());
+       }
+
+      sb.sprintf (GTXT ("Smallest allocation bytes"));
+      allocStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getASmallestBytes ()));
+      allocStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Largest allocation bytes"));
+      allocStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getALargestBytes ()));
+      allocStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Total allocations"));
+      allocStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getAllocCnt ()));
+      allocStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Total bytes"));
+      allocStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%lld"), (long long) (hDataTotal->getAllocBytes ()));
+      allocStat->append (sb.toString ());
+    }
+
+  if (hDataTotal->getLeakCnt () > 0)
+    {
+      if (hDataTotal->getL0KB1KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("0KB - 1KB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL0KB1KBCnt ());
+         leakStat->append (sb.toString ());
+       }
+      if (hDataTotal->getL1KB8KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1KB - 8KB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL1KB8KBCnt ());
+         leakStat->append (sb.toString ());
+       }
+      if (hDataTotal->getL8KB32KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("8KB - 32KB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL8KB32KBCnt ());
+         leakStat->append (sb.toString ());
+       }
+      if (hDataTotal->getL32KB128KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("32KB - 128KB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL32KB128KBCnt ());
+         leakStat->append (sb.toString ());
+       }
+      if (hDataTotal->getL128KB256KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("128KB - 256KB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL128KB256KBCnt ());
+         leakStat->append (sb.toString ());
+       }
+      if (hDataTotal->getL256KB512KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("256KB - 512KB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL256KB512KBCnt ());
+         leakStat->append (sb.toString ());
+       }
+      if (hDataTotal->getL512KB1000KBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("512KB - 1000KB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL512KB1000KBCnt ());
+         leakStat->append (sb.toString ());
+       }
+      if (hDataTotal->getL1000KB10MBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1000KB - 10MB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL1000KB10MBCnt ());
+         leakStat->append (sb.toString ());
+       }
+      if (hDataTotal->getL10MB100MBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("10MB - 100MB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL10MB100MBCnt ());
+         leakStat->append (sb.toString ());
+       }
+      if (hDataTotal->getL100MB1GBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("100MB - 1GB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL100MB1GBCnt ());
+         leakStat->append (sb.toString ());
+       }
+      if (hDataTotal->getL1GB10GBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1GB - 10GB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL1GB10GBCnt ());
+         leakStat->append (sb.toString ());
+       }
+      if (hDataTotal->getL10GB100GBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("10GB - 100GB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL10GB100GBCnt ());
+         leakStat->append (sb.toString ());
+       }
+      if (hDataTotal->getL100GB1TBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("100GB - 1TB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL100GB1TBCnt ());
+         leakStat->append (sb.toString ());
+       }
+      if (hDataTotal->getL1TB10TBCnt () > 0)
+       {
+         sb.sprintf (GTXT ("1TB - 10TB"));
+         leakStat->append (sb.toString ());
+         sb.sprintf (NTXT ("%d"), hDataTotal->getL1TB10TBCnt ());
+         leakStat->append (sb.toString ());
+       }
+
+      sb.sprintf (GTXT ("Smallest leaked bytes"));
+      leakStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getLSmallestBytes ()));
+      leakStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Largest leaked bytes"));
+      leakStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getLLargestBytes ()));
+      leakStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Total leaked"));
+      leakStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%d"), (int) (hDataTotal->getLeakCnt ()));
+      leakStat->append (sb.toString ());
+
+      sb.sprintf (GTXT ("Total bytes"));
+      leakStat->append (sb.toString ());
+      sb.sprintf (NTXT ("%lld"), (long long) (hDataTotal->getLeakBytes ()));
+      leakStat->append (sb.toString ());
+    }
+  Vector<Vector<char*>*>* statisticsData = new Vector<Vector<char*>*>(3);
+  statisticsData->store (0, memoryUsage);
+  statisticsData->store (1, allocStat);
+  statisticsData->store (2, leakStat);
+  return statisticsData;
+}
+
+Vector<char*> *
+dbeGetFuncNames (int dbevindex, Vector<Obj> *funcs)
+{
+  int len = funcs->size ();
+  Vector<char*> *list = new Vector<char*>(len);
+  for (int i = 0; i < len; i++)
+    list->store (i, dbeGetFuncName (dbevindex, funcs->fetch (i))); // no strdup()
+  return list;
+}
+
+Vector<char*> *
+dbeGetObjNamesV2 (int dbevindex, Vector<uint64_t> *ids)
+{
+  int len = ids->size ();
+  Vector<char*> *list = new Vector<char*>(len);
+  for (int i = 0; i < len; i++)
+    list->store (i, dbeGetObjNameV2 (dbevindex, ids->fetch (i))); // no strdup()
+  return list;
+}
+
+char *
+dbeGetFuncName (int dbevindex, Obj func)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  if (func == 0)
+    return NULL;
+  char *fname;
+  fname = ((Histable *) func)->get_name (dbev->get_name_format ());
+  return fname ? dbe_strdup (fname) : NULL;
+}
+
+Vector<uint64_t> *
+dbeGetFuncIds (int dbevindex, Vector<Obj> *funcs)
+{
+  int len = funcs->size ();
+  Vector<uint64_t> *list = new Vector<uint64_t>(len);
+  for (int i = 0; i < len; i++)
+    list->store (i, dbeGetFuncId (dbevindex, funcs->fetch (i)));
+  return list;
+}
+
+uint64_t
+dbeGetFuncId (int dbevindex, Obj func)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  if (func == 0)
+    return 0;
+  uint64_t id = ((Histable *) func)->id;
+  return id;
+}
+
+char *
+dbeGetObjNameV2 (int dbevindex, uint64_t id)
+{
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Histable *obj = dbeSession->findObjectById (id);
+  if (obj == NULL)
+    return NULL;
+  char *fname = obj->get_name (dbev->get_name_format ());
+  return fname ? dbe_strdup (fname) : NULL;
+}
+
+char *
+dbeGetDataspaceTypeDesc (int /*dbevindex*/, Obj stack)
+{
+  if (stack == 0)
+    return NULL;
+  Histable *hist = CallStack::getStackPC ((void *) stack, 0);
+  DbeInstr *instr;
+  Histable::Type type = hist->get_type ();
+  if (type != Histable::INSTR)
+    return NULL;
+  else
+    instr = (DbeInstr *) hist;
+  char *descriptor = instr->get_descriptor ();
+  return descriptor ? dbe_strdup (descriptor) : NULL;
+}
+
+Vector<void*> *
+dbeGetDataDescriptorsV2 (int exp_id)
+{
+  Experiment *exp = dbeSession->get_exp (exp_id);
+  if (exp == NULL)
+    return NULL;
+  Vector<int> *dataId = new Vector<int>;
+  Vector<char*> *dataName = new Vector<char*>;
+  Vector<char*> *dataUName = new Vector<char*>;
+  Vector<int> *auxProp = new Vector<int>;
+  Vector<DataDescriptor*> *ddscr = exp->getDataDescriptors ();
+  for (int i = 0; i < ddscr->size (); i++)
+    {
+      DataDescriptor *dataDscr = ddscr->fetch (i);
+      if (dataDscr->getFlags () & DDFLAG_NOSHOW)
+       continue;
+      int data_id = dataDscr->getId ();
+      int aux_prop_id = (data_id == DATA_HWC) ? PROP_HWCTAG : PROP_NONE;
+      dataId->append (data_id);
+      dataName->append (strdup (dataDscr->getName ()));
+      dataUName->append (strdup (dataDscr->getUName ()));
+      auxProp->append (aux_prop_id);
+    }
+  delete ddscr;
+  Vector<void*> *res = new Vector<void*>(3);
+  res->store (0, dataId);
+  res->store (1, dataName);
+  res->store (2, dataUName);
+  res->store (3, auxProp);
+  return res;
+}
+
+Vector<void*> *
+dbeGetDataPropertiesV2 (int exp_id, int data_id)
+{
+  Experiment *exp = dbeSession->get_exp (exp_id);
+  if (exp == NULL)
+    return NULL;
+  DataDescriptor *dataDscr = exp->get_raw_events (data_id);
+  if (dataDscr == NULL)
+    return NULL;
+  Vector<PropDescr*> *props = dataDscr->getProps ();
+  Vector<int> *propId = new Vector<int>(props->size ());
+  Vector<char*> *propUName = new Vector<char*>(props->size ());
+  Vector<int> *propTypeId = new Vector<int>(props->size ());
+  Vector<char*> *propTypeName = new Vector<char*>(props->size ());
+  Vector<int> *propFlags = new Vector<int>(props->size ());
+  Vector<char*> *propName = new Vector<char*>(props->size ());
+  Vector<void*> *propStateNames = new Vector<void*>(props->size ());
+  Vector<void*> *propStateUNames = new Vector<void*>(props->size ());
+
+  for (int i = 0; i < props->size (); i++)
+    {
+      PropDescr *prop = props->fetch (i);
+      char *pname = prop->name;
+      if (pname == NULL)
+       pname = NTXT ("");
+      char *uname = prop->uname;
+      if (uname == NULL)
+       uname = pname;
+      int vtypeNum = prop->vtype;
+      if (vtypeNum < 0 || vtypeNum >= TYPE_LAST)
+       vtypeNum = TYPE_NONE;
+      const char * vtypeNames[] = VTYPE_TYPE_NAMES;
+      const char *vtype = vtypeNames[prop->vtype];
+      Vector<char*> *stateNames = NULL;
+      Vector<char*> *stateUNames = NULL;
+      int nStates = prop->getMaxState ();
+      if (nStates > 0)
+       {
+         stateNames = new Vector<char*>(nStates);
+         stateUNames = new Vector<char*>(nStates);
+         for (int kk = 0; kk < nStates; kk++)
+           {
+             const char * stateName = prop->getStateName (kk);
+             stateNames->store (kk, dbe_strdup (stateName));
+             const char * Uname = prop->getStateUName (kk);
+             stateUNames->store (kk, dbe_strdup (Uname));
+           }
+       }
+      propId->store (i, prop->propID);
+      propUName->store (i, dbe_strdup (uname));
+      propTypeId->store (i, prop->vtype);
+      propTypeName->store (i, dbe_strdup (vtype));
+      propFlags->store (i, prop->flags);
+      propName->store (i, dbe_strdup (pname));
+      propStateNames->store (i, stateNames);
+      propStateUNames->store (i, stateUNames);
+    }
+  Vector<void*> *res = new Vector<void*>(7);
+  res->store (0, propId);
+  res->store (1, propUName);
+  res->store (2, propTypeId);
+  res->store (3, propTypeName);
+  res->store (4, propFlags);
+  res->store (5, propName);
+  res->store (6, propStateNames);
+  res->store (7, propStateUNames);
+  return res;
+}
+
+Vector<void *> *
+dbeGetExperimentTimeInfo (Vector<int> *exp_ids)
+{
+  int sz = exp_ids->size ();
+  Vector<long long> *offset_time = new Vector<long long> (sz);
+  Vector<long long> *start_time = new Vector<long long> (sz);
+  Vector<long long> *end_time = new Vector<long long> (sz);
+  Vector<long long> *start_wall_sec = new Vector<long long> (sz);
+  Vector<char* > *hostname = new Vector<char*> (sz);
+  Vector<int> *cpu_freq = new Vector<int> (sz);
+  for (int ii = 0; ii < sz; ii++)
+    {
+      int expIdx = exp_ids->fetch (ii);
+      { // update end_time by forcing fetch of experiment data
+       // workaround until dbeGetEndTime() is more robust
+       int id = (expIdx < 0) ? 0 : expIdx;
+       Experiment *exp = dbeSession->get_exp (id);
+       if (exp)
+         {
+           Vector<DataDescriptor*> *ddscr = exp->getDataDescriptors ();
+           delete ddscr;
+         }
+      }
+      offset_time->store (ii, dbeGetRelativeStartTime (0, expIdx));
+      start_time->store (ii, dbeGetStartTime (0, expIdx));
+      end_time->store (ii, dbeGetEndTime (0, expIdx));
+      start_wall_sec->store (ii, dbeGetWallStartSec (0, expIdx));
+      hostname->store (ii, dbeGetHostname (0, expIdx));
+      cpu_freq->store (ii, dbeGetClock (0, expIdx));
+    }
+  Vector<void*> *res = new Vector<void*>(4);
+  res->store (0, offset_time);
+  res->store (1, start_time);
+  res->store (2, end_time);
+  res->store (3, start_wall_sec);
+  res->store (4, hostname);
+  res->store (5, cpu_freq);
+  return res;
+}
+
+Vector<void *> *
+dbeGetExperimentDataDescriptors (Vector<int> *exp_ids)
+{
+  int sz = exp_ids->size ();
+  Vector<void*> *exp_dscr_info = new Vector<void*> (sz);
+  Vector<void*> *exp_dscr_props = new Vector<void*> (sz);
+
+  for (int ii = 0; ii < sz; ii++)
+    {
+      int expIdx = exp_ids->fetch (ii);
+      Vector<void*> *ddscrInfo = dbeGetDataDescriptorsV2 (expIdx);
+      Vector<void*> *ddscrProps = new Vector<void*> (); // one entry per ddscrInfo
+      if (ddscrInfo)
+       {
+         Vector<int> *dataId = (Vector<int>*)ddscrInfo->fetch (0);
+         if (dataId)
+           {
+             // loop thru data descriptors
+             int ndata = dataId->size ();
+             for (int j = 0; j < ndata; ++j)
+               {
+                 Vector<void*> *props = dbeGetDataPropertiesV2 (expIdx, dataId->fetch (j));
+                 ddscrProps->store (j, props);
+               }
+           }
+       }
+      exp_dscr_info->store (ii, ddscrInfo);
+      exp_dscr_props->store (ii, ddscrProps);
+    }
+  Vector<void*> *res = new Vector<void*>(2);
+  res->store (0, exp_dscr_info);
+  res->store (1, exp_dscr_props);
+  return res;
+}
+
+static Vector<void *> *
+dbeGetTLDataRepVals (VMode view_mode, hrtime_t start_ts, hrtime_t delta,
+                    int numDeltas, DataView*packets,
+                    Vector<long> *representativeEvents, bool showDuration);
+
+static bool
+dbeHasTLData (int dbevindex, int exp_id, int data_id, int entity_prop_id,
+             int entity_prop_value, int aux)
+{
+  DataView *packets =
+         getTimelinePackets (dbevindex, exp_id, data_id, entity_prop_id);
+  if (!packets || packets->getSize () == 0)
+    return false;
+  long start_ind = getIdxByVals (packets, aux, entity_prop_value,
+                                0, DataView::REL_GTEQ); // time >= 0
+  if (start_ind < 0)
+    return false;
+
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  VMode view_mode = dbev->get_view_mode ();
+  Experiment *exp = dbeSession->get_exp (exp_id);
+  if (!hasInvisbleTLEvents (exp, view_mode))
+    return true; // all events are visible, no further checking required
+  long end_ind = getIdxByVals (packets, aux, entity_prop_value,
+                              MAX_TIME, DataView::REL_LTEQ);
+  for (long ii = start_ind; ii <= end_ind; ii++)
+    {
+      if (!isVisibleTLEvent (exp, view_mode, packets, ii))
+       continue;
+      return true; // first visible packet => has data
+    }
+  return false;
+}
+
+Vector<bool> *
+dbeHasTLData (int dbev_index, Vector<int> *exp_ids, Vector<int> *data_ids,
+             Vector<int> *entity_prop_ids, // LWP,CPU,THR, etc
+             Vector<int> *entity_prop_values, Vector<int> *auxs)
+{
+  DbeView *dbev = dbeSession->getView (dbev_index);
+  if (!dbev->isShowAll () && (dbev->isShowHideChanged ()
+                             || dbev->isNewViewMode ()))
+    {
+      // LIBRARY_VISIBILITY
+      dbev->resetAndConstructShowHideStacks ();
+      if (dbev->isNewViewMode ())
+       dbev->resetNewViewMode ();
+      if (dbev->isShowHideChanged ())
+       dbev->resetShowHideChanged ();
+    }
+
+  int sz = exp_ids->size ();
+  Vector<bool> *hasVec = new Vector<bool>(sz);
+  for (int ii = 0; ii < sz; ii++)
+    {
+      bool hasData = dbeHasTLData (dbev_index, exp_ids->fetch (ii),
+                                  data_ids->fetch (ii),
+                                  entity_prop_ids->fetch (ii),
+                                  entity_prop_values->fetch (ii),
+                                  auxs->fetch (ii));
+      hasVec->store (ii, hasData);
+    }
+  return hasVec;
+}
+
+/*
+ *   dbeGetTLData implements:
+ *   FROM data_id
+ *     DURATION >= delta AND ( start_ts <= TSTAMP < start_ts+num*delta OR
+ *                             start_ts <= TSTAMP-DURATION < start_ts+num*delta )
+ *     OR
+ *     FAIR( DURATION < delta AND ( start_ts <= TSTAMP < start_ts+num*delta ) )
+ *     WHERE lfilter
+ */
+
+Vector<void *> *
+dbeGetTLData (
+             int dbevindex,
+             int exp_id,
+             int data_id, // DATA_*
+             int entity_prop_id, // Show PROP_LWPID, PROP_CPUID, PROP_THRID, PROP_EXPID, or N/A
+             int entity_prop_value, // which LWPID, CPUID, THRID, EXPID for this request
+             int aux,
+             hrtime_t param_start_ts,
+             hrtime_t param_delta,
+             int param_numDeltas,
+             bool getRepresentatives, // fetch TL representatives
+             Vector<char *> *chartProps) // calculate sums for these property vals
+{
+  const hrtime_t start_ts = param_start_ts;
+  const hrtime_t delta = param_delta;
+  const int numDeltas = param_numDeltas;
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  if (dbev == NULL)
+    abort ();
+  Experiment *exp = dbeSession->get_exp (exp_id);
+  if (exp == NULL)
+    return NULL;
+  if (getRepresentatives == false && chartProps == NULL)
+    return NULL;
+  if (delta <= 0)
+    return NULL;
+
+  hrtime_t tmp_ts = start_ts + delta * numDeltas;
+  if (tmp_ts < start_ts)
+    tmp_ts = MAX_TIME;
+  const hrtime_t end_ts = tmp_ts;
+  if (exp->get_status () == Experiment::INCOMPLETE &&
+      exp->getLastEvent () < end_ts)
+    exp->update ();
+  DataView *packets =
+         getTimelinePackets (dbevindex, exp_id, data_id, entity_prop_id);
+  if (packets == NULL)
+    return NULL; // strange, no data view?
+
+  VMode view_mode = dbev->get_view_mode (); // user, expert, machine //YXXX yuck
+
+  // storage for calculating timeline representative events
+  Vector<long> *representativeEvents = NULL;
+  // list of representative events to be displayed on TL
+  Vector<int> *binRepIdx = NULL;
+  // for each bin, index    of current "best" representativeEvent
+  Vector<void*> *representativeVals = NULL;
+  // TL representative packets' values
+
+  // storage for calculating charts
+  Vector<int> *propIds = NULL; // [propIdx], which prop to measure
+  Vector<void*> *propVals = NULL; // [propIdx][bin], prop vals
+  Vector<int> *propNumStates = NULL; // [propIdx], how many states for prop?
+  Vector<bool> *propCumulativeChart = NULL; // [propIdx], data represents cumulative totals
+  Vector<long long> *propCumulativeRecentBinLastVal = NULL; // [propIdx], most recent value
+  Vector<long long> *propCumulativeRecentBinHighVal = NULL; // [propIdx], highest value for propCumulativeRecentBin
+  Vector<int> *propCumulativeRecentBin = NULL; // [propIdx], most recent bin
+
+  // determine when to show duration of events
+  bool tmp_repsShowDuration = false;
+  bool tmp_statesUseDuration = false;
+  bool tmp_extendMicrostates = false;
+  const hrtime_t ptimerTickDuration = exp->get_params ()->ptimer_usec * 1000LL; // nanoseconds per tick
+  const bool hasDuration = packets->getProp (PROP_EVT_TIME) ? true : false;
+  if (hasDuration)
+    {
+      switch (entity_prop_id)
+       {
+       case PROP_CPUID:
+         tmp_repsShowDuration = false;
+         tmp_statesUseDuration = false;
+         break;
+       case PROP_THRID:
+       case PROP_LWPID:
+         tmp_repsShowDuration = true;
+         tmp_statesUseDuration = true;
+         tmp_extendMicrostates = (DATA_CLOCK == data_id) && (ptimerTickDuration < param_delta);
+         break;
+       case PROP_EXPID:
+       case PROP_NONE: // experiment summary row uses this
+       default:
+         if (DATA_SAMPLE == data_id)
+           {
+             tmp_repsShowDuration = true;
+             tmp_statesUseDuration = true;
+           }
+         else if (DATA_GCEVENT == data_id)
+           {
+             tmp_repsShowDuration = true;
+             tmp_statesUseDuration = true;
+           }
+         else if (DATA_CLOCK == data_id)
+           {
+             tmp_repsShowDuration = false;
+             tmp_statesUseDuration = true;
+             tmp_extendMicrostates = true;
+           }
+         else
+           {
+             tmp_repsShowDuration = false;
+             tmp_statesUseDuration = true;
+           }
+         break;
+       }
+    }
+  const bool repsShowDuration = tmp_repsShowDuration; // show stretched callstacks
+  const bool statesUseDuration = tmp_statesUseDuration; // use duration to calculate state charts
+  const bool extendMicrostates = tmp_extendMicrostates; // we show discrete profiling microstates with
+  // width=(tick-1), but for computing
+  // zoomed-out graphs we need to extend to
+  // account for all ticks, width=(ntick)
+  const bool reverseScan = repsShowDuration || extendMicrostates; // scan packets in reverse
+
+  // determine range of packet indices (lo_pkt_idx, hi_pkt_idx)
+  long lo_pkt_idx, hi_pkt_idx;
+  if (extendMicrostates && !(entity_prop_id == PROP_THRID || entity_prop_id == PROP_LWPID))
+    {
+      // merging data from multiple threads, need to scan all packets with timestamp [start_ts, exp end]
+      hrtime_t exp_end_time = exp->getLastEvent () + 1;
+      hi_pkt_idx = getIdxByVals (packets, aux, entity_prop_value,
+                                exp_end_time, DataView::REL_LT); // last item
+    }
+  else
+    hi_pkt_idx = getIdxByVals (packets, aux, entity_prop_value,
+                              end_ts, DataView::REL_LT);
+  if (repsShowDuration)
+    {
+      // There are two issues to deal with
+      // 1. events that end "off screen" to the right
+      // 2. overlapping events
+
+      // 1. events that end "off screen" to the right
+      // For now, we only consistently handle the case where events don't overlap.
+      // Note that packet timestamps mark end of duration, not start.
+      // This means that the rightmost event won't be within hi_pkt_idx.
+      // Solution: Check if end+1 packet _started_ in-range
+      // Caveat: because we only look ahead by one packet, if there are
+      // overlapping duration events (e.g. EXPID aggregation)), zoom level
+      // and panning combo may cause events with TSTAMP>end_ts
+      // to appear/disappear.  A complete solution would involve
+      // a solution to 2.
+
+      // 2. overlapping events
+      // For now, we have a simplistic solution that makes "wide" events win.  However,
+      // a future solution for deterministically dealing with overlap might look like this:
+      // - find all packets that touch the visible time range
+      //   - possibly use two DataViews: one with TSTAMP_HI sort and one with TSTAMP_LO
+      //     sort to allow efficient determination of packets with HI and LO endpoints in-range
+      // - create buckets to  capture "winning" event for each bin (each pixel, that is)
+      // - sort the new list of packets by TSTAMP_HI (for example)
+      // - looping thru the packets that are in-range, update every bin it touches with it's id
+      // - if there is overlap, earlier packets will be kicked out of bins
+      // - On the GUI side, paint one event at a time, as normal.
+      // - However, for selections, recognize that duration of event may span many bins
+      //
+      long idx;
+      if (hi_pkt_idx >= 0)
+       // a packet was found to the left of the end time
+       idx = hi_pkt_idx + 1; // attempt to go one packet right
+      else
+       idx = getIdxByVals (packets, aux, entity_prop_value,
+                           end_ts, DataView::REL_GTEQ);
+      if (isValidIdx (packets, entity_prop_id, aux, entity_prop_value, idx))
+       {
+         int64_t pkt_ts = packets->getLongValue (PROP_TSTAMP, idx);
+         int64_t duration = packets->getLongValue (PROP_EVT_TIME, idx);
+         pkt_ts -= duration;
+         if (pkt_ts < end_ts)
+           hi_pkt_idx = idx;
+       }
+    }
+  lo_pkt_idx = getIdxByVals (packets, aux, entity_prop_value,
+                            start_ts, DataView::REL_GTEQ);
+
+  // allocate structs that return chart data
+  bool hasCumulativeCharts = false;
+  if (chartProps && chartProps->size () > 0)
+    {
+      int nprops = chartProps->size ();
+      // pre-allocate storage
+      propIds = new Vector<int> (nprops);
+      propVals = new Vector<void*>(nprops);
+      propNumStates = new Vector<int> (nprops);
+      propCumulativeChart = new Vector<bool>(nprops);
+      propCumulativeRecentBinLastVal = new Vector<long long>(nprops);
+      propCumulativeRecentBinHighVal = new Vector<long long>(nprops);
+      propCumulativeRecentBin = new Vector<int>(nprops);
+      for (int propNum = 0; propNum < nprops; propNum++)
+       {
+         const char* propStr = chartProps->fetch (propNum);
+         int items_per_prop = 0;
+         int prop_id = PROP_NONE;
+         if (!strcmp (propStr, "EVT_COUNT"))
+           items_per_prop = 1; // use PROP_NONE for counting packets
+         else
+           {
+             int lookup_prop_id = dbeSession->getPropIdByName (propStr);
+             PropDescr *propDscr = packets->getProp (lookup_prop_id);
+             if (propDscr != NULL)
+               {
+                 switch (propDscr->vtype)
+                   {
+                   case TYPE_INT32:
+                   case TYPE_UINT32:
+                   case TYPE_INT64:
+                   case TYPE_UINT64:
+                     items_per_prop = propDscr->getMaxState () + 1;
+                     // add extra slot to store values with out-of-range idx
+                     prop_id = lookup_prop_id;
+                     break;
+                   case TYPE_DOUBLE:
+                     break; // not implemented yet
+                   case TYPE_STRING:
+                   case TYPE_OBJ:
+                   case TYPE_DATE:
+                   default:
+                     break;
+                   }
+               }
+           }
+         void *vals;
+         if (!items_per_prop)
+           vals = NULL;
+         else if (items_per_prop == 1)
+           {
+             Vector<long long> *longVals = new Vector<long long> ();
+             longVals->store (numDeltas - 1, 0); // initialize all elements
+             vals = longVals;
+           }
+         else
+           {
+             Vector<Vector<long long>*> *stateVals =
+                     new Vector<Vector<long long>*> ();
+             vals = stateVals;
+             // initialize only on-demand, some may not be needed
+           }
+
+         bool isCumulativeChart;
+#define YXXX_HEAP_VS_TIME 1 // YXXX add data meaning to properties?
+#if YXXX_HEAP_VS_TIME
+         isCumulativeChart = (prop_id == PROP_HCUR_LEAKS || prop_id == PROP_HCUR_ALLOCS);
+#endif
+         if (isCumulativeChart)
+           hasCumulativeCharts = true;
+         propIds->store (propNum, prop_id);
+         propVals->store (propNum, vals);
+         propNumStates->store (propNum, items_per_prop);
+         propCumulativeRecentBinLastVal->store (propNum, 0);
+         propCumulativeRecentBinHighVal->store (propNum, 0);
+         propCumulativeRecentBin->store (propNum, 0);
+         propCumulativeChart->store (propNum, isCumulativeChart);
+       }
+    }
+
+  // Adjust idx range for calculating 'cumulative charts' e.g. heap size
+  if (hasCumulativeCharts)
+    {
+      // set initial values if earlier packet exists
+      long lo_idx;
+      if (lo_pkt_idx >= 0)
+       // packet was found to the right of start
+       lo_idx = lo_pkt_idx - 1; // attempt to go left by one event
+      else
+       // no packet was to the right of start, look left of start
+       lo_idx = getIdxByVals (packets, aux, entity_prop_value,
+                              start_ts, DataView::REL_LT);
+      if (isValidIdx (packets, entity_prop_id, aux, entity_prop_value, lo_idx))
+       {
+         // preceding packet found
+         // update initial values
+         int nprops = propCumulativeChart->size ();
+         for (int propNum = 0; propNum < nprops; propNum++)
+           {
+             if (!propCumulativeChart->fetch (propNum))
+               continue;
+             int propId = propIds->fetch (propNum);
+             long long value = packets->getLongValue (propId, lo_idx);
+             propCumulativeRecentBinLastVal->store (propNum, value);
+             propCumulativeRecentBinHighVal->store (propNum, value);
+           }
+         // update indices used for iterating
+         lo_pkt_idx = lo_idx;
+         if (hi_pkt_idx < lo_pkt_idx)
+           hi_pkt_idx = lo_pkt_idx;
+       }
+    }
+  if (lo_pkt_idx < 0 || hi_pkt_idx < 0)
+    goto dbeGetTLData_done; // no data; return empty vectors, not null
+
+  // representative events (subset of callstacks to represent on TL)
+  if (getRepresentatives)
+    {
+      representativeEvents = new Vector<long>(numDeltas);
+      // per-bin, longest event's index
+      binRepIdx = new Vector<int>(numDeltas);
+      for (int ii = 0; ii < numDeltas; ++ii)
+       binRepIdx->append (-1);
+    }
+  // While packets are sorted by _end_ timestamp (TSTAMP),
+  // after calculating start times for non-zero durations,
+  // start times are not guaranteed be monotonically increasing.
+  // For packets with duration, we'll scan them in reverse order to
+  // take advantage of the monotonically decreasing _end_ timestamps.
+  long start_idx, idx_inc;
+  if (!reverseScan)
+    {
+      start_idx = lo_pkt_idx;
+      idx_inc = 1;
+    }
+  else
+    {
+      start_idx = hi_pkt_idx;
+      idx_inc = -1;
+    }
+  for (long ii = start_idx; ii >= lo_pkt_idx && ii <= hi_pkt_idx; ii += idx_inc)
+    {
+      if (!isVisibleTLEvent (exp, view_mode, packets, ii) && !hasCumulativeCharts)
+       continue;
+
+      // determine packet time duration and start bin
+      int tmp_start_bin; // packet start bin
+      int tmp_end_bin; // packet end bin (inclusive)
+      const hrtime_t pkt_end_ts = packets->getLongValue (PROP_TSTAMP, ii);
+      const hrtime_t pkt_dur = packets->getLongValue (PROP_EVT_TIME, ii);
+      const hrtime_t pkt_start_ts = pkt_end_ts - pkt_dur;
+      if (pkt_end_ts < start_ts && !hasCumulativeCharts)
+       continue; // weird, should not happen
+      if (pkt_start_ts >= end_ts)
+       continue; // could happen
+      hrtime_t bin_end_ts = pkt_end_ts;
+      if (bin_end_ts >= end_ts)
+       bin_end_ts = end_ts - 1;
+      tmp_end_bin = (int) ((bin_end_ts - start_ts) / delta);
+      hrtime_t bin_start_ts = pkt_start_ts;
+      if (bin_start_ts < start_ts)
+       bin_start_ts = start_ts; // event truncated to left.
+      tmp_start_bin = (int) ((bin_start_ts - start_ts) / delta);
+      // By definition
+      //   (end_ts - start_ts) == delta * numDeltas
+      // and we know
+      //   pkt_start < end_ts
+      // therefore
+      //   (pkt_start - start_ts) < delta * numDeltas
+      //   (pkt_start - start_ts) / delta < numDeltas
+      //   bin < numDeltas
+      assert (tmp_end_bin < numDeltas);
+      assert (tmp_start_bin < numDeltas);
+      const bool is_offscreen = tmp_end_bin < 0 ? true : false;
+      if (tmp_end_bin < 0)
+       tmp_end_bin = 0;
+      const int pkt_end_bin = tmp_end_bin; // packet end bin (inclusive)
+      const int pkt_start_bin = tmp_start_bin;
+      if (getRepresentatives && !is_offscreen)
+       { // find best representative
+         // Note: for events with duration, we're scanning packets in order
+         // of decreasing end-timestamp.  This means that the first packet
+         // that hits a particular _start_ bin will have the longest duration
+         // of any later packet that might hit that start bin.  The
+         // the first packet will be the best (longest) packet.
+         const int bin = reverseScan ? pkt_start_bin : pkt_end_bin;
+         int eventIdx = binRepIdx->fetch (bin);
+         if (eventIdx == -1)
+           {
+             eventIdx = representativeEvents->size (); // append to end
+             representativeEvents->append (ii);
+             binRepIdx->store (bin, eventIdx);
+           }
+       }
+      if (propIds)
+       { // per-bin chart: sum across filtered packets
+         for (int propNum = 0; propNum < propIds->size (); propNum++)
+           {
+             void *thisProp = propVals->fetch (propNum);
+             if (thisProp == NULL)
+               continue; // no valid data
+             if (is_offscreen && !propCumulativeChart->fetch (propNum))
+               continue; // offscreen events are only processed for cumulative charts
+             int propId = propIds->fetch (propNum);
+             long long val;
+             if (propId == PROP_NONE)
+               val = 1; // count
+             else
+               val = packets->getLongValue (propId, ii);
+             long nitems = propNumStates->fetch (propNum);
+             if (nitems < 1)
+               continue;
+             else if (nitems == 1)
+               {
+                 // chart is not based on not multiple states
+                 Vector<long long>* thisPropVals =
+                         (Vector<long long>*)thisProp;
+                 if (thisPropVals->size () == 0)
+                   thisPropVals->store (numDeltas - 1, 0);
+                 const int bin = statesUseDuration ? pkt_start_bin : pkt_end_bin;
+                 if (!propCumulativeChart->fetch (propNum))
+                   {
+                     val += thisPropVals->fetch (bin);
+                     thisPropVals->store (bin, val);
+                   }
+                 else
+                   {
+                     // propCumulativeChart
+                     long long high_value = propCumulativeRecentBinHighVal->fetch (propNum);
+                     int last_bin = propCumulativeRecentBin->fetch (propNum);
+                     if (last_bin < bin)
+                       {
+                         // backfill from previous event
+                         // last_bin: store largest value (in case of multiple events)
+                         thisPropVals->store (last_bin, high_value);
+                         // propagate forward the bin's last value
+                         long long last_value = propCumulativeRecentBinLastVal->fetch (propNum);
+                         for (int kk = last_bin + 1; kk < bin; kk++)
+                           thisPropVals->store (kk, last_value);
+                         // prepare new bin for current event
+                         high_value = 0; // high value of next bin is 0.
+                         propCumulativeRecentBinHighVal->store (propNum, high_value);
+                         propCumulativeRecentBin->store (propNum, bin);
+                       }
+                     long long this_value = packets->getLongValue (propId, ii);
+                     propCumulativeRecentBinLastVal->store (propNum, this_value);
+                     if (high_value < this_value)
+                       {
+                         // record the max
+                         high_value = this_value;
+                         propCumulativeRecentBinHighVal->store (propNum, high_value);
+                       }
+                     if (ii == hi_pkt_idx)
+                       {
+                         // bin: show largest value (in case of multiple events
+                         thisPropVals->store (bin, high_value);
+                         //forward fill remaining bins
+                         for (int kk = bin + 1; kk < numDeltas; kk++)
+                           thisPropVals->store (kk, this_value);
+                       }
+                   }
+               }
+             else
+               {
+                 // means val is actually a state #
+                 Vector<Vector<long long>*>* thisPropStateVals =
+                         (Vector<Vector<long long>*>*)thisProp;
+                 if (thisPropStateVals->size () == 0)
+                   thisPropStateVals->store (numDeltas - 1, 0);
+                 long stateNum;
+                 if (val >= 0 && val < nitems)
+                   stateNum = (long) val;
+                 else
+                   stateNum = nitems - 1; // out of range, use last slot
+                 hrtime_t graph_pkt_dur = pkt_dur;
+                 hrtime_t graph_pkt_start_ts = pkt_start_ts;
+                 int tmp2_start_bin = pkt_start_bin;
+                 if (propId == PROP_MSTATE)
+                   {
+                     if (statesUseDuration && extendMicrostates)
+                       {
+                         // microstate stacks are shown and filtered with width=NTICK-1
+                         // but for microstate graph calcs use width=NTICK.
+                         graph_pkt_dur += ptimerTickDuration;
+                         graph_pkt_start_ts -= ptimerTickDuration;
+                         hrtime_t bin_start_ts = graph_pkt_start_ts;
+                         if (bin_start_ts < start_ts)
+                           bin_start_ts = start_ts; // event truncated to left.
+                         tmp2_start_bin = (int) ((bin_start_ts - start_ts) / delta);
+                       }
+                   }
+                 const int graph_pkt_start_bin = statesUseDuration ? tmp2_start_bin : pkt_end_bin;
+
+                 // We will distribute the state's presence evenly over duration of the event.
+                 // When only a 'partial bin' is touched by an event, adjust accordingly.
+                 long long value_per_bin; // weight to be applied to each bin
+                 {
+                   long long weight;
+                   if (propId == PROP_MSTATE)  // ticks to nanoseconds
+                     weight = packets->getLongValue (PROP_NTICK, ii) * ptimerTickDuration;
+                   else if (graph_pkt_dur)
+                     weight = graph_pkt_dur; // nanoseconds
+                   else
+                     weight = 1; // no duration; indicate presence
+                   if (graph_pkt_start_bin != pkt_end_bin)
+                     {
+                       // spans multiple bins
+                       double nbins = (double) graph_pkt_dur / delta;
+                       value_per_bin = weight / nbins;
+                     }
+                   else
+                     value_per_bin = weight;
+                 }
+                 for (int evtbin = graph_pkt_start_bin; evtbin <= pkt_end_bin; evtbin++)
+                   {
+                     Vector<long long>* stateValues =
+                             (Vector<long long>*) thisPropStateVals->fetch (evtbin);
+                     if (stateValues == NULL)
+                       {
+                         // on-demand storage
+                         stateValues = new Vector<long long>(nitems);
+                         stateValues->store (nitems - 1, 0); // force memset of full vector
+                         thisPropStateVals->store (evtbin, stateValues);
+                       }
+                     long long new_val = stateValues->fetch (stateNum);
+                     if (graph_pkt_start_bin == pkt_end_bin ||
+                         (evtbin > graph_pkt_start_bin && evtbin < pkt_end_bin))
+                       {
+                         new_val += value_per_bin;
+                       }
+                     else
+                       {
+                         // partial bin
+                         const hrtime_t bin_start = start_ts + evtbin * delta;
+                         const hrtime_t bin_end = start_ts + (evtbin + 1) * delta - 1;
+                         if (evtbin == graph_pkt_start_bin)
+                           {
+                             // leftmost bin
+                             if (graph_pkt_start_ts < bin_start)
+                               new_val += value_per_bin;
+                             else
+                               {
+                                 double percent = (double) (bin_end - graph_pkt_start_ts) / delta;
+                                 new_val += value_per_bin*percent;
+                               }
+                           }
+                         else
+                           {
+                             // rightmost bin
+                             if (pkt_end_ts > bin_end)
+                               new_val += value_per_bin;
+                             else
+                               {
+                                 double percent = (double) (pkt_end_ts - bin_start) / delta;
+                                 new_val += value_per_bin*percent;
+                               }
+                           }
+                       }
+                     stateValues->store (stateNum, new_val);
+                   }
+               }
+           }
+       }
+    }
+  delete binRepIdx;
+  delete propIds;
+  delete propCumulativeChart;
+  delete propCumulativeRecentBinLastVal;
+  delete propCumulativeRecentBinHighVal;
+  delete propCumulativeRecentBin;
+  if (representativeEvents != NULL && reverseScan)
+    {
+      if (repsShowDuration)
+       {
+         //YXXX for now prune here, but in the future, let gui decide what to show
+         // Prune events that are completely obscured long duration events.
+         // Note: representativeEvents is sorted by decreasing _end_ timestamps.
+         Vector<long> *prunedEvents = new Vector<long>(numDeltas);
+         hrtime_t prev_start_ts = MAX_TIME;
+         long repCnt = representativeEvents->size ();
+         for (long kk = 0; kk < repCnt; kk++)
+           {
+             long ii = representativeEvents->fetch (kk);
+             hrtime_t tmp_end_ts = packets->getLongValue (PROP_TSTAMP, ii);
+             hrtime_t tmp_dur = packets->getLongValue (PROP_EVT_TIME, ii);
+             hrtime_t tmp_start_ts = tmp_end_ts - tmp_dur;
+             if (tmp_start_ts >= prev_start_ts)
+               // this event would be completely hidden
+               // (because of sorting, we know tmp_end_ts <= prev_end_ts)
+               continue;
+             prev_start_ts = tmp_start_ts;
+             prunedEvents->append (ii);
+           }
+         // invert order to to get increasing _end_ timestamps
+         representativeEvents->reset ();
+         for (long kk = prunedEvents->size () - 1; kk >= 0; kk--)
+           {
+             long packet_idx = prunedEvents->fetch (kk);
+             representativeEvents->append (packet_idx);
+           }
+         delete prunedEvents;
+       }
+      else
+       { // !repsShowDuration
+         // Note: representativeEvents is sorted by decreasing _end_ timestamps.
+         // Reverse the order:
+         long hi_idx = representativeEvents->size () - 1;
+         long lo_idx = 0;
+         while (hi_idx > lo_idx)
+           {
+             // swap
+             long lo = representativeEvents->fetch (lo_idx);
+             long hi = representativeEvents->fetch (hi_idx);
+             representativeEvents->store (lo_idx, hi);
+             representativeEvents->store (hi_idx, lo);
+             hi_idx--;
+             lo_idx++;
+           }
+       }
+    }
+
+dbeGetTLData_done:
+  if (getRepresentatives)
+    {
+      representativeVals = dbeGetTLDataRepVals (view_mode, start_ts, delta,
+                   numDeltas, packets, representativeEvents, repsShowDuration);
+      delete representativeEvents;
+    }
+  Vector<void*> *results = new Vector<void*> (2);
+  results->store (0, representativeVals);
+  results->store (1, propVals);
+  return results;
+}
+
+// add representative events to return buffer
+
+static Vector<void *> *
+dbeGetTLDataRepVals (VMode view_mode, hrtime_t start_ts, hrtime_t delta,
+                    int numDeltas, DataView*packets,
+                    Vector<long> *representativeEvents, bool showDuration)
+{
+  int numrecs = representativeEvents ? representativeEvents->size () : 0;
+  // allocate storage for results
+  Vector<int> *startBins = new Vector<int>(numrecs);
+  Vector<int> *numBins = new Vector<int>(numrecs);
+  Vector<Obj> *eventIdxs = new Vector<Obj>(numrecs);
+  Vector<Obj> *stackIds = NULL;
+  if (packets->getProp (PROP_FRINFO))
+    stackIds = new Vector<Obj>(numrecs);
+  Vector<int> *mstates = NULL;
+  if (packets->getProp (PROP_MSTATE))
+    mstates = new Vector<int>(numrecs);
+  Vector<Vector<long long>*> *sampleVals = NULL;
+  if (packets->getProp (PROP_SMPLOBJ))
+    sampleVals = new Vector<Vector<long long>*>(numrecs);
+  Vector<long long> *timeStart = new Vector<long long>(numrecs);
+  Vector<long long> *timeEnd = new Vector<long long>(numrecs);
+  int prevEndBin = -1; // make sure we don't overlap bins
+  for (int eventIdx = 0; eventIdx < numrecs; eventIdx++)
+    {
+      long packetIdx = representativeEvents->fetch (eventIdx);
+      // long eventId = packets->getIdByIdx( packetIdx );
+      const hrtime_t pkt_tstamp = packets->getLongValue (PROP_TSTAMP, packetIdx);
+      const hrtime_t pkt_dur = showDuration ? packets->getLongValue (PROP_EVT_TIME, packetIdx) : 0;
+      timeStart->store (eventIdx, pkt_tstamp - pkt_dur);
+      timeEnd->store (eventIdx, pkt_tstamp);
+
+      // calc startBin
+      int startBin = (int) ((pkt_tstamp - pkt_dur - start_ts) / delta);
+      if (startBin <= prevEndBin)
+       startBin = prevEndBin + 1;
+      // calc binCnt
+      int endBin = (int) ((pkt_tstamp - start_ts) / delta);
+      if (endBin >= numDeltas)
+       endBin = numDeltas - 1;
+      int binCnt = endBin - startBin + 1;
+      prevEndBin = endBin;
+      startBins->store (eventIdx, startBin);
+      numBins->store (eventIdx, binCnt);
+      eventIdxs->store (eventIdx, packetIdx); // store packet's idx
+      if (stackIds != NULL)
+       {
+         void* stackId = getStack (view_mode, packets, packetIdx);
+         stackIds->store (eventIdx, (Obj) (unsigned long) stackId);
+       }
+      if (mstates != NULL)
+       {
+         int mstate = packets->getIntValue (PROP_MSTATE, packetIdx);
+         mstates->store (eventIdx, mstate);
+       }
+      if (sampleVals != NULL)
+       {
+         Sample* sample = (Sample*) packets->getObjValue (PROP_SMPLOBJ, packetIdx);
+         if (!sample || !sample->get_usage ())
+           sample = sample;
+         else
+           {
+             PrUsage* prusage = sample->get_usage ();
+             Vector<long long> *mstateVals = prusage->getMstateValues ();
+             sampleVals->store (eventIdx, mstateVals);
+           }
+       }
+    }
+  // caller responsible for: delete representativeEvents;
+  Vector<void*> *results = new Vector<void*> (8);
+  results->store (0, startBins);
+  results->store (1, numBins);
+  results->store (2, eventIdxs);
+  results->store (3, stackIds);
+  results->store (4, mstates);
+  results->store (5, sampleVals);
+  results->store (6, timeStart);
+  results->store (7, timeEnd);
+  return results;
+}
+
+// starting from <event_id> packet idx, step <move_count> visible events
+// return the resulting idx and that packet's center time, or null if no event.
+Vector<long long> *
+dbeGetTLEventCenterTime (int dbevindex, int exp_id, int data_id,
+                        int entity_prop_id, int entity_prop_val, int aux,
+                        long long event_id, long long move_count)
+{
+  DataView *packets = getTimelinePackets (dbevindex, exp_id, data_id,
+                                         entity_prop_id);
+  if (packets == NULL)
+    return NULL;
+  long idx = (long) event_id;
+
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  VMode view_mode = dbev->get_view_mode ();
+  Experiment *exp = dbeSession->get_exp (exp_id);
+  int direction;
+  if (move_count == 0)
+    direction = 0;
+  else if (move_count < 0)
+    {
+      move_count = -move_count;
+      direction = -1;
+    }
+  else
+    direction = 1;
+  idx = getTLVisibleIdxByStepping (exp, view_mode, entity_prop_id, packets, aux,
+                                  entity_prop_val, idx, move_count, direction);
+  if (idx >= 0)
+    {
+      long long ts = packets->getLongValue (PROP_TSTAMP, idx);
+      long long dur = packets->getLongValue (PROP_EVT_TIME, idx);
+      long long center = ts - dur / 2;
+      Vector<long long> *results = new Vector<long long> (2);
+      results->store (0, idx); // result idx
+      results->store (1, center); // result timestamp
+      return results;
+    }
+  return NULL;
+}
+
+long long
+dbeGetTLEventIdxNearTime (int dbevindex, int exp_id, int data_id,
+                         int entity_prop_id, int entity_prop_val, int aux,
+                         int searchDirection, long long tstamp)
+{
+  DataView *packets = getTimelinePackets (dbevindex, exp_id, data_id,
+                                         entity_prop_id);
+  if (packets == NULL)
+    return -1;
+  DbeView *dbev = dbeSession->getView (dbevindex);
+  VMode view_mode = dbev->get_view_mode ();
+  Experiment *exp = dbeSession->get_exp (exp_id);
+  if (searchDirection < 0)
+    {
+      int idx = getTLVisibleIdxByVals (exp, view_mode, entity_prop_id,
+                                      packets, aux, entity_prop_val, tstamp,
+                                      DataView::REL_LTEQ);
+      if (idx != -1)
+       return idx;
+      searchDirection = 1; // couldn't find to left, try to right
+    }
+  if (searchDirection > 0)
+    {
+      int idx = getTLVisibleIdxByVals (exp, view_mode, entity_prop_id,
+                                      packets, aux, entity_prop_val, tstamp,
+                                      DataView::REL_GTEQ);
+      if (idx != -1)
+       return idx;
+      // couldn't find to right, fall through to generic
+    }
+  // search left and right of timestamp
+  long idx1, idx2;
+  idx1 = getTLVisibleIdxByVals (exp, view_mode, entity_prop_id,
+                               packets, aux, entity_prop_val, tstamp,
+                               DataView::REL_LT);
+  idx2 = getTLVisibleIdxByVals (exp, view_mode, entity_prop_id,
+                               packets, aux, entity_prop_val, tstamp,
+                               DataView::REL_GTEQ);
+  if (idx1 == -1)
+    return idx2;
+  else if (idx2 == -1)
+    return idx1;
+
+  // both valid, so need to compare to see which is closer
+  long long t1 = packets->getLongValue (PROP_TSTAMP, idx1);
+  long long t2 = packets->getLongValue (PROP_TSTAMP, idx2);
+  long long t2dur = packets->getLongValue (PROP_EVT_TIME, idx2);
+  long long delta1 = tstamp - t1; // should always be positive
+  long long delta2 = (t2 - t2dur) - tstamp; // if negative, overlaps idx1
+  if (delta1 > delta2)
+    return idx2;
+  else
+    return idx1;
+}
+
+enum Aggr_type
+{
+  AGGR_NONE,
+  AGGR_FAIR,
+  AGGR_MAX,
+  AGGR_MIN,
+  AGGR_CNT,
+  AGGR_SUM,
+  AGGR_AVG
+};
+
+static Aggr_type
+getAggrFunc (char *aname)
+{
+  Aggr_type agrfn = AGGR_NONE;
+  if (aname == NULL)
+    return agrfn;
+  if (strcmp (aname, NTXT ("FAIR")) == 0)
+    agrfn = AGGR_FAIR;
+  else if (strcmp (aname, NTXT ("MAX")) == 0)
+    agrfn = AGGR_MAX;
+  else if (strcmp (aname, NTXT ("MIN")) == 0)
+    agrfn = AGGR_MIN;
+  else if (strcmp (aname, NTXT ("CNT")) == 0)
+    agrfn = AGGR_CNT;
+  else if (strcmp (aname, NTXT ("SUM")) == 0)
+    agrfn = AGGR_SUM;
+  else if (strcmp (aname, NTXT ("AVG")) == 0)
+    agrfn = AGGR_AVG;
+  return agrfn;
+}
+
+static long long
+computeAggrVal (DefaultMap<long long, long long> *fval_map, Aggr_type agrfn)
+{
+  long long aval = 0;
+  long cnt = 0;
+  Vector<long long> *fvals = fval_map->values ();
+  long nvals = fvals->size ();
+  for (int i = 0; i < nvals; ++i)
+    {
+      long long val = fvals->fetch (i);
+      switch (agrfn)
+       {
+       case AGGR_FAIR:
+         aval = val;
+         break;
+       case AGGR_MAX:
+         if (aval < val || cnt == 0)
+           aval = val;
+         break;
+       case AGGR_MIN:
+         if (aval > val || cnt == 0)
+           aval = val;
+         break;
+       case AGGR_CNT:
+         aval = cnt + 1;
+         break;
+       case AGGR_SUM:
+       case AGGR_AVG:
+         aval += val;
+         break;
+       case AGGR_NONE:
+         break;
+       }
+      if (agrfn == AGGR_FAIR)
+       break;
+      cnt += 1;
+    }
+
+  // Finalize aggregation
+  if (agrfn == AGGR_AVG)
+    if (cnt > 0)
+      aval = (aval + cnt / 2) / cnt;
+  delete fvals;
+  return aval;
+}
+
+Vector<long long> *
+dbeGetAggregatedValue (int data_id, // data table id
+                      char *lfilter, // local filter
+                      char *fexpr, // function expression
+                      char *pname_ts, // property name for timestamp
+                      hrtime_t start_ts, // start of the first time interval
+                      hrtime_t delta, // time interval length
+                      int num, // number of time intervals
+                      char *pname_key, // property name for aggregation key
+                      char *aggr_func) // aggregation function
+{
+  Vector<long long> *res = new Vector<long long>;
+  Experiment *exp = dbeSession->get_exp (0);
+  if (exp == NULL)
+    return res;
+  hrtime_t end_ts = start_ts + delta * num;
+  if (end_ts < start_ts)    // check overflow
+    end_ts = MAX_TIME;
+
+  if (exp->get_status () == Experiment::INCOMPLETE
+      && exp->getLastEvent () < end_ts)
+    exp->update ();
+
+  DataDescriptor *dataDscr = exp->get_raw_events (data_id);
+  if (dataDscr == NULL)
+    return res;
+
+  // Process timestamp argument
+  int prop_ts = dbeSession->getPropIdByName (pname_ts);
+  if (prop_ts == PROP_NONE)
+    return res;
+  assert (prop_ts == -1);
+
+  // Parse all expressions
+  Expression *flt_expr = NULL;
+  if (lfilter != NULL)
+    flt_expr = dbeSession->ql_parse (lfilter);
+  Expression *func_expr = NULL;
+  if (fexpr != NULL)
+    func_expr = dbeSession->ql_parse (fexpr);
+  if (func_expr == NULL)   // Not specified or malformed
+    return res;
+
+  // Process aggregation key argument
+  int prop_key = PROP_NONE;
+  Data *data_key = NULL;
+  if (pname_key != NULL)
+    {
+      prop_key = dbeSession->getPropIdByName (pname_key);
+      data_key = dataDscr->getData (prop_key);
+      if (data_key == NULL)   // Specified but not found
+       return res;
+    }
+
+  // Process aggregation function argument
+  Aggr_type agrfn = AGGR_FAIR;
+  if (aggr_func != NULL)
+    {
+      agrfn = getAggrFunc (aggr_func);
+      if (agrfn == AGGR_NONE) // Specified but not recognized
+       return res;
+    }
+  DefaultMap<long long, long long> *
+       fval_map = new DefaultMap<long long, long long>; // key_val -> func_val
+  Vector<long long> *key_set = NULL;
+  assert (key_set != NULL);
+  if (key_set == NULL)
+    {
+      key_set = new Vector<long long>;
+      key_set->append (0L);
+    }
+  DefaultMap<long long, int> *key_seen = new DefaultMap<long long, int>;
+  long idx_prev = -1;
+  for (int tidx = 0; tidx < num; ++tidx)
+    {
+      long idx_cur = -1;
+      assert (idx_cur != -1);
+      int left = key_set->size ();
+      key_seen->clear ();
+      for (long idx = idx_cur; idx > idx_prev; --idx)
+       {
+         long id = 0;
+         assert (id != 0);
+
+         // Pre-create expression context
+         Expression::Context ctx (dbeSession->getView (0), exp, NULL, id);
+         // First use the filter
+         if (flt_expr != NULL)
+           if (flt_expr->eval (&ctx) == 0)
+             continue;
+
+         // Calculate the key
+         // keys are limited to integral values
+         long long key = 0;
+         if (data_key != NULL)
+           key = data_key->fetchLong (id);
+
+         // Check if already seen
+         if (key_seen->get (key) == 1)
+           continue;
+         key_seen->put (key, 1);
+         left -= 1;
+
+         // Calculate function value
+         // function values are limited to integral values
+         long long fval = func_expr->eval (&ctx);
+         fval_map->put (key, fval);
+         if (left == 0)
+           break;
+       }
+      idx_prev = idx_cur;
+      long long aval = computeAggrVal (fval_map, agrfn);
+      res->store (tidx, aval);
+    }
+  delete key_seen;
+  delete fval_map;
+  delete flt_expr;
+  delete func_expr;
+  return res;
+}
+
+Vector<char*> *
+dbeGetLineInfo (Obj pc)
+{
+  DbeInstr *instr = (DbeInstr*) pc;
+  if (instr == NULL || instr->get_type () != Histable::INSTR)
+    return NULL;
+  DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE);
+  const char *fname = dbeline ? dbeline->sourceFile->get_name () : NTXT ("");
+  char lineno[16];
+  *lineno = '\0';
+  if (dbeline != NULL)
+    snprintf (lineno, sizeof (lineno), NTXT ("%d"), dbeline->lineno);
+  Vector<char*> *res = new Vector<char*>(2);
+  res->store (0, strdup (fname));
+  res->store (1, strdup (lineno));
+  return res;
+}
+
+int
+dbeSetAlias (char *name, char *uname, char *expr)
+{
+  char *res = dbeSession->indxobj_define (name, uname, expr, NULL, NULL);
+  return res == NULL ? 0 : 1;
+}
+
+Vector<char*> *
+dbeGetAlias (char *name)
+{
+  Vector<char*> *res = new Vector<char*>;
+  int idx = dbeSession->findIndexSpaceByName (name);
+  if (idx >= 0)
+    {
+      char *str = dbeSession->getIndexSpaceDescr (idx);
+      res->append (dbe_strdup (str));
+      str = dbeSession->getIndexSpaceExprStr (idx);
+      res->append (dbe_strdup (str));
+    }
+  return res;
+}
+
+static int
+key_cmp (const void *p1, const void *p2)
+{
+  long long ll1 = *(long long*) p1;
+  long long ll2 = *(long long*) p2;
+  return ll1 < ll2 ? -1 : ll1 > ll2 ? 1 : 0;
+}
+
+Vector<Vector<long long>*> *
+dbeGetXYPlotData (
+                 int data_id, // data table id
+                 char *lfilter, // local filter expression
+                 char *arg, // name for the argument
+                 char *func1, // expression for the first axis (x)
+                 char *aggr1, // aggregation function for func1: "SUM","CNT",...
+                 char *func2, // expression for the second axis (y)
+                 char *aggr2, // aggregation function for func2
+                 char *func3, // expression for the third axis (color)
+                 char *aggr3) // aggregation function for func3
+{
+  Vector<Vector<long long>*> *res = new Vector<Vector<long long>*>;
+  Experiment *exp = dbeSession->get_exp (0);
+  if (exp == NULL)
+    return res;
+  if (exp->get_status () == Experiment::INCOMPLETE)
+    exp->update ();
+
+  DataDescriptor *dataDscr = exp->get_raw_events (data_id);
+  if (dataDscr == NULL)
+    return res;
+
+  // Parse all expressions
+  Vector<Expression*> *funcs = new Vector<Expression*>;
+  Vector<Aggr_type> *aggrs = new Vector<Aggr_type>;
+  Vector<DefaultMap<long long, long long>*> *fval_maps =
+         new Vector<DefaultMap<long long, long long>*>;
+  Vector<DefaultMap<long long, long>*> *cnt_maps =
+         new Vector<DefaultMap<long long, long>*>;
+  if (func1 != NULL)
+    {
+      Expression *expr = dbeSession->ql_parse (func1);
+      funcs->append (expr);
+      aggrs->append (getAggrFunc (aggr1));
+      fval_maps->append (new DefaultMap<long long, long long>);
+      cnt_maps->append (new DefaultMap<long long, long>);
+      res->append (new Vector<long long>);
+      if (func2 != NULL)
+       {
+         expr = dbeSession->ql_parse (func2);
+         funcs->append (expr);
+         aggrs->append (getAggrFunc (aggr2));
+         fval_maps->append (new DefaultMap<long long, long long>);
+         cnt_maps->append (new DefaultMap<long long, long>);
+         res->append (new Vector<long long>);
+         if (func3 != NULL)
+           {
+             expr = dbeSession->ql_parse (func3);
+             funcs->append (expr);
+             aggrs->append (getAggrFunc (aggr3));
+             fval_maps->append (new DefaultMap<long long, long long>);
+             cnt_maps->append (new DefaultMap<long long, long>);
+             res->append (new Vector<long long>);
+           }
+       }
+    }
+  if (funcs->size () == 0)
+    {
+      funcs->destroy ();
+      delete funcs;
+      fval_maps->destroy ();
+      delete fval_maps;
+      cnt_maps->destroy ();
+      delete cnt_maps;
+      delete aggrs;
+      return res;
+    }
+  Expression *arg_expr = NULL;
+  if (arg != NULL)
+    arg_expr = dbeSession->ql_parse (arg);
+  if (arg_expr == NULL)
+    {
+      funcs->destroy ();
+      delete funcs;
+      fval_maps->destroy ();
+      delete fval_maps;
+      cnt_maps->destroy ();
+      delete cnt_maps;
+      delete aggrs;
+      return res;
+    }
+  Expression *flt_expr = NULL;
+  if (lfilter != NULL)
+    flt_expr = dbeSession->ql_parse (lfilter);
+  Vector<long long> *kidx_map = new Vector<long long>(); // key_idx -> key_val
+  for (long i = 0; i < dataDscr->getSize (); i++)
+    {
+      Expression::Context ctx (dbeSession->getView (0), exp, NULL, i);
+      // First use the filter
+      if (flt_expr != NULL)
+       if (flt_expr->eval (&ctx) == 0)
+         continue;
+
+      // Compute the argument
+      long long key = arg_expr->eval (&ctx);
+      if (kidx_map->find (key) == -1)
+       kidx_map->append (key);
+      for (long j = 0; j < funcs->size (); ++j)
+       {
+         Expression *func = funcs->fetch (j);
+         Aggr_type aggr = aggrs->fetch (j);
+         DefaultMap<long long, long long> *fval_map = fval_maps->fetch (j);
+         DefaultMap<long long, long> *cnt_map = cnt_maps->fetch (j);
+         long long fval = func->eval (&ctx);
+         long long aval = fval_map->get (key);
+         long cnt = cnt_map->get (key);
+         switch (aggr)
+           {
+           case AGGR_NONE:
+           case AGGR_FAIR:
+             if (cnt == 0)
+               aval = fval;
+             break;
+           case AGGR_MAX:
+             if (aval < fval || cnt == 0)
+               aval = fval;
+             break;
+           case AGGR_MIN:
+             if (aval > fval || cnt == 0)
+               aval = fval;
+             break;
+           case AGGR_CNT:
+             aval = cnt + 1;
+             break;
+           case AGGR_SUM:
+           case AGGR_AVG:
+             aval += fval;
+             break;
+           }
+         cnt_map->put (key, cnt + 1);
+         fval_map->put (key, aval);
+       }
+    }
+  kidx_map->sort (key_cmp);
+
+  // Finalize aggregation, prepare result
+  for (long j = 0; j < funcs->size (); ++j)
+    {
+      Aggr_type aggr = aggrs->fetch (j);
+      Vector<long long> *resj = res->fetch (j);
+      DefaultMap<long long, long long> *
+             fval_map = fval_maps->fetch (j);
+      DefaultMap<long long, long> *
+             cnt_map = cnt_maps->fetch (j);
+      for (int kidx = 0; kidx < kidx_map->size (); ++kidx)
+       {
+         long long key = kidx_map->fetch (kidx);
+         long long aval = fval_map->get (key);
+         if (aggr == AGGR_AVG)
+           {
+             long cnt = cnt_map->get (key);
+             if (cnt > 0)
+               aval = (aval + cnt / 2) / cnt;
+           }
+         resj->append (aval);
+       }
+    }
+  delete flt_expr;
+  funcs->destroy ();
+  delete funcs;
+  delete aggrs;
+  delete arg_expr;
+  delete kidx_map;
+  fval_maps->destroy ();
+  delete fval_maps;
+  cnt_maps->destroy ();
+  delete cnt_maps;
+  return res;
+}
+
+/* ********************************************************************* */
+/*  Routines for use by Collector GUI */
+/**
+ * Returns signal value for provided name. Example of name: "SIGUSR1"
+ * @param signal
+ * @return value
+ */
+int
+dbeGetSignalValue (char *signal)
+{
+  int ret = -1;
+  if (signal == NULL)
+    return ret;
+  if (strcmp (signal, "SIGUSR1") == 0)
+    return (SIGUSR1);
+  if (strcmp (signal, "SIGUSR2") == 0)
+    return (SIGUSR2);
+  if (strcmp (signal, "SIGPROF") == 0)
+    return (SIGPROF);
+  return ret;
+}
+
+char *
+dbeSendSignal (pid_t p, int signum)
+{
+  int ret = kill (p, signum);
+  if (p == 0 || p == -1)
+    return (dbe_sprintf (GTXT ("kill of process %d not supported\n"), p));
+  if (ret == 0)
+    return NULL;
+  char *msg = dbe_sprintf (GTXT ("kill(%d, %d) failed: %s\n"), p, signum,
+                          strerror (errno));
+  return msg;
+}
+
+char *
+dbeGetCollectorControlValue (char *control)
+{
+  if (control == NULL)
+    return NULL;
+  if (col_ctr == NULL)
+    col_ctr = new Coll_Ctrl (1);
+  char *msg = col_ctr->get (control);
+  return msg;
+}
+
+char *
+dbeSetCollectorControlValue (char *control, char * value)
+{
+  if (control == NULL)
+    return NULL;
+  if (col_ctr == NULL)
+    col_ctr = new Coll_Ctrl (1);
+  char *msg = col_ctr->set (control, value);
+  return msg;
+}
+
+char *
+dbeUnsetCollectorControlValue (char *control)
+{
+  if (control == NULL)
+    return NULL;
+  if (col_ctr == NULL)
+    col_ctr = new Coll_Ctrl (1);
+  char *msg = col_ctr->unset (control);
+  return msg;
+}
+
+void
+dbeSetLocation (const char *fname, const char *location)
+{
+  Vector<SourceFile*> *sources = dbeSession->get_sources ();
+  for (long i = 0, sz = sources ? sources->size () : 0; i < sz; i++)
+    {
+      SourceFile *src = sources->get (i);
+      DbeFile *df = src->dbeFile;
+      if (df && (strcmp (fname, df->get_name ()) == 0))
+       {
+         df->find_file ((char *) location);
+         break;
+       }
+    }
+}
+
+void
+dbeSetLocations (Vector<const char *> *fnames, Vector<const char *> *locations)
+{
+  if (fnames == NULL || locations == NULL
+      || fnames->size () != locations->size ())
+    return;
+  for (long i = 0, sz = fnames->size (); i < sz; i++)
+    dbeSetLocation (fnames->get (i), locations->get (i));
+}
+
+Vector<void*> *
+dbeResolvedWith_setpath (const char *path)
+{
+  Vector<char*> *names = new Vector<char*>();
+  Vector<char*> *pathes = new Vector<char*>();
+  Vector<long long> *ids = new Vector<long long>();
+  Vector<SourceFile*> *sources = dbeSession->get_sources ();
+  for (long i = 0, sz = sources ? sources->size () : 0; i < sz; i++)
+    {
+      SourceFile *src = sources->get (i);
+      DbeFile *df = src->dbeFile;
+      if (df == NULL || (df->filetype & DbeFile::F_FICTION) != 0)
+       continue;
+      char *fnm = df->get_name ();
+      if ((df->filetype & (DbeFile::F_JAVACLASS | DbeFile::F_JAVA_SOURCE)) != 0)
+       {
+         char *jnm = dbe_sprintf (NTXT ("%s/%s"), path, fnm);
+         if (df->check_access (jnm) == DbeFile::F_FILE)
+           {
+             names->append (dbe_strdup (fnm));
+             pathes->append (jnm);
+             ids->append (src->id);
+             continue;
+           }
+         free (jnm);
+       }
+      char *nm = dbe_sprintf (NTXT ("%s/%s"), path, get_basename (fnm));
+      if (df->check_access (nm) == DbeFile::F_FILE)
+       {
+         names->append (dbe_strdup (fnm));
+         pathes->append (nm);
+         ids->append (src->id);
+         continue;
+       }
+      free (nm);
+    }
+  if (names->size () != 0)
+    {
+      Vector<void*> *data = new Vector<void*>(3);
+      data->append (names);
+      data->append (pathes);
+      data->append (ids);
+      return data;
+    }
+  return NULL;
+}
+
+Vector<void*> *
+dbeResolvedWith_pathmap (const char *old_prefix, const char *new_prefix)
+{
+  size_t len = strlen (old_prefix);
+  Vector<char*> *names = new Vector<char*>();
+  Vector<char*> *pathes = new Vector<char*>();
+  Vector<long long> *ids = new Vector<long long>();
+  Vector<SourceFile*> *sources = dbeSession->get_sources ();
+  for (long i = 0, sz = sources ? sources->size () : 0; i < sz; i++)
+    {
+      SourceFile *src = sources->get (i);
+      DbeFile *df = src->dbeFile;
+      if (df == NULL || (df->filetype & DbeFile::F_FICTION) != 0)
+       continue;
+      char *fnm = df->get_name ();
+      if (strncmp (old_prefix, fnm, len) == 0
+         && (fnm[len] == '/' || fnm[len] == '\0'))
+       {
+         char *nm = dbe_sprintf (NTXT ("%s/%s"), new_prefix, fnm + len);
+         if (df->check_access (nm) == DbeFile::F_FILE)
+           {
+             names->append (dbe_strdup (fnm));
+             pathes->append (nm);
+             ids->append (src->id);
+             continue;
+           }
+         if ((df->filetype & DbeFile::F_JAVA_SOURCE) != 0)
+           {
+             free (nm);
+             nm = dbe_sprintf (NTXT ("%s/%s"), new_prefix, fnm);
+             if (df->check_access (nm) == DbeFile::F_FILE)
+               {
+                 names->append (dbe_strdup (fnm));
+                 pathes->append (nm);
+                 ids->append (src->id);
+                 continue;
+               }
+           }
+         free (nm);
+       }
+    }
+  if (names->size () != 0)
+    {
+      Vector<void*> *data = new Vector<void*>(3);
+      data->append (names);
+      data->append (pathes);
+      data->append (ids);
+      return data;
+    }
+  return NULL;
+}
+
+void
+dbe_archive (Vector<long long> *ids, Vector<const char *> *locations)
+{
+  if (ids == NULL || locations == NULL || ids->size () != locations->size ())
+    return;
+  Experiment *exp = dbeSession->get_exp (0);
+  if (exp == NULL)
+    return;
+  Vector<SourceFile*> *sources = dbeSession->get_sources ();
+  for (long i1 = 0, sz1 = ids->size (); i1 < sz1; i1++)
+    {
+      long long id = ids->get (i1);
+      for (long i = 0, sz = sources ? sources->size () : 0; i < sz; i++)
+       {
+         SourceFile *src = sources->get (i);
+         if (src->id == id)
+           {
+             DbeFile *df = src->dbeFile;
+             if (df)
+               {
+                 char *fnm = df->find_file ((char *) locations->get (i1));
+                 if (fnm)
+                   {
+                     char *nm = df->get_name ();
+                     char *anm = exp->getNameInArchive (nm, false);
+                     exp->copy_file (fnm, anm, true);
+                     free (anm);
+                   }
+               }
+           }
+       }
+    }
+}
+
+/* ************************************************************************ */
+
+/* Routines to check connection between Remote Analyzer Client and er_print */
+char *
+dbeCheckConnection (char *str)
+{
+  return dbe_strdup (str);
+}
diff --git a/gprofng/src/Dbe.h b/gprofng/src/Dbe.h
new file mode 100644 (file)
index 0000000..f811096
--- /dev/null
@@ -0,0 +1,294 @@
+/* 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 _DBE_H_
+#define _DBE_H_
+
+#include <stdio.h>
+#include "enums.h"
+
+class MetricList;
+template <class ITEM> class Vector;
+typedef long long Obj;
+
+Vector<char*> *dbeGetInitMessages (void);
+Vector<char*> *dbeGetExpPreview (int dbevindex, char *exp_name);
+char *dbeGetExpParams (int dbevindex, char *exp_name);
+char *dbeCreateDirectories (const char *dirname);
+char *dbeDeleteFile (const char *pathname);
+Vector<char*> *dbeReadFile (const char *pathname);
+int dbeWriteFile (const char *pathname, const char *contents);
+char *dbeGetFileAttributes (const char *filename, const char *format);
+char *dbeGetFiles (const char *dirname, const char *format);
+char *dbeGetRunningProcesses (const char *format);
+char *dbeOpenExperimentList (int dbevindex, Vector<Vector<char*>*> *groups,
+                            bool sessionRestart);
+char *dbeReadRCFile (int dbevindex, char* path);
+char *dbeSetExperimentsGroups (Vector<Vector<char*>*> *groups);
+Vector<Vector<char*>*> *dbeGetExperimensGroups ();
+char *dbeDropExperiment (int dbevindex, Vector<int> *drop_index);
+Vector<char*> *dbeGetExpsProperty (const char *prop_name);
+Vector<char*> *dbeGetExpName (int dbevindex);
+Vector<int> *dbeGetExpState (int dbevindex);
+Vector<bool> *dbeGetExpEnable (int dbevindex);
+bool dbeSetExpEnable (int dbevindex, Vector<bool> *enable);
+Vector<char*> *dbeGetExpInfo (int dbevindex);
+bool dbeGetViewModeEnable ();
+bool dbeGetJavaEnable ();
+int dbeUpdateNotes (int dbevindex, int exp_id, int type, char* text,
+                   bool handle_file);
+Vector<void*> *dbeGetTabListInfo (int dbevindex);
+Vector<bool> *dbeGetTabSelectionState (int dbevindex);
+void dbeSetTabSelectionState (int dbevindex, Vector<bool> *selected);
+Vector<bool> *dbeGetMemTabSelectionState (int dbevindex);
+void dbeSetMemTabSelectionState (int dbevindex, Vector<bool> *selected);
+Vector<bool> *dbeGetIndxTabSelectionState (int dbevindex);
+void dbeSetIndxTabSelectionState (int dbevindex, Vector<bool> *selected);
+Vector<char*> *dbeGetLoadObjectName (int dbevindex);
+Vector<void *> *dbeGetLoadObjectList (int dbevindex);
+Vector<char*> *dbeGetSearchPath (int dbevindex);
+void dbeSetSearchPath (int dbevindex, Vector<char*> *path);
+Vector<void*> *dbeGetPathmaps (int dbevindex);
+char *dbeSetPathmaps (Vector<char*> *from, Vector<char*> *to);
+char *dbeAddPathmap (int dbevindex, char *from, char *to);
+char *dbeGetMsg (int dbevindex, int type);
+int dbeInitView (int index, int cloneindex);
+void dbeDeleteView (int dbevindex);
+
+//     methods concerning metrics
+MetricList *dbeGetMetricListV2 (int dbevindex, MetricType mtype,
+                               Vector<int> *type, Vector<int> *subtype,
+                               Vector<bool> *sort, Vector<int> *vis,
+                               Vector<char*> *aux, Vector<char*> *expr_spec,
+                               Vector<char*> *legends);
+Vector<void*> *dbeGetRefMetricsV2 ();
+Vector<void*> *dbeGetCurMetricsV2 (int dbevindex, MetricType mtype);
+void dbeSetSort (int dbevindex, int sort_index, MetricType mtype, bool reverse);
+
+//     methods concerning metrics for Overview Tab
+Vector<void*> *dbeGetRefMetricTree (int dbevindex, bool include_unregistered);
+Vector<void*> *dbeGetRefMetricTreeValues (int dbevindex, Vector<char *> *met_cmds,
+                                         Vector<char *> *non_met_cmds);
+Vector<char*> *dbeGetOverviewText (int dbevindex);
+Vector<int> *dbeGetAnoValue (int dbevindex);
+void dbeSetAnoValue (int dbevindex, Vector<int> *set);
+int dbeGetNameFormat (int dbevindex);
+bool dbeGetSoName (int dbevindex);
+void dbeSetNameFormat (int dbevindex, int fnames, bool soname);
+int dbeGetViewMode (int dbevindex);
+void dbeSetViewMode (int dbevindex, int nmode);
+Vector<void*> *dbeGetTLValue (int dbevindex);
+void dbeSetTLValue (int dbevindex, const char *tldata_cmd,
+                   int entitiy_prop_id, int stackalign, int stackdepth);
+Vector<void*> *dbeGetExpFounderDescendants ();
+Vector<void*> *dbeGetExpSelection (int dbevindex);
+Vector<void*> *dbeGetSampleStatus (int dbevindex, int nselected,
+                                  Vector<bool> *selected);
+Vector<unsigned> *dbeGetSampleSize (int dbevindex, Vector<bool> *selected);
+char *dbeCheckPattern (int dbevindex, Vector<bool> *selected, char *pattern,
+                      int type);
+char *dbeSetFilterStr (int dbevindex, char *filter_str);
+char *dbeGetFilterStr (int dbevindex);
+int dbeValidateFilterExpression (char *str_expr);
+Vector<void*> *dbeGetFilterKeywords (int dbevindex);
+Vector<void*> *dbeGetFilters (int dbevindex, int nexp);
+bool dbeUpdateFilters (int dbevindex, Vector<bool> *selected,
+                      Vector<char*> *pattern_str);
+char *dbeComposeFilterClause (int dbevindex, int type, int subtype,
+                             Vector<int>*selections);
+Vector<int> *dbeGetLoadObjectState (int dbevindex);
+void dbeSetLoadObjectState (int dbevindex, Vector<int> *selected);
+void dbeSetLoadObjectDefaults (int dbevindex);
+Vector<void*> *dbeGetMemObjects (int dbevindex);
+char *dbeDefineMemObj (char *name, char *index_expr, char *_machmodel,
+                      char *sdesc, char *ldesc);
+char *dbeDeleteMemObj (char *name);
+Vector<char*> *dbeGetCPUVerMachineModel (int dbevindex);
+char *dbeLoadMachineModel (char *name);
+char *dbeGetMachineModel ();
+Vector<char*> *dbeListMachineModels ();
+void dbeDetectLoadMachineModel (int dbevindex);
+Vector<void*> *dbeGetIndxObjDescriptions (int dbevindex);
+Vector<void*> *dbeGetCustomIndxObjects (int dbevindex);
+char *dbeDefineIndxObj (char *name, char *index_expr, char *sdesc, char *ldesc);
+void dbeSetSelObj (int dbevindex, Obj sel_obj, int type, int subtype);
+void dbeSetSelObjV2 (int dbevindex, uint64_t id);
+Obj dbeGetSelObj (int dbevindex, int type, int subtype);
+uint64_t dbeGetSelObjV2 (int dbevindex, char *typeStr);
+int dbeGetSelIndex (int dbevindex, Obj sel_obj, int type, int subtype);
+Vector<uint64_t> *dbeGetSelObjsIO (int dbevindex, Vector<uint64_t> *ids, int type);
+Vector<uint64_t> *dbeGetSelObjIO (int dbevindex, uint64_t id, int type);
+uint64_t dbeGetSelObjHeapTimestamp (int dbevindex, uint64_t id);
+int dbeGetSelObjHeapUserExpId (int dbevindex, uint64_t id);
+char *dbeSetPrintLimit (int dbevindex, int limit);
+int dbeGetPrintLimit (int dbevindex);
+char *dbeSetPrintMode (int dbevindex, char *printmode);
+int dbeGetPrintMode (int dbevindex);
+char *dbeGetPrintModeString (int dbevindex);
+char dbeGetPrintDelim (int dbevindex);
+Vector<void*> *dbeGetTotals (int dbevindex, int dsptype, int subtype);
+Vector<void*> *dbeGetHotMarks (int dbevindex, int type);
+Vector<void*> *dbeGetHotMarksInc (int dbevindex, int type);
+Vector<void*> *dbeGetSummaryHotMarks (int dbevindex, Vector<Obj> *sel_objs, int type);
+Vector<uint64_t> *dbeGetFuncId (int dbevindex, int type, int begin, int length);
+Vector<void*> *dbeGetFuncCalleeInfo (int dbevindex, int type, Vector<int>* idxs, int groupId);
+Vector<void*> *dbeGetFuncCallerInfo (int dbevindex, int type, Vector<int>* idxs, int groupId);
+Vector<void*> *dbeGetFuncCalleeInfoById (int dbevindex, int type, int idx);
+Vector<void*> *dbeGetFuncCallerInfoById (int dbevindex, int type, int idx);
+char *dbePrintData (int dbevindex, int type, int subtype, char *printer,
+                   char *fname, FILE *outfile);
+int dbeSetFuncData (int dbevindex, Obj sel_obj, int type, int subtype);
+Vector<void*> *dbeGetFuncList (int dbevindex, int type, int subtype);
+Vector<void*> *dbeGetFuncListV2 (int dbevindex, int mtype, Obj sel_obj, int type, int subtype);
+Vector<void*> *dbeGetFuncListMini (int dbevindex, int type, int subtype);
+Vector<Obj> *dbeGetComparableObjsV2 (int dbevindex, Obj sel_obj, int type);
+Obj dbeConvertSelObj (Obj obj, int type);
+Vector<int> *dbeGetGroupIds (int dbevindex);
+Vector<void*> *dbeGetTableDataV2 (int dbevindex, char *mlistStr, char *modeStr,
+                                 char *typeStr, char *subtypeStr, Vector<uint64_t> *ids);
+
+int dbeGetCallTreeNumLevels (int dbevindex);
+Vector<void*> *dbeGetCallTreeLevel (int dbevindex, char *mcmd, int level);
+Vector<void*> *dbeGetCallTreeLevels (int dbevindex, char *mcmd);
+Vector<void*> *dbeGetCallTreeChildren (int dbevindex, char *mcmd, Vector<int /*NodeIdx*/>*nodes);
+Vector<void*> *dbeGetCallTreeLevelFuncs (int dbevindex, int level_start, int level_end);
+Vector<void*> *dbeGetCallTreeFuncs (int dbevindex);
+Vector<char*> *dbeGetNames (int dbevindex, int type, Obj sel_obj);
+Vector<void*> *dbeGetTotalMax (int dbevindex, int type, int subtype);
+Vector<void*> *dbeGetStatisOverviewList (int dbevindex);
+Vector<void*> *dbeGetStatisList (int dbevindex);
+Vector<void*> *dbeGetSummary (int dbevindex, Vector<Obj> *objs, int type, int subtype);
+Vector<void*> *dbeGetSummaryV2 (int dbevindex, Vector<Obj> *objs, int type, int subtype);
+Vector<int> *dbeGetFounderExpId (Vector<int> *expIds);
+Vector<int> *dbeGetUserExpId (Vector<int> *expIds); // filter "user visible" experiment id
+Vector<int> *dbeGetExpGroupId (Vector<int> *expIds);
+char *dbeGetExpName (int dbevindex, char *dir_name);
+Vector<char*> *dbeGetHwcHelp (int dbevindex, bool forKernel);
+Vector<Vector<char*>*> *dbeGetHwcSets (int dbevindex, bool forKernel);
+Vector<void*> *dbeGetHwcsAll (int dbevindex, bool forKernel);
+Vector<char*> *dbeGetHwcAttrList (int dbevindex, bool forKernel);
+int dbeGetHwcMaxConcurrent (int dbevindex, bool forKernel);
+int dbeGetHwcMaxReg (int dbevindex); // TBR?
+
+Vector<char*> *dbeGetIfreqData (int dbevindex);
+Vector<void*> *dbeGetLeakListInfo (int dbevindex, bool leakflag);
+Vector<void*> *dbeMpviewGetTlFuncReps (int dbevindex, int exp_id,
+                                      long long binSizeTime, long long startTime, long long endTime,
+                                      long long binSizeRank, long long startRank, long long endRank);
+Vector<void*> *dbeMpviewGetTlMsgReps (int dbevindex, int exp_id, int throttle,
+                                     long long binSizeTime, long long startTime, long long endTime,
+                                     long long binSizeRank, long long startRank, long long endRank);
+Vector<long long> *dbeMpviewGetAxisRange (int dbevindex, int exp_id,
+                                         int chart_type, int axis_type);
+Vector<char*> *dbeMpviewGetAxisDiscreteLabels (int dbevindex, int exp_id,
+                                              int chart_type, int axis_type);
+Vector<void*> *dbeMpviewGetFuncDetails (int dbevindex, int exp_id, Obj funcId);
+Vector<void*> *dbeMpviewGetMesgDetails (int dbevindex, int exp_id, Obj mesgId);
+Vector<long long> *dbeMpviewGetChartData (int dbevindex, int exp_id, int ctype,
+                                         int attr1, long long start1,
+                                         long long end1, int nbins1,
+                                         int attr2, long long start2,
+                                         long long end2, int nbins2,
+                                         int metric, int reduction);
+void dbeMpviewFilterSet (int dbevindex, int exp_id, Vector<int> *ctid,
+                        Vector<int > *axid, Vector<long long> *startVal,
+                        Vector<long long> *endVal);
+void dbeMpviewLoadStacks (int dbevindex, int exp_id);
+
+
+Obj dbeGetObject (int dbevindex, Obj sel_func, Obj sel_pc);
+char *dbeGetName (int dbevindex, int exp_id);
+Vector<char*> *dbeGetExpVerboseName (Vector<int> *exp_ids);
+long long dbeGetStartTime (int dbevindex, int exp_id);
+long long dbeGetRelativeStartTime (int dbevindex, int exp_id);
+long long dbeGetEndTime (int dbevindex, int exp_id);
+int dbeGetClock (int dbevindex, int exp_id);
+long long dbeGetWallStartSec (int dbevindex, int exp_id);
+char *dbeGetHostname (int dbevindex, int exp_id);
+Vector<void*> *dbeGetEntityProps (int dbevindex);
+Vector<void*> *dbeGetEntities (int dbevindex, int exp_id, int ekind);
+Vector<void*> *dbeGetEntitiesV2 (int dbevindex, Vector<int> *exp_ids, int ekind);
+Vector<void*> *dbeGetTLDetails (int dbevindex, int exp_id, int data_id,
+                               int entity_prop_id, Obj event_id);
+Vector<Obj> *dbeGetStackFunctions (int dbevindex, Obj stack);
+Vector<void*> *dbeGetStacksFunctions (int dbevindex, Vector<Obj> *stacks);
+Vector<Obj> *dbeGetStackPCs (int dbevindex, Obj stack);
+Vector<char*> *dbeGetStackNames (int dbevindex, Obj stack);
+Vector<void*> *dbeGetSamples (int dbevindex, int exp_id, int64_t lo, int64_t hi);
+Vector<void*> *dbeGetGCEvents (int dbevindex, int exp_id, int64_t lo, int64_t hi);
+Vector<Vector<char*>*>* dbeGetIOStatistics (int dbevindex);
+Vector<Vector<char*>*>* dbeGetHeapStatistics (int dbevindex);
+Vector<char*> *dbeGetFuncNames (int dbevindex, Vector<Obj> *funcs);
+Vector<char*> *dbeGetObjNamesV2 (int dbevindex, Vector<uint64_t> *ids);
+char *dbeGetFuncName (int dbevindex, Obj func);
+char *dbeGetObjNameV2 (int dbevindex, uint64_t id);
+Vector<uint64_t> *dbeGetFuncIds (int dbevindex, Vector<Obj> *funcs);
+uint64_t dbeGetFuncId (int dbevindex, Obj func);
+char *dbeGetDataspaceTypeDesc (int dbevindex, Obj stack);
+Vector<void*> *dbeGetDataDescriptorsV2 (int exp_id);
+Vector<void*> *dbeGetDataPropertiesV2 (int exp_id, int data_id);
+Vector<void*> *dbeGetExperimentTimeInfo (Vector<int> *exp_ids);
+Vector<void*> *dbeGetExperimentDataDescriptors (Vector<int> *exp_ids);
+
+/*   New Timeline Interface */
+Vector<long long> *dbeGetAggregatedValue (int data_id, char *lfilter, char *fexpr,
+                                         char *pname_ts, hrtime_t start_ts,
+                                         hrtime_t delta, int num,
+                                         char *pname_key, char *aggr_func);
+Vector<char*> *dbeGetLineInfo (Obj pc);
+int dbeSetAlias (char *name, char *uname, char *expr);
+Vector<char*> *dbeGetAlias (char *name);
+Vector<Vector<long long>*> *dbeGetXYPlotData (int data_id, char *lfilter,
+                                             char *arg, char *func1, char *aggr1,
+                                             char *func2, char *aggr2,
+                                             char *func3, char *aggr3);
+Vector<bool> *dbeHasTLData (int dbev_index, Vector<int> *exp_ids,
+                           Vector<int> *data_ids, // DATA_*
+                           Vector<int> *entity_prop_ids, // LWP,CPU,THR, etc
+                           Vector<int> *entity_prop_values,
+                           Vector<int> *auxs);
+Vector<void*> *dbeGetTLData (int dbevindex, int exp_id, int data_id,
+                            int entity_prop_id, int entity_prop_val, int aux,
+                            hrtime_t start_ts, hrtime_t delta, int num,
+                            bool getRepresentatives, Vector<char*> *chartProperties);
+Vector<long long> *dbeGetTLEventCenterTime (int dbevindex, int exp_id,
+                                           int data_id, int entity_prop_id,
+                                           int entity_prop_val, int aux,
+                                           long long event_idx, long long move_count);
+long long dbeGetTLEventIdxNearTime (int dbevindex, int exp_id,
+                                   int data_id,
+                                   int entity_prop_id, int entity_prop_val, int aux,
+                                   int searchDirection,
+                                   long long timestamp);
+
+/*   Interface for use by Collector GUI */
+int dbeGetSignalValue (char *);
+char *dbeSendSignal (pid_t, int);
+char *dbeGetCollectorControlValue (char *);
+char *dbeSetCollectorControlValue (char *, char *);
+char *dbeUnsetCollectorControlValue (char *);
+char *dbeCheckConnection (char *);
+void dbe_archive (Vector<long long> *ids, Vector<const char *> *locations);
+void dbeSetLocation (const char *fname, const char *location);
+void dbeSetLocations (Vector<const char *> *fnames, Vector<const char *> *locations);
+Vector<void*> *dbeResolvedWith_setpath (const char *path);
+Vector<void*> *dbeResolvedWith_pathmap (const char *old_prefix, const char *new_prefix);
+
+#endif /* _DBE_H_ */
diff --git a/gprofng/src/DbeApplication.cc b/gprofng/src/DbeApplication.cc
new file mode 100644 (file)
index 0000000..382bd45
--- /dev/null
@@ -0,0 +1,113 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+
+#include "DbeSession.h"
+#include "DbeApplication.h"
+#include "LoadObject.h"
+#include "Experiment.h"
+#include "PreviewExp.h"
+#include "Function.h"
+#include "Hist_data.h"
+#include "Module.h"
+#include "DataObject.h"
+#include "Sample.h"
+#include "CallStack.h"
+#include "Print.h"
+#include "util.h"
+#include "libgen.h"
+#include "i18n.h"
+
+DbeApplication *theDbeApplication;
+
+DbeApplication::DbeApplication (int argc, char *argv[], char* _run_dir)
+: Application (argc, argv, _run_dir)
+{
+  theDbeApplication = this;
+  ipcMode = false;
+  rdtMode = false;
+  if (argc > 1)
+    if (strcmp (argv[1], NTXT ("-IPC")) == 0
+       || strcmp (argv[1], NTXT ("-DIPC")) == 0)
+      ipcMode = true;
+  lic_found = 0;
+  lic_err = NULL;
+
+  // Instantiate a session
+  (void) new DbeSession (settings, ipcMode, rdtMode);
+}
+
+DbeApplication::~DbeApplication ()
+{
+  delete dbeSession;
+  theDbeApplication = NULL;
+}
+
+Vector<char*> *
+DbeApplication::initApplication (char *fdhome, char *licpath, ProgressFunc func)
+{
+  // set the home directory
+  if (fdhome != NULL)
+    set_run_dir (fdhome);
+
+  // Set progress function
+  set_progress_func (func);
+
+  // Get license
+  char *license_err = NULL;
+  char *sts;
+  if (licpath != NULL)
+    {
+      lic_found = 0;
+      if (lic_found == 0)
+       {
+         lic_err = dbe_strdup (DbeApplication::get_version ());
+         sts = dbe_strdup (GTXT ("OK"));
+       }
+      else if (lic_found == 2)
+       {
+         lic_err = dbe_strdup (license_err);
+         sts = dbe_strdup (GTXT ("WARN"));
+       }
+      else if (lic_found == 3)
+       {
+         lic_err = dbe_strdup (license_err);
+         sts = dbe_strdup (GTXT ("FATAL"));
+       }
+      else
+       {
+         lic_err = dbe_strdup (license_err);
+         sts = dbe_strdup (GTXT ("ERROR"));
+       }
+    }
+  else
+    {
+      lic_err = dbe_strdup (DbeApplication::get_version ());
+      sts = dbe_strdup (GTXT ("OK"));
+    }
+  Vector<char*> *data = new Vector<char*>(2);
+  data->store (0, sts);
+  data->store (1, lic_err);
+  return data;
+}
diff --git a/gprofng/src/DbeApplication.h b/gprofng/src/DbeApplication.h
new file mode 100644 (file)
index 0000000..b6bdaaf
--- /dev/null
@@ -0,0 +1,50 @@
+/* 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.  */
+
+/*
+ * The DbeApplication class is the base class for all C++ executables
+ *  that read Experiments
+ *
+ *  It is derived from the Application class, and differs from it
+ *  only in that it instantiates a DbeSession (q.v.) to manage
+ *  the reading and processing of Experiments
+ */
+
+#ifndef _DBEAPPLICATION_H
+#define _DBEAPPLICATION_H
+
+#include "Application.h"
+
+template <class ITEM> class Vector;
+
+class DbeApplication : public Application
+{
+public:
+  DbeApplication (int argc, char *argv[], char *_run_dir = NULL);
+  ~DbeApplication ();
+  Vector<char*> *initApplication (char *fdhome, char *licpath, ProgressFunc func);
+
+  bool rdtMode;
+  bool ipcMode;
+};
+
+extern DbeApplication *theDbeApplication;
+
+#endif  /* _DBEAPPLICATION_H */
diff --git a/gprofng/src/DbeArray.h b/gprofng/src/DbeArray.h
new file mode 100644 (file)
index 0000000..af7c36e
--- /dev/null
@@ -0,0 +1,99 @@
+/* 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 _DbeArray_H
+#define _DbeArray_H
+
+template <typename ITEM> class DbeArray
+{
+public:
+
+  DbeArray (long sz)
+  {
+    count = 0;
+    limit = sz;
+    data = new ITEM[limit];
+  };
+
+  virtual
+  ~DbeArray ()
+  {
+    delete[] data;
+  }
+
+  int
+  append (const ITEM &item)
+  {
+    int n = allocate (1);
+    ITEM *p = get (n);
+    *p = item;
+    return n;
+  };
+
+  ITEM *
+  get (long index)
+  {
+    return (index < count && index >= 0) ? data + index : (ITEM *) NULL;
+  };
+
+  int
+  allocate (int cnt)
+  {
+    count += cnt;
+    resize (count);
+    return count - cnt;
+  };
+
+  int
+  size ()
+  {
+    return (int) count;
+  };
+
+  void
+  reset ()
+  {
+    count = 0;
+  };
+
+private:
+
+  void
+  resize (long cnt)
+  {
+    if (limit <= cnt)
+      {
+       limit *= 2;
+       if (limit < cnt)
+         limit = cnt + 1;
+       ITEM *d = new ITEM[limit];
+       if (count > 0)
+         memcpy (d, data, sizeof (ITEM) * count);
+       delete[] data;
+       data = d;
+      }
+  };
+
+  ITEM *data;   // Pointer to data vector
+  long count;   // Number of items
+  long limit;   // Array length
+};
+
+#endif /* _DbeArray_H */
diff --git a/gprofng/src/DbeCacheMap.h b/gprofng/src/DbeCacheMap.h
new file mode 100644 (file)
index 0000000..4c51a34
--- /dev/null
@@ -0,0 +1,109 @@
+/* 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.  */
+
+/*
+ *     Dbe Cache Map implementation.
+ *
+ *    Simple Cache Map makes the following assumptions:
+ *    - Cache Map is used for very fast but not guaranteed mapping;
+ *    - No Relations can be used;
+ *    - all objects used as keys or values has to be managed
+ *      outside CacheMap (f.e. deletion);
+ */
+
+#ifndef _DbeCacheMap_h
+#define _DbeCacheMap_h
+
+#include <Map.h>
+
+template <typename Key_t, class ITEM>
+class DbeCacheMap : public Map<Key_t, ITEM *>
+{
+public:
+
+  DbeCacheMap (int _size = DefaultSize)
+  { // _size should be 2 ** N
+    size = _size;
+    table = new DbeCache_T[size];
+    memset (table, 0, size * sizeof (DbeCache_T));
+  };
+
+  ~DbeCacheMap ()
+  {
+    delete[] table;
+  };
+
+  void
+  put (Key_t key, ITEM *val)
+  {
+    int ind = get_hash (key);
+    table[ind].key = key;
+    table[ind].value = val;
+  };
+
+  ITEM *
+  get (Key_t key)
+  {
+    int ind = get_hash (key);
+    if (table[ind].key == key)
+      return table[ind].value;
+    return (ITEM *) NULL;
+  };
+
+  ITEM *
+  remove (Key_t key)
+  {
+    int ind = get_hash (key);
+    ITEM *v = table[ind].value;
+    table[ind].value = (ITEM *) NULL;
+    return v;
+  };
+
+  ITEM *
+  get (Key_t /* key */, typename Map<Key_t, ITEM *>::Relation /* rel */)
+  {
+    return (ITEM *) NULL;
+  };
+
+private:
+
+  enum
+  {
+    DefaultSize     = (1 << 13)
+  };
+
+  typedef struct DbeCache_S
+  {
+    Key_t key;
+    ITEM *value;
+  } DbeCache_T;
+  DbeCache_T *table;
+  int size;
+
+  int
+  get_hash (Key_t key)
+  {
+    unsigned long long h = (unsigned long long) key;
+    h ^= (h >> 20) ^ (h >> 12);
+    return (h ^ (h >> 7) ^ (h >> 4)) & (size - 1);
+  }
+};
+
+#endif
diff --git a/gprofng/src/DbeFile.cc b/gprofng/src/DbeFile.cc
new file mode 100644 (file)
index 0000000..9e1fe1c
--- /dev/null
@@ -0,0 +1,541 @@
+/* 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 "util.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "DbeFile.h"
+#include "ExpGroup.h"
+#include "DbeJarFile.h"
+
+DbeFile::DbeFile (const char *filename)
+{
+  filetype = 0;
+  name = dbe_strdup (filename);
+  name = canonical_path (name);
+  orig_location = NULL;
+  location = NULL;
+  location_info = NULL;
+  jarFile = NULL;
+  container = NULL;
+  need_refind = true;
+  inArchive = false;
+  sbuf.st_atim.tv_sec = 0;
+  experiment = NULL;
+}
+
+DbeFile::~DbeFile ()
+{
+  free (name);
+  free (location);
+  free (orig_location);
+  free (location_info);
+}
+
+void
+DbeFile::set_need_refind (bool val)
+{
+  if (val != need_refind)
+    {
+      free (location_info);
+      location_info = NULL;
+      need_refind = val;
+    }
+}
+
+void
+DbeFile::set_location (const char *filename)
+{
+  free (location);
+  location = NULL;
+  if (filename)
+    {
+      if (strncmp (filename, NTXT ("./"), 2) == 0)
+       filename += 2;
+      location = canonical_path (dbe_strdup (filename));
+    }
+  free (location_info);
+  location_info = NULL;
+  set_need_refind (false);
+}
+
+char *
+DbeFile::get_location_info ()
+{
+  if (location_info == NULL)
+    {
+      char *fnm = get_name ();
+      char *loc = get_location ();
+      Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location_info: %s %s\n"),
+              STR (fnm), STR (loc));
+      if (loc == NULL)
+       {
+         if (filetype & F_FICTION)
+           location_info = dbe_strdup (fnm);
+         else
+           location_info = dbe_sprintf (GTXT ("%s (not found)"),
+                                        get_relative_path (fnm));
+       }
+      else
+       {
+         char *r_fnm = get_relative_path (fnm);
+         char *r_loc = get_relative_path (loc);
+         if (strcmp (r_fnm, r_loc) == 0)
+           location_info = dbe_strdup (r_fnm);
+         else
+           {
+             char *bname = get_basename (r_fnm);
+             if (strcmp (bname, r_loc) == 0)  // found in current directory
+               location_info = dbe_strdup (bname);
+             else
+               location_info = dbe_sprintf (GTXT ("%s (found as %s)"), bname, r_loc);
+           }
+       }
+    }
+  return location_info;
+}
+
+char *
+DbeFile::getResolvedPath ()
+{
+  if (get_location ())
+    return location;
+  return name;
+}
+
+DbeFile *
+DbeFile::getJarDbeFile (char *fnm, int sym)
+{
+  Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::getJarDbeFile: %s fnm='%s' sym=%d\n"),
+          STR (name), STR (fnm), sym);
+  DbeFile *df = NULL;
+  if (sym)
+    {
+      char *s = strchr (fnm, sym);
+      if (s)
+       {
+         s = dbe_strndup (fnm, s - fnm);
+         df = dbeSession->getDbeFile (s, F_JAR_FILE | F_FILE);
+         free (s);
+       }
+    }
+  if (df == NULL)
+    df = dbeSession->getDbeFile (fnm, F_JAR_FILE | F_FILE);
+  if (df && (df->experiment == NULL))
+    df->experiment = experiment;
+  return df;
+}
+
+char *
+DbeFile::get_location (bool find_needed)
+{
+  Dprintf (DEBUG_DBE_FILE, NTXT ("get_location 0x%x %s\n"), filetype, STR (name));
+  if (!find_needed)
+    return need_refind ? NULL : location;
+  if (location || !need_refind)
+    return location;
+  set_need_refind (false);
+  if ((filetype & F_FICTION) != 0)
+    return NULL;
+  if (filetype == F_DIR_OR_JAR)
+    {
+      find_in_archives (name);
+      if (location)
+       {
+         filetype |= F_JAR_FILE | F_FILE;
+         return location;
+       }
+      find_in_pathmap (name);
+      if (location)
+       return location;
+      if (check_access (name) == F_DIRECTORY)
+       {
+         filetype |= F_DIRECTORY;
+         set_location (name);
+         return location;
+       }
+    }
+
+  if ((filetype & F_FILE) != 0)
+    {
+      if (experiment)
+       {
+         char *fnm = experiment->checkFileInArchive (name, false);
+         if (fnm)
+           {
+             set_location (fnm);
+             inArchive = true;
+             sbuf.st_mtime = 0; // Don't check timestamps
+             free (fnm);
+             return location;
+           }
+         if ((filetype & F_JAVACLASS) != 0)
+           {
+             if (orig_location)
+               {
+                 Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d name='%s' orig_location='%s'\n"),
+                          (int) __LINE__, name, orig_location);
+                 // Parse a fileName attribute. There are 4 possibilities:
+                 //   file:<Class_Name>
+                 //   file:<name_of_jar_or_zip_file>
+                 //   jar:file:<name_of_jar_or_zip_file>!<Class_Name>
+                 //   zip:<name_of_jar_or_zip_file>!<Class_Name>
+                 DbeFile *jar_df = NULL;
+                 if (strncmp (orig_location, NTXT ("zip:"), 4) == 0)
+                   jar_df = getJarDbeFile (orig_location + 4, '!');
+                 else if (strncmp (orig_location, NTXT ("jar:file:"), 9) == 0)
+                   jar_df = getJarDbeFile (orig_location + 9, '!');
+                 else if (strncmp (orig_location, NTXT ("file:"), 5) == 0
+                          && isJarOrZip (orig_location + 5))
+                   jar_df = getJarDbeFile (orig_location + 5, 0);
+                 if (jar_df)
+                   {
+                     if (find_in_jar_file (name, jar_df->get_jar_file ()))
+                       {
+                         Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d FOUND name='%s' location='%s' jar='%s'\n"),
+                                  (int) __LINE__, name, STR (location), STR (jar_df->get_location ()));
+                         inArchive = jar_df->inArchive;
+                         container = jar_df;
+                         return location;
+                       }
+                   }
+                 if (strncmp (orig_location, NTXT ("file:"), 5) == 0
+                     && !isJarOrZip (orig_location + 5))
+                   {
+                     DbeFile *df = new DbeFile (orig_location + 5);
+                     df->filetype = DbeFile::F_FILE;
+                     df->experiment = experiment;
+                     fnm = df->get_location ();
+                     if (fnm)
+                       {
+                         set_location (fnm);
+                         inArchive = df->inArchive;
+                         sbuf.st_mtime = df->sbuf.st_mtime;
+                         Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d FOUND name='%s' orig_location='%s' location='%s'\n"),
+                                  (int) __LINE__, name, orig_location, fnm);
+                         delete df;
+                         return location;
+                       }
+                     delete df;
+                   }
+               }
+             fnm = dbe_sprintf (NTXT ("%s/%s/%s"), experiment->get_expt_name (), SP_DYNAMIC_CLASSES, name);
+             if (find_file (fnm))
+               {
+                 inArchive = true;
+                 sbuf.st_mtime = 0; // Don't check timestamps
+                 Dprintf (DEBUG_DBE_FILE, NTXT ("DbeFile::get_location:%d FOUND name='%s' location='%s'\n"),
+                          (int) __LINE__, name, fnm);
+                 free (fnm);
+                 return location;
+               }
+             free (fnm);
+           }
+       }
+    }
+
+  if (dbeSession->archive_mode)
+    {
+      find_file (name);
+      if (location)
+       return location;
+    }
+
+  bool inPathMap = find_in_pathmap (name);
+  if (location)
+    return location;
+  find_in_setpath (name, dbeSession->get_search_path ());
+  if (location)
+    return location;
+  if ((filetype & (F_JAVACLASS | F_JAVA_SOURCE)) != 0)
+    {
+      find_in_classpath (name, dbeSession->get_classpath ());
+      if (location)
+       return location;
+    }
+  if (!inPathMap)
+    find_file (name);
+  Dprintf (DEBUG_DBE_FILE && (location == NULL),
+          "DbeFile::get_location:%d NOT FOUND name='%s'\n", __LINE__, name);
+  return location;
+}
+
+int
+DbeFile::check_access (const char *filename)
+{
+  if (filename == NULL)
+    return F_NOT_FOUND;
+  int st = dbe_stat (filename, &sbuf);
+  Dprintf (DEBUG_DBE_FILE, NTXT ("check_access: %d 0x%x %s\n"), st, filetype, filename);
+  if (st == 0)
+    {
+      if (S_ISDIR (sbuf.st_mode))
+       return F_DIRECTORY;
+      else if (S_ISREG (sbuf.st_mode))
+       return F_FILE;
+      return F_UNKNOWN; // Symbolic link or unknown type of file
+    }
+  sbuf.st_atim.tv_sec = 0;
+  sbuf.st_mtime = 0; // Don't check timestamps
+  return F_NOT_FOUND; // File not found
+}
+
+bool
+DbeFile::isJarOrZip (const char *fnm)
+{
+  size_t len = strlen (fnm) - 4;
+  return len > 0 && (strcmp (fnm + len, NTXT (".jar")) == 0
+                    || strcmp (fnm + len, NTXT (".zip")) == 0);
+}
+
+char *
+DbeFile::find_file (const char *filename)
+{
+  switch (check_access (filename))
+    {
+    case F_DIRECTORY:
+      if (filetype == F_DIR_OR_JAR)
+       filetype |= F_DIRECTORY;
+      if ((filetype & F_DIRECTORY) != 0)
+       set_location (filename);
+      break;
+    case F_FILE:
+      if (filetype == F_DIR_OR_JAR)
+       {
+         filetype |= F_FILE;
+         if (isJarOrZip (filename))
+           filetype |= F_JAR_FILE;
+       }
+      if ((filetype & F_DIRECTORY) == 0)
+       set_location (filename);
+      break;
+    }
+  return location;
+}
+
+DbeJarFile *
+DbeFile::get_jar_file ()
+{
+  if (jarFile == NULL)
+    {
+      char *fnm = get_location ();
+      if (fnm)
+       jarFile = dbeSession->get_JarFile (fnm);
+    }
+  return jarFile;
+}
+
+char *
+DbeFile::find_package_name (const char *filename, const char *dirname)
+{
+  char *nm = dbe_sprintf (NTXT ("%s/%s"), dirname, filename);
+  if (!find_in_pathmap (nm))
+    find_file (nm);
+  free (nm);
+  return location;
+}
+
+char *
+DbeFile::find_in_directory (const char *filename, const char *dirname)
+{
+  if (filename && dirname)
+    {
+      char *nm = dbe_sprintf (NTXT ("%s/%s"), dirname, filename);
+      find_file (nm);
+      free (nm);
+    }
+  return location;
+}
+
+char *
+DbeFile::find_in_jar_file (const char *filename, DbeJarFile *jfile)
+{
+  // Read .jar or .zip
+  if (jfile == NULL)
+    return NULL;
+  int entry = jfile->get_entry (filename);
+  if (entry >= 0)
+    {
+      char *fnm = dbeSession->get_tmp_file_name (filename, true);
+      long long fsize = jfile->copy (fnm, entry);
+      if (fsize >= 0)
+       {
+         dbeSession->tmp_files->append (fnm);
+         set_location (fnm);
+         sbuf.st_size = fsize;
+         sbuf.st_mtime = 0; // Don't check timestamps
+         fnm = NULL;
+       }
+      free (fnm);
+    }
+  return location;
+}
+
+bool
+DbeFile::find_in_pathmap (char *filename)
+{
+  Vector<pathmap_t*> *pathmaps = dbeSession->get_pathmaps ();
+  bool inPathMap = false;
+  if (strncmp (filename, NTXT ("./"), 2) == 0)
+    filename += 2;
+  for (int i = 0, sz = pathmaps ? pathmaps->size () : 0; i < sz; i++)
+    {
+      pathmap_t *pmp = pathmaps->fetch (i);
+      size_t len = strlen (pmp->old_prefix);
+      if (strncmp (pmp->old_prefix, filename, len) == 0
+         && (filename[len] == '/' || filename[len] == '\0'))
+       {
+         inPathMap = true;
+         if (find_in_directory (filename + len, pmp->new_prefix))
+           {
+             return inPathMap;
+           }
+       }
+    }
+  return inPathMap;
+}
+
+void
+DbeFile::find_in_archives (char *filename)
+{
+  for (int i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++)
+    {
+      ExpGroup *gr = dbeSession->expGroups->fetch (i1);
+      if (gr->founder)
+       {
+         char *nm = gr->founder->checkFileInArchive (filename, false);
+         if (nm)
+           {
+             find_file (nm);
+             if (location)
+               {
+                 sbuf.st_mtime = 0; // Don't check timestamps
+                 return;
+               }
+           }
+       }
+    }
+}
+
+void
+DbeFile::find_in_setpath (char *filename, Vector<char*> *searchPath)
+{
+  char *base = get_basename (filename);
+  for (int i = 0, sz = searchPath ? searchPath->size () : 0; i < sz; i++)
+    {
+      char *spath = searchPath->fetch (i);
+      // Check file in each experiment directory
+      if (streq (spath, "$") || streq (spath, NTXT ("$expts")))
+       {
+         // find only in founders and only LoadObj.
+         for (int i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++)
+           {
+             ExpGroup *gr = dbeSession->expGroups->fetch (i1);
+             char *exp_name = gr->founder->get_expt_name ();
+             if (gr->founder)
+               {
+                 if ((filetype & (F_JAVACLASS | F_JAVA_SOURCE)) != 0)
+                   {
+                     // Find with the package name
+                     if (find_in_directory (filename, exp_name))
+                        return;
+                   }
+                 if (find_in_directory (base, exp_name))
+                   return;
+               }
+           }
+         continue;
+       }
+      DbeFile *df = dbeSession->getDbeFile (spath, DbeFile::F_DIR_OR_JAR);
+      if (df->get_location () == NULL)
+       continue;
+      if ((filetype & (F_JAVACLASS | F_JAVA_SOURCE)) != 0)
+       {
+         if ((df->filetype & F_JAR_FILE) != 0)
+           {
+             if (find_in_jar_file (filename, df->get_jar_file ()))
+               {
+                 container = df;
+                 return;
+               }
+             continue;
+           }
+         else if ((df->filetype & F_DIRECTORY) != 0)
+           // Find with the package name
+           if (find_package_name (filename, spath))
+             return;
+       }
+      if ((df->filetype & F_DIRECTORY) != 0)
+       if (find_in_directory (base, df->get_location ()))
+         return;
+    }
+}
+
+void
+DbeFile::find_in_classpath (char *filename, Vector<DbeFile*> *classPath)
+{
+  for (int i = 0, sz = classPath ? classPath->size () : 0; i < sz; i++)
+    {
+      DbeFile *df = classPath->fetch (i);
+      if (df->get_location () == NULL)
+       continue;
+      if ((df->filetype & F_JAR_FILE) != 0)
+       {
+         if (find_in_jar_file (filename, df->get_jar_file ()))
+           {
+             container = df;
+             return;
+           }
+       }
+      else if ((df->filetype & F_DIRECTORY) != 0)
+       // Find with the package name
+       if (find_package_name (filename, df->get_name ()))
+         return;
+    }
+}
+
+struct stat64 *
+DbeFile::get_stat ()
+{
+  if (sbuf.st_atim.tv_sec == 0)
+    {
+      int st = check_access (get_location (false));
+      if (st == F_NOT_FOUND)
+       return NULL;
+    }
+  return &sbuf;
+}
+
+bool
+DbeFile::compare (DbeFile *df)
+{
+  if (df == NULL)
+    return false;
+  struct stat64 *st1 = get_stat ();
+  struct stat64 *st2 = df->get_stat ();
+  if (st1 == NULL || st2 == NULL)
+    return false;
+  if (st1->st_size != st2->st_size)
+    return false;
+  if (st1->st_mtim.tv_sec != st2->st_mtim.tv_sec)
+    return false;
+  return true;
+}
diff --git a/gprofng/src/DbeFile.h b/gprofng/src/DbeFile.h
new file mode 100644 (file)
index 0000000..abd7180
--- /dev/null
@@ -0,0 +1,103 @@
+/* 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 _DBE_FILE_H
+#define _DBE_FILE_H
+
+#include <fcntl.h>
+
+class DbeJarFile;
+class Experiment;
+template <class ITEM> class Vector;
+
+class DbeFile
+{
+public:
+
+  enum
+  {
+    F_NOT_FOUND     = 0,
+    F_FICTION       = 1,
+    F_LOADOBJ       = 2,
+    F_SOURCE        = 4,
+    F_JAVACLASS     = 8,
+    F_JAVA_SOURCE   = 16,
+    F_DOT_O         = 32,
+    F_DEBUG_FILE    = 64,
+    F_DOT_A_LIB     = 128,
+    F_DIR_OR_JAR    = 256,
+    F_DIRECTORY     = 512,
+    F_FILE          = 1024,
+    F_JAR_FILE      = 2048,
+    F_UNKNOWN       = 65536
+  };
+
+  DbeFile (const char *filename);
+  ~DbeFile ();
+
+  char *
+  get_name ()
+  {
+    return name;
+  };
+
+  bool
+  get_need_refind ()
+  {
+    return need_refind;
+  };
+
+  char *get_location (bool find_needed = true);
+  char *getResolvedPath ();
+  char *get_location_info ();
+  struct stat64 *get_stat ();
+  bool compare (DbeFile *df);
+  void set_need_refind (bool val);
+  void set_location (const char *filename);
+  int check_access (const char *filename);
+  char *find_file (const char *filename);
+  DbeFile *getJarDbeFile (char *fnm, int sym);
+  char *find_in_jar_file (const char *filename, DbeJarFile *jfile);
+  DbeJarFile *get_jar_file ();
+
+  bool inArchive;
+  int filetype;
+  struct stat64 sbuf;
+  DbeFile *container;
+  char *orig_location;
+  Experiment *experiment;
+
+protected:
+  static bool isJarOrZip (const char *fnm);
+  char *find_package_name (const char *filename, const char *dirname);
+  char *find_in_directory (const char *filename, const char *dirname);
+  bool find_in_pathmap (char *filename);
+  void find_in_archives (char *filename);
+  void find_in_setpath (char *filename, Vector<char*> *searchPath);
+  void find_in_classpath (char *filename, Vector<DbeFile*> *classPath);
+
+  char *name;
+  char *location;
+  char *location_info;
+  bool need_refind;
+  DbeJarFile *jarFile;
+};
+
+#endif /* _DBE_FILE_H */
diff --git a/gprofng/src/DbeJarFile.cc b/gprofng/src/DbeJarFile.cc
new file mode 100644 (file)
index 0000000..9029512
--- /dev/null
@@ -0,0 +1,505 @@
+/* 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 <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "zlib.h"
+#include "util.h"
+#include "DbeJarFile.h"
+#include "Data_window.h"
+#include "vec.h"
+
+static uint32_t
+get_u1 (unsigned char *b)
+{
+  return (uint32_t) ((b)[0]);
+}
+
+static uint32_t
+get_u2 (unsigned char *b)
+{
+  return (get_u1 (b + 1) << 8) | get_u1 (b);
+}
+
+static uint32_t
+get_u4 (unsigned char *b)
+{
+  return (get_u2 (b + 2) << 16) | get_u2 (b);
+}
+
+static uint64_t
+get_u8 (unsigned char *b)
+{
+  return (((uint64_t) get_u4 (b + 4)) << 32) | get_u4 (b);
+}
+
+enum
+{
+  END_CENT_DIR_SIZE     = 22,
+  LOC_FILE_HEADER_SIZE  = 30,
+  CENT_FILE_HEADER_SIZE = 46,
+  ZIP64_LOCATOR_SIZE    = 20,
+  ZIP64_CENT_DIR_SIZE   = 56,
+  ZIP_BUF_SIZE          = 65536
+};
+
+struct EndCentDir
+{
+  uint64_t count;
+  uint64_t size;
+  uint64_t offset;
+};
+
+class ZipEntry
+{
+public:
+
+  ZipEntry ()
+  {
+    name = NULL;
+    data_offset = 0;
+  }
+
+  ~ZipEntry ()
+  {
+    free (name);
+  }
+
+  int
+  compare (ZipEntry *ze)
+  {
+    return dbe_strcmp (name, ze->name);
+  }
+
+  char *name;       // entry name
+  int time;         // modification time
+  int64_t size;     // size of uncompressed data
+  int64_t csize;    // size of compressed data (zero if uncompressed)
+  uint32_t compressionMethod;
+  int64_t offset;   // offset of LOC header
+  int64_t data_offset;
+};
+
+static int
+cmp_names (const void *a, const void *b)
+{
+  ZipEntry *e1 = *((ZipEntry **) a);
+  ZipEntry *e2 = *((ZipEntry **) b);
+  return e1->compare (e2);
+}
+
+template<> void Vector<ZipEntry *>::dump (const char *msg)
+{
+  Dprintf (1, NTXT ("Vector<ZipEntry *> %s  [%lld]\n"), msg ? msg : NTXT (""), (long long) size ());
+  for (long i = 0, sz = size (); i < sz; i++)
+    {
+      ZipEntry *ze = get (i);
+      Dprintf (1, NTXT ("  %lld offset:%lld (0x%llx) size: %lld --> %lld %s\n"),
+              (long long) i, (long long) ze->offset, (long long) ze->offset,
+              (long long) ze->csize, (long long) ze->size, STR (ze->name));
+    }
+}
+
+DbeJarFile::DbeJarFile (const char *jarName)
+{
+  name = strdup (jarName);
+  fnames = NULL;
+  dwin = new Data_window (name);
+  get_entries ();
+}
+
+DbeJarFile::~DbeJarFile ()
+{
+  free (name);
+  delete fnames;
+}
+
+void
+DbeJarFile::get_entries ()
+{
+  Dprintf (DUMP_JAR_FILE, NTXT ("\nArchive: %s\n"), STR (name));
+  if (dwin->not_opened ())
+    {
+      append_msg (CMSG_ERROR, GTXT ("Cannot open file `%s'"), name);
+      return;
+    }
+  struct EndCentDir endCentDir;
+  if (get_EndCentDir (&endCentDir) == 0)
+    return;
+
+  if (endCentDir.count == 0)
+    {
+      append_msg (CMSG_WARN, GTXT ("No files in %s"), name);
+      return;
+    }
+  unsigned char *b = (unsigned char *) dwin->bind (endCentDir.offset, endCentDir.size);
+  if (b == NULL)
+    {
+      append_msg (CMSG_ERROR, GTXT ("%s: cannot read the central directory record"), name);
+      return;
+    }
+
+  fnames = new Vector<ZipEntry*>(endCentDir.count);
+  for (uint64_t i = 0, offset = endCentDir.offset, last = endCentDir.offset + endCentDir.size; i < endCentDir.count; i++)
+    {
+      if ((last - offset) < CENT_FILE_HEADER_SIZE)
+       {
+         append_msg (CMSG_ERROR, GTXT ("%s: cannot read the central file header (%lld (from %lld), offset=0x%016llx last=0x%016llx"),
+                     name, (long long) i, (long long) endCentDir.count, (long long) offset, (long long) last);
+         break;
+       }
+      b = (unsigned char *) dwin->bind (offset, CENT_FILE_HEADER_SIZE);
+      //  Central file header
+      //  Offset Bytes    Description
+      //     0     4   central file header signature = 0x02014b50
+      //     4     2   version made by
+      //     6     2   version needed to extract
+      //     8     2   general purpose bit flag
+      //    10     2   compression method
+      //    12     2   last mod file time
+      //    14     2   last mod file date
+      //    16     4   crc-32
+      //    20     4   compressed size
+      //    24     4   uncompressed size
+      //    28     2   file name length
+      //    30     2   extra field length
+      //    32     2   file comment length
+      //    34     2   disk number start
+      //    36     2   internal file attributes
+      //    38     4   external file attributes
+      //    42     4   relative offset of local header
+      //    46         file name (variable size)
+      //               extra field (variable size)
+      //               file comment (variable size)
+      uint32_t signature = get_u4 (b);
+      if (signature != 0x02014b50)
+       {
+         append_msg (CMSG_ERROR, GTXT ("%s: wrong header signature (%lld (total %lld), offset=0x%016llx last=0x%016llx"),
+                     name, (long long) i, (long long) endCentDir.count, (long long) offset, (long long) last);
+         break;
+       }
+      ZipEntry *ze = new ZipEntry ();
+      fnames->append (ze);
+      uint32_t name_len = get_u2 (b + 28);
+      uint32_t extra_len = get_u2 (b + 30);
+      uint32_t comment_len = get_u2 (b + 32);
+      ze->compressionMethod = get_u2 (b + 10);
+      ze->csize = get_u4 (b + 20);
+      ze->size = get_u4 (b + 24);
+      ze->offset = get_u4 (b + 42);
+      char *nm = (char *) dwin->bind (offset + 46, name_len);
+      if (nm)
+       {
+         ze->name = (char *) malloc (name_len + 1);
+         strncpy (ze->name, nm, name_len);
+         ze->name[name_len] = 0;
+       }
+      offset += CENT_FILE_HEADER_SIZE + name_len + extra_len + comment_len;
+    }
+  fnames->sort (cmp_names);
+  if (DUMP_JAR_FILE)
+    fnames->dump (get_basename (name));
+}
+
+int
+DbeJarFile::get_entry (const char *fname)
+{
+  if (fnames == NULL)
+    return -1;
+  ZipEntry zipEntry, *ze = &zipEntry;
+  ze->name = (char *) fname;
+  int ind = fnames->bisearch (0, -1, &ze, cmp_names);
+  ze->name = NULL;
+  return ind;
+}
+
+long long
+DbeJarFile::copy (char *toFileNname, int fromEntryNum)
+{
+  if (fromEntryNum < 0 || fromEntryNum >= VecSize (fnames))
+    return -1;
+  ZipEntry *ze = fnames->get (fromEntryNum);
+  if (ze->data_offset == 0)
+    {
+      //  Local file header
+      //  Offset Bytes    Description
+      //     0     4   local file header signature = 0x04034b50
+      //     4     2   version needed to extract
+      //     6     2   general purpose bit flag
+      //     8     2   compression method
+      //    10     2   last mod file time
+      //    12     2   last mod file date
+      //    14     4   crc-32
+      //    18     4   compressed size
+      //    22     4   uncompressed size
+      //    26     2   file name length
+      //    28     2   extra field length
+      //    30     2   file name (variable size)
+      //               extra field (variable size)
+      unsigned char *b = (unsigned char *) dwin->bind (ze->offset, LOC_FILE_HEADER_SIZE);
+      if (b == NULL)
+       {
+         append_msg (CMSG_ERROR,
+                GTXT ("%s: Cannot read a local file header (%s offset=0x%lld"),
+                name, STR (ze->name), (long long) ze->offset);
+         return -1;
+       }
+      uint32_t signature = get_u4 (b);
+      if (signature != 0x04034b50)
+       {
+         append_msg (CMSG_ERROR,
+                     GTXT ("%s: wrong local header signature ('%s' offset=%lld (0x%llx)"),
+                     name, STR (ze->name), (long long) ze->offset,
+                     (long long) ze->offset);
+         return -1;
+       }
+      ze->data_offset = ze->offset + LOC_FILE_HEADER_SIZE + get_u2 (b + 26) + get_u2 (b + 28);
+    }
+
+  if (ze->compressionMethod == 0)
+    {
+      int fd = open (toFileNname, O_CREAT | O_WRONLY | O_LARGEFILE, 0644);
+      if (fd == -1)
+       {
+         append_msg (CMSG_ERROR, GTXT ("Cannot create file %s (%s)"), toFileNname, STR (strerror (errno)));
+         return -1;
+       }
+      long long len = dwin->copy_to_file (fd, ze->data_offset, ze->size);
+      close (fd);
+      if (len != ze->size)
+       {
+         append_msg (CMSG_ERROR, GTXT ("%s: Cannot write %lld bytes (only %lld)"),
+                     toFileNname, (long long) ze->size, (long long) len);
+         unlink (toFileNname);
+         return -1;
+       }
+      return len;
+    }
+
+  unsigned char *b = (unsigned char *) dwin->bind (ze->data_offset, ze->csize);
+  if (b == NULL)
+    {
+      append_msg (CMSG_ERROR,
+                 GTXT ("%s: Cannot extract file %s (offset=0x%lld csize=%lld)"),
+                 name, STR (ze->name), (long long) ze->offset,
+                 (long long) ze->csize);
+      return -1;
+    }
+  z_stream strm;
+  strm.zalloc = Z_NULL;
+  strm.zfree = Z_NULL;
+  strm.opaque = Z_NULL;
+  strm.next_in = Z_NULL;
+  strm.avail_in = 0;
+  if (inflateInit2 (&strm, -MAX_WBITS) != Z_OK)
+    {
+      append_msg (CMSG_ERROR, GTXT ("%s: inflateInit2 failed (%s)"), STR (ze->name), STR (strm.msg));
+      return -1;
+    }
+  strm.avail_in = ze->csize;
+  strm.next_in = b;
+  int retval = ze->size;
+  unsigned char *buf = (unsigned char *) malloc (ze->size);
+  for (;;)
+    {
+      strm.next_out = buf;
+      strm.avail_out = ze->size;
+      int ret = inflate (&strm, Z_SYNC_FLUSH);
+      if ((ret == Z_NEED_DICT) || (ret == Z_DATA_ERROR) || (ret == Z_MEM_ERROR) || (ret == Z_STREAM_ERROR))
+       {
+         append_msg (CMSG_ERROR, GTXT ("%s: inflate('%s') error %d (%s)"), name, STR (ze->name), ret, STR (strm.msg));
+         retval = -1;
+         break;
+       }
+      if (strm.avail_out != 0)
+       break;
+    }
+  inflateEnd (&strm);
+  if (retval != -1)
+    {
+      int fd = open (toFileNname, O_CREAT | O_WRONLY | O_LARGEFILE, 0644);
+      if (fd == -1)
+       {
+         append_msg (CMSG_ERROR, GTXT ("Cannot create file %s (%s)"), toFileNname, STR (strerror (errno)));
+         retval = -1;
+       }
+      else
+       {
+         long long len = write (fd, buf, ze->size);
+         if (len != ze->size)
+           {
+             append_msg (CMSG_ERROR, GTXT ("%s: Cannot write %lld bytes (only %lld)"),
+                         toFileNname, (long long) strm.avail_out, (long long) len);
+             retval = -1;
+           }
+         close (fd);
+       }
+    }
+  free (buf);
+  return retval;
+}
+
+int
+DbeJarFile::get_EndCentDir (struct EndCentDir *endCentDir)
+{
+  int64_t fsize = dwin->get_fsize ();
+  int64_t sz = (fsize < ZIP_BUF_SIZE) ? fsize : ZIP_BUF_SIZE;
+
+  // Find the end of central directory record:
+  unsigned char *b = (unsigned char *) dwin->bind (fsize - sz, sz);
+  if (b == NULL)
+    {
+      append_msg (CMSG_ERROR, GTXT ("%s: cannot find the central directory record (fsize=%lld)"),
+                 name, (long long) fsize);
+      return 0;
+    }
+
+  //  End of central directory record:
+  //  Offset Bytes    Description
+  //     0     4    end of central directory signature = 0x06054b50
+  //     4     2    number of this disk
+  //     6     2    disk where central directory starts
+  //     8     2    number of central directory records on this disk
+  //    10     2    total number of central directory records
+  //    12     4    size of central directory(bytes)
+  //    16     4    offset of start of central directory, relative to start of archive
+  //    20     2    comment length(n)
+  //    22     n    comment
+
+  endCentDir->count = 0;
+  endCentDir->size = 0;
+  endCentDir->offset = 0;
+  int64_t ecdrOffset = fsize;
+  for (int64_t i = END_CENT_DIR_SIZE; i < sz; i++)
+    {
+      b = (unsigned char *) dwin->bind (fsize - i, END_CENT_DIR_SIZE);
+      if (b == NULL)
+       {
+         append_msg (CMSG_ERROR, GTXT ("%s: read failed (offset:0x%llx  bytes:%lld"),
+                     name, (long long) (fsize - i), (long long) END_CENT_DIR_SIZE);
+         break;
+       }
+      uint32_t signature = get_u4 (b);
+      if (signature == 0x06054b50)
+       {
+         int64_t len_comment = get_u2 (b + 20);
+         if (i != (len_comment + END_CENT_DIR_SIZE))
+           continue;
+         ecdrOffset = fsize - i;
+         endCentDir->count = get_u2 (b + 10);
+         endCentDir->size = get_u4 (b + 12);
+         endCentDir->offset = get_u4 (b + 16);
+         Dprintf (DUMP_JAR_FILE,
+                  "  Zip archive file size:              %10lld (0x%016llx)\n"
+                  "  end-cent-dir record offset:         %10lld (0x%016llx)\n"
+                  "  cent-dir offset:                    %10lld (0x%016llx)\n"
+                  "  cent-dir size:                      %10lld (0x%016llx)\n"
+                  "  cent-dir entries:                   %10lld\n",
+                  (long long) fsize, (long long) fsize,
+                  (long long) ecdrOffset, (long long) ecdrOffset,
+                  (long long) endCentDir->offset, (long long) endCentDir->offset,
+                  (long long) endCentDir->size, (long long) endCentDir->size,
+                  (long long) endCentDir->count);
+         break;
+       }
+    }
+  if (ecdrOffset == fsize)
+    {
+      append_msg (CMSG_ERROR,
+                 GTXT ("%s: cannot find the central directory record"), name);
+      return 0;
+    }
+  if (endCentDir->count == 0xffff || endCentDir->offset == 0xffffffff
+      || endCentDir->size == 0xffffffff)
+    {
+      // Zip64 format:
+      //      Zip64 end of central directory record
+      //      Zip64 end of central directory locator  ( Can be absent )
+      //      End of central directory record
+      b = (unsigned char *) dwin->bind (ecdrOffset - ZIP64_LOCATOR_SIZE,
+                                       ZIP64_LOCATOR_SIZE);
+      if (b == NULL)
+       {
+         append_msg (CMSG_ERROR,
+            GTXT ("%s: cannot find the Zip64 central directory record"), name);
+         return 0;
+       }
+      uint32_t signature = get_u4 (b);
+      if (signature == 0x07064b50)
+       { // Get an offset from the Zip64 cent-dir locator
+         //  Zip64 end of central directory locator
+         //  Offset Bytes    Description
+         //     0     4    Zip64 end of central dir locator signature = 0x07064b50
+         //     4     4    number of the disk with the start of the zip64 end of central directory
+         //     8     8    relative offset of the Zip64 end of central directory record
+         //    12     4    total number of disks
+         Dprintf (DUMP_JAR_FILE, "    cent-dir locator offset           %10lld (0x%016llx)\n",
+                  (long long) (ecdrOffset - ZIP64_LOCATOR_SIZE), (long long) (ecdrOffset - ZIP64_LOCATOR_SIZE));
+         ecdrOffset = get_u8 (b + 8);
+       }
+      else   // the Zip64 end of central directory locator is absent
+       ecdrOffset -= ZIP64_CENT_DIR_SIZE;
+      Dprintf (DUMP_JAR_FILE, NTXT ("  Zip64 end-cent-dir record offset:   %10lld (0x%016llx)\n"),
+              (long long) ecdrOffset, (long long) ecdrOffset);
+
+      b = (unsigned char *) dwin->bind (ecdrOffset, ZIP64_CENT_DIR_SIZE);
+      if (b == NULL)
+       {
+         append_msg (CMSG_ERROR,
+            GTXT ("%s: cannot find the Zip64 central directory record"), name);
+         return 0;
+       }
+      //  Zip64 end of central directory record
+      //  Offset Bytes    Description
+      //     0     4    Zip64 end of central dir signature = 0x06064b50
+      //     4     8    size of zip64 end of central directory record
+      //    12     2    version made by
+      //    14     2    version needed to extract
+      //    16     4    number of this disk
+      //    20     4    number of the disk with the start of the central directory
+      //    24     8    total number of entries in the central directory on this disk
+      //    32     8    total number of entries in the central directory
+      //    40     8    size of the central directory
+      //    48     8    offset of start of centraldirectory with respect to the starting disk number
+      //    56          Zip64 extensible data sector (variable size)
+      signature = get_u4 (b);
+      if (signature != 0x06064b50)
+       {
+         append_msg (CMSG_ERROR, GTXT ("%s: cannot find the Zip64 central directory record"), name);
+         return 0;
+       }
+      endCentDir->count = get_u8 (b + 32);
+      endCentDir->size = get_u8 (b + 40);
+      endCentDir->offset = get_u8 (b + 48);
+      Dprintf (DUMP_JAR_FILE,
+              NTXT ("  cent-dir offset:                    %10lld (0x%016llx)\n"
+                    "  cent-dir size:                      %10lld (0x%016llx)\n"
+                    "  cent-dir entries:                   %10lld\n"),
+              (long long) endCentDir->offset, (long long) endCentDir->offset,
+              (long long) endCentDir->size, (long long) endCentDir->size,
+              (long long) endCentDir->count);
+    }
+  return 1;
+}
+
diff --git a/gprofng/src/DbeJarFile.h b/gprofng/src/DbeJarFile.h
new file mode 100644 (file)
index 0000000..f0b4f7b
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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 _DBE_JAR_FILE_H
+#define _DBE_JAR_FILE_H
+
+#include "Emsg.h"
+
+class Data_window;
+class ZipEntry;
+template <class ITEM> class Vector;
+
+class DbeJarFile : public DbeMessages
+{
+public:
+  DbeJarFile (const char *jarName);
+  ~DbeJarFile ();
+
+  int get_entry (const char *fname);
+  long long copy (char *toFileNname, int fromEntryNum);
+
+private:
+  void get_entries ();
+  int get_EndCentDir (struct EndCentDir *endCentDir);
+  char *name;
+  Vector<ZipEntry *> *fnames;
+  Data_window *dwin;
+};
+#endif /* _DBE_JAR_FILE_H */
diff --git a/gprofng/src/DbeLinkList.h b/gprofng/src/DbeLinkList.h
new file mode 100644 (file)
index 0000000..760cc67
--- /dev/null
@@ -0,0 +1,73 @@
+/* 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 _DbeLinkList_h
+#define _DbeLinkList_h
+
+template <typename ITEM> class DbeLinkList
+{
+public:
+
+  DbeLinkList (ITEM _item)
+  {
+    item = _item;
+    next = NULL;
+  };
+
+  ~DbeLinkList () { };
+
+  ITEM
+  get_item ()
+  {
+    return item;
+  }
+
+  DbeLinkList<ITEM> *
+  get_next ()
+  {
+    return next;
+  }
+
+  void
+  set_next (DbeLinkList<ITEM> *p)
+  {
+    next = p;
+  }
+
+  void
+  destroy (bool deleteItem = false)
+  {
+    for (DbeLinkList<ITEM> *p = next; p;)
+      {
+       DbeLinkList<ITEM> *p1 = p->get_next ();
+       if (deleteItem)
+         delete p->get_item ();
+       delete p;
+       p = p1;
+      }
+    next = NULL;
+  }
+
+private:
+  ITEM item;
+  DbeLinkList<ITEM> *next;
+};
+
+#endif /* _DbeLinkList_h */
diff --git a/gprofng/src/DbeLock.cc b/gprofng/src/DbeLock.cc
new file mode 100644 (file)
index 0000000..14a1eb3
--- /dev/null
@@ -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 "DbeLock.h"
+
+DbeLock::DbeLock ()
+{
+  pthread_mutex_init (&lock, NULL);
+}
+
+DbeLock::~DbeLock () { }
+
+void
+DbeLock::aquireLock ()
+{
+  pthread_mutex_lock (&lock);
+}
+
+void
+DbeLock::releaseLock ()
+{
+  pthread_mutex_unlock (&lock);
+}
diff --git a/gprofng/src/DbeLock.h b/gprofng/src/DbeLock.h
new file mode 100644 (file)
index 0000000..28dfb6e
--- /dev/null
@@ -0,0 +1,38 @@
+/* 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 _DBE_LOCK_H
+#define _DBE_LOCK_H
+
+#include <pthread.h>
+
+class DbeLock
+{
+public:
+  DbeLock ();
+  ~DbeLock ();
+  void aquireLock ();
+  void releaseLock ();
+
+private:
+  pthread_mutex_t lock;
+};
+
+#endif /* _DBE_LOCK_H */
diff --git a/gprofng/src/DbeSession.cc b/gprofng/src/DbeSession.cc
new file mode 100644 (file)
index 0000000..4370114
--- /dev/null
@@ -0,0 +1,3527 @@
+/* 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 <ctype.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/param.h>
+
+#include "util.h"
+#include "Application.h"
+#include "Experiment.h"
+#include "ExpGroup.h"
+#include "Expression.h"
+#include "DataObject.h"
+#include "Elf.h"
+#include "Function.h"
+#include "DbeSession.h"
+#include "LoadObject.h"
+#include "DbeSyncMap.h"
+#include "DbeThread.h"
+#include "ClassFile.h"
+#include "IndexObject.h"
+#include "PathTree.h"
+#include "Print.h"
+#include "QLParser.tab.hh"
+#include "DbeView.h"
+#include "MemorySpace.h"
+#include "Module.h"
+#include "SourceFile.h"
+#include "StringBuilder.h"
+#include "BaseMetric.h"
+#include "BaseMetricTreeNode.h"
+#include "Command.h"
+#include "UserLabel.h"
+#include "StringMap.h"
+#include "DbeFile.h"
+#include "DbeJarFile.h"
+#include "IOActivity.h"
+#include "HeapActivity.h"
+
+// This is a universal List structure to organize objects
+// of various types, even if different.
+struct List
+{
+  List *next;
+  void *val;
+};
+
+struct Countable
+{
+  Countable (void *_item)
+  {
+    item = _item;
+    ref_count = 0;
+  }
+
+  void *item;
+  int ref_count;
+};
+
+Platform_t DbeSession::platform =
+#if ARCH(SPARC)
+       Sparc;
+#elif ARCH(Aarch64)
+       Aarch64;
+#else   // ARCH(Intel)
+       Intel;
+#endif
+
+// This constant determines the size of the data object name hash table.
+static const int HTableSize         = 8192;
+static int DEFAULT_TINY_THRESHOLD   = -1;
+
+unsigned int mpmt_debug_opt = 0;
+DbeSession *dbeSession = NULL;
+
+DbeSession::DbeSession (Settings *_settings, bool _ipc_mode, bool _rdt_mode)
+{
+  dbeSession = this;
+  ipc_mode = _ipc_mode;
+  rdt_mode = _rdt_mode;
+  settings = new Settings (_settings);
+  views = new Vector<DbeView*>;
+  exps = new Vector<Experiment*>;
+  lobjs = new Vector<LoadObject*>;
+  objs = new Vector<Histable*>;
+  dobjs = new Vector<DataObject*>;
+  metrics = new Vector<Countable*>;
+  reg_metrics = new Vector<BaseMetric*>;
+  hwcentries = NULL;
+  reg_metrics_tree = NULL; // BaseMetric() requires DbeSession::ql_parse
+  idxobjs = new Vector<HashMap<uint64_t, Histable*>*>;
+  tmp_files = new Vector<char*>;
+  search_path = new Vector<char*>;
+  classpath = new Vector<char*>;
+  classpath_df = NULL;
+  expGroups = new Vector<ExpGroup*>;
+  sourcesMap = new HashMap<char*, SourceFile*>;
+  sources = new Vector<SourceFile*>;
+  comp_lobjs = new HashMap<char*, LoadObject*>;
+  comp_dbelines = new HashMap<char*, DbeLine*>;
+  comp_sources = new HashMap<char*, SourceFile*>;
+  loadObjMap = new DbeSyncMap<LoadObject>;
+  f_special = new Vector<Function*>(LastSpecialFunction);
+  omp_functions = new Vector<Function*>(OMP_LAST_STATE);
+  interactive = false;
+  lib_visibility_used = false;
+
+  // Define all known property names
+  propNames = new Vector<PropDescr*>;
+  propNames_name_store (PROP_NONE, NTXT (""));
+  propNames_name_store (PROP_ATSTAMP, NTXT ("ATSTAMP"));
+  propNames_name_store (PROP_ETSTAMP, NTXT ("ETSTAMP"));
+  propNames_name_store (PROP_TSTAMP, NTXT ("TSTAMP"));
+  propNames_name_store (PROP_THRID, NTXT ("THRID"));
+  propNames_name_store (PROP_LWPID, NTXT ("LWPID"));
+  propNames_name_store (PROP_CPUID, NTXT ("CPUID"));
+  propNames_name_store (PROP_FRINFO, NTXT ("FRINFO"));
+  propNames_name_store (PROP_EVT_TIME, NTXT ("EVT_TIME"));
+
+  // Samples
+  propNames_name_store (PROP_SMPLOBJ, NTXT ("SMPLOBJ"));
+  propNames_name_store (PROP_SAMPLE, NTXT ("SAMPLE"));
+
+  // GCEvents
+  propNames_name_store (PROP_GCEVENTOBJ, NTXT ("GCEVENTOBJ"));
+  propNames_name_store (PROP_GCEVENT, NTXT ("GCEVENT"));
+
+  // Metadata used by some packet types
+  propNames_name_store (PROP_VOIDP_OBJ, NTXT ("VOIDP_OBJ"),
+                       NULL, TYPE_UINT64, DDFLAG_NOSHOW);
+
+  // Clock profiling properties
+  propNames_name_store (PROP_UCPU, NTXT ("UCPU"));
+  propNames_name_store (PROP_SCPU, NTXT ("SCPU"));
+  propNames_name_store (PROP_TRAP, NTXT ("TRAP"));
+  propNames_name_store (PROP_TFLT, NTXT ("TFLT"));
+  propNames_name_store (PROP_DFLT, NTXT ("DFLT"));
+  propNames_name_store (PROP_KFLT, NTXT ("KFLT"));
+  propNames_name_store (PROP_ULCK, NTXT ("ULCK"));
+  propNames_name_store (PROP_TSLP, NTXT ("TSLP"));
+  propNames_name_store (PROP_WCPU, NTXT ("WCPU"));
+  propNames_name_store (PROP_TSTP, NTXT ("TSTP"));
+
+  propNames_name_store (PROP_MSTATE, NTXT ("MSTATE"));
+  propNames_name_store (PROP_NTICK, NTXT ("NTICK"));
+  propNames_name_store (PROP_OMPSTATE, NTXT ("OMPSTATE"));
+
+  // Synchronization tracing properties
+  propNames_name_store (PROP_SRQST, NTXT ("SRQST"));
+  propNames_name_store (PROP_SOBJ, NTXT ("SOBJ"));
+
+  // Hardware counter profiling properties
+  propNames_name_store (PROP_HWCTAG, NTXT ("HWCTAG"));
+  propNames_name_store (PROP_HWCINT, NTXT ("HWCINT"));
+  propNames_name_store (PROP_VADDR, NTXT ("VADDR"));
+  propNames_name_store (PROP_PADDR, NTXT ("PADDR"));
+  propNames_name_store (PROP_VIRTPC, NTXT ("VIRTPC"));
+  propNames_name_store (PROP_PHYSPC, NTXT ("PHYSPC"));
+  propNames_name_store (PROP_LWP_LGRP_HOME, NTXT ("LWP_LGRP_HOME"));
+  propNames_name_store (PROP_PS_LGRP_HOME, NTXT ("PS_LGRP_HOME"));
+  propNames_name_store (PROP_EA_PAGESIZE, NTXT ("EA_PAGESIZE"));
+  propNames_name_store (PROP_EA_LGRP, NTXT ("EA_LGRP"));
+  propNames_name_store (PROP_PC_PAGESIZE, NTXT ("PC_PAGESIZE"));
+  propNames_name_store (PROP_PC_LGRP, NTXT ("PC_LGRP"));
+  propNames_name_store (PROP_HWCDOBJ, NTXT ("HWCDOBJ"));
+  propNames_name_store (PROP_MEM_LAT, NTXT ("MEM_LAT"));
+  propNames_name_store (PROP_MEM_SRC, NTXT ("MEM_SRC"));
+
+  // Heap tracing properties
+  propNames_name_store (PROP_HTYPE, NTXT ("HTYPE"));
+  propNames_name_store (PROP_HSIZE, NTXT ("HSIZE"));
+  propNames_name_store (PROP_HVADDR, NTXT ("HVADDR"));
+  propNames_name_store (PROP_HOVADDR, NTXT ("HOVADDR"));
+  propNames_name_store (PROP_HLEAKED, NTXT ("HLEAKED"),
+                       GTXT ("Leaked bytes"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_HMEM_USAGE, NTXT ("HMEM_USAGE"));
+  propNames_name_store (PROP_HFREED, NTXT ("HFREED"),
+                       GTXT ("Freed bytes"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_HCUR_ALLOCS, NTXT ("HCUR_ALLOCS"),
+                       GTXT ("Current allocations"), TYPE_INT64, 0);
+  propNames_name_store (PROP_HCUR_NET_ALLOC, NTXT ("HCUR_NET_ALLOC"),
+                       NULL, TYPE_INT64, DDFLAG_NOSHOW);
+  propNames_name_store (PROP_HCUR_LEAKS, NTXT ("HCUR_LEAKS"),
+                       GTXT ("Current leaks"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_DDSCR_LNK, NTXT ("DDSCR_LNK"),
+                       NULL, TYPE_UINT64, DDFLAG_NOSHOW);
+
+  // IO tracing properties
+  propNames_name_store (PROP_IOTYPE, NTXT ("IOTYPE"));
+  propNames_name_store (PROP_IOFD, NTXT ("IOFD"));
+  propNames_name_store (PROP_IONBYTE, NTXT ("IONBYTE"));
+  propNames_name_store (PROP_IORQST, NTXT ("IORQST"));
+  propNames_name_store (PROP_IOOFD, NTXT ("IOOFD"));
+  propNames_name_store (PROP_IOFNAME, NTXT ("IOFNAME"));
+  propNames_name_store (PROP_IOVFD, NTXT ("IOVFD"));
+  propNames_name_store (PROP_IOFSTYPE, NTXT ("IOFSTYPE"));
+
+  // omptrace raw properties
+  propNames_name_store (PROP_CPRID, NTXT ("CPRID"));
+  propNames_name_store (PROP_PPRID, NTXT ("PPRID"));
+  propNames_name_store (PROP_TSKID, NTXT ("TSKID"));
+  propNames_name_store (PROP_PTSKID, NTXT ("PTSKID"));
+  propNames_name_store (PROP_PRPC, NTXT ("PRPC"));
+
+  // Data race detection properties
+  propNames_name_store (PROP_RID, NTXT ("RID"));
+  propNames_name_store (PROP_RTYPE, NTXT ("RTYPE"));
+  propNames_name_store (PROP_LEAFPC, NTXT ("LEAFPC"));
+  propNames_name_store (PROP_RVADDR, NTXT ("RVADDR"));
+  propNames_name_store (PROP_RCNT, NTXT ("RCNT"));
+
+  // Deadlock detection properties
+  propNames_name_store (PROP_DID, NTXT ("DID"));
+  propNames_name_store (PROP_DLTYPE, NTXT ("DLTYPE"));
+  propNames_name_store (PROP_DTYPE, NTXT ("DTYPE"));
+  propNames_name_store (PROP_DVADDR, NTXT ("DVADDR"));
+
+  // Synthetic properties (queries only)
+  propNames_name_store (PROP_STACK, NTXT ("STACK"));
+  propNames_name_store (PROP_MSTACK, NTXT ("MSTACK"));
+  propNames_name_store (PROP_USTACK, NTXT ("USTACK"));
+  propNames_name_store (PROP_XSTACK, NTXT ("XSTACK"));
+  propNames_name_store (PROP_HSTACK, NTXT ("HSTACK"));
+  propNames_name_store (PROP_STACKID, NTXT ("STACKID"));
+  //propNames_name_store( PROP_CPRID,   NTXT("CPRID") );
+  //propNames_name_store( PROP_TSKID,   NTXT("TSKID") );
+  propNames_name_store (PROP_JTHREAD, NTXT ("JTHREAD"),
+                       GTXT ("Java thread number"), TYPE_UINT64, 0);
+
+  propNames_name_store (PROP_LEAF, NTXT ("LEAF"));
+  propNames_name_store (PROP_DOBJ, NTXT ("DOBJ"));
+  propNames_name_store (PROP_SAMPLE_MAP, NTXT ("SAMPLE_MAP"));
+  propNames_name_store (PROP_GCEVENT_MAP, NTXT ("GCEVENT_MAP"));
+  propNames_name_store (PROP_PID, NTXT ("PID"),
+                       GTXT ("Process id"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_EXPID, NTXT ("EXPID"),
+                       GTXT ("Experiment id"), TYPE_UINT64, DDFLAG_NOSHOW);
+  propNames_name_store (PROP_EXPID_CMP, NTXT ("EXPID_CMP"),
+                       GTXT ("Comparable Experiment Id"), TYPE_UINT64,
+                       DDFLAG_NOSHOW); //YXXX find better description
+  propNames_name_store (PROP_EXPGRID, NTXT ("EXPGRID"),
+                       GTXT ("Comparison Group id"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_PARREG, NTXT ("PARREG"));
+  propNames_name_store (PROP_TSTAMP_LO, NTXT ("TSTAMP_LO"),
+                       GTXT ("Start Timestamp (nanoseconds)"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_TSTAMP_HI, NTXT ("TSTAMP_HI"),
+                       GTXT ("End Timestamp (nanoseconds)"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_TSTAMP2, NTXT ("TSTAMP2"),
+                       GTXT ("End Timestamp (nanoseconds)"), TYPE_UINT64,
+                       DDFLAG_NOSHOW);
+  propNames_name_store (PROP_FREQ_MHZ, NTXT ("FREQ_MHZ"),
+                       GTXT ("CPU Frequency, MHz"), TYPE_UINT32, 0);
+  propNames_name_store (PROP_NTICK_USEC, NTXT ("NTICK_USEC"),
+                       GTXT ("Clock Profiling Interval, Microseconds"),
+                       TYPE_UINT64, 0);
+
+  propNames_name_store (PROP_IOHEAPBYTES, NTXT ("IOHEAPBYTES"));
+
+  propNames_name_store (PROP_STACKL, NTXT ("STACKL"));
+  propNames_name_store (PROP_MSTACKL, NTXT ("MSTACKL"));
+  propNames_name_store (PROP_USTACKL, NTXT ("USTACKL"));
+  propNames_name_store (PROP_XSTACKL, NTXT ("XSTACKL"));
+
+  propNames_name_store (PROP_STACKI, NTXT ("STACKI"));
+  propNames_name_store (PROP_MSTACKI, NTXT ("MSTACKI"));
+  propNames_name_store (PROP_USTACKI, NTXT ("USTACKI"));
+  propNames_name_store (PROP_XSTACKI, NTXT ("XSTACKI"));
+
+  // Make sure predefined names are not used for dynamic properties
+  propNames_name_store (PROP_LAST, NTXT (""));
+
+  localized_SP_UNKNOWN_NAME = GTXT ("(unknown)");
+
+  // define Index objects
+  dyn_indxobj = new Vector<IndexObjType_t*>();
+  dyn_indxobj_indx = 0;
+  char *s = dbe_sprintf (NTXT ("((EXPID_CMP<<%llu) | THRID)"),
+                        (unsigned long long) IndexObject::INDXOBJ_EXPID_SHIFT);
+  indxobj_define (NTXT ("Threads"), GTXT ("Threads"), s, NULL, NULL);
+  free (s);
+  indxobj_define (NTXT ("CPUs"), GTXT ("CPUs"), NTXT ("(CPUID)"), NULL, NULL);
+  indxobj_define (NTXT ("Samples"), GTXT ("Samples"), NTXT ("(SAMPLE_MAP)"),
+                 NULL, NULL);
+  indxobj_define (NTXT ("GCEvents"), GTXT ("GCEvents"), NTXT ("(GCEVENT_MAP)"),
+                 NULL, NULL);
+  indxobj_define (NTXT ("Seconds"), GTXT ("Seconds"),
+                 NTXT ("(TSTAMP/1000000000)"), NULL, NULL);
+  indxobj_define (NTXT ("Processes"), GTXT ("Processes"), NTXT ("(EXPID_CMP)"),
+                 NULL, NULL);
+  s = dbe_sprintf (NTXT ("((EXPGRID<<%llu) | (EXPID<<%llu))"),
+                  (unsigned long long) IndexObject::INDXOBJ_EXPGRID_SHIFT,
+                  (unsigned long long) IndexObject::INDXOBJ_EXPID_SHIFT);
+  indxobj_define (NTXT ("Experiment_IDs"), GTXT ("Experiment_IDs"), s, NULL, NULL);
+  free (s);
+  indxobj_define (NTXT ("Datasize"), GTXT ("Datasize"),
+                 "(IOHEAPBYTES==0?0:"
+                 "((IOHEAPBYTES<=(1<<0)?(1<<0):"
+                 "((IOHEAPBYTES<=(1<<2)?(1<<2):"
+                 "((IOHEAPBYTES<=(1<<4)?(1<<4):"
+                 "((IOHEAPBYTES<=(1<<6)?(1<<6):"
+                 "((IOHEAPBYTES<=(1<<8)?(1<<8):"
+                 "((IOHEAPBYTES<=(1<<10)?(1<<10):"
+                 "((IOHEAPBYTES<=(1<<12)?(1<<12):"
+                 "((IOHEAPBYTES<=(1<<14)?(1<<14):"
+                 "((IOHEAPBYTES<=(1<<16)?(1<<16):"
+                 "((IOHEAPBYTES<=(1<<18)?(1<<18):"
+                 "((IOHEAPBYTES<=(1<<20)?(1<<20):"
+                 "((IOHEAPBYTES<=(1<<22)?(1<<22):"
+                 "((IOHEAPBYTES<=(1<<24)?(1<<24):"
+                 "((IOHEAPBYTES<=(1<<26)?(1<<26):"
+                 "((IOHEAPBYTES<=(1<<28)?(1<<28):"
+                 "((IOHEAPBYTES<=(1<<30)?(1<<30):"
+                 "((IOHEAPBYTES<=(1<<32)?(1<<32):"
+                 "((IOHEAPBYTES<=(1<<34)?(1<<34):"
+                 "((IOHEAPBYTES<=(1<<36)?(1<<36):"
+                 "((IOHEAPBYTES<=(1<<38)?(1<<38):"
+                 "((IOHEAPBYTES<=(1<<40)?(1<<40):"
+                 "((IOHEAPBYTES<=(1<<42)?(1<<42):"
+                 "((IOHEAPBYTES<=(1<<44)?(1<<44):"
+                 "((IOHEAPBYTES<=(1<<46)?(1<<46):"
+                 "((IOHEAPBYTES<=(1<<48)?(1<<48):"
+                 "((IOHEAPBYTES<=(1<<50)?(1<<50):"
+                 "(IOHEAPBYTES==-1?-1:(1<<50|1)"
+                 "))))))))))))))))))))))))))))))))))))))))))))))))))))))",
+                 NULL, NULL);
+  indxobj_define (NTXT ("Duration"), GTXT ("Duration"),
+                 "((TSTAMP_HI-TSTAMP_LO)==0?0:"
+                 "(((TSTAMP_HI-TSTAMP_LO)<=1000?1000:"
+                 "(((TSTAMP_HI-TSTAMP_LO)<=10000?10000:"
+                 "(((TSTAMP_HI-TSTAMP_LO)<=100000?100000:"
+                 "(((TSTAMP_HI-TSTAMP_LO)<=1000000?1000000:"
+                 "(((TSTAMP_HI-TSTAMP_LO)<=10000000?10000000:"
+                 "(((TSTAMP_HI-TSTAMP_LO)<=100000000?100000000:"
+                 "(((TSTAMP_HI-TSTAMP_LO)<=1000000000?1000000000:"
+                 "(((TSTAMP_HI-TSTAMP_LO)<=10000000000?10000000000:"
+                 "(((TSTAMP_HI-TSTAMP_LO)<=100000000000?100000000000:"
+                 "(((TSTAMP_HI-TSTAMP_LO)<=1000000000000?1000000000000:"
+                 "(((TSTAMP_HI-TSTAMP_LO)<=10000000000000?10000000000000:"
+                 "(10000000000001))))))))))))))))))))))))", NULL, NULL);
+  dyn_indxobj_indx_fixed = dyn_indxobj_indx;
+  Elf::elf_init ();
+  defExpName = NULL;
+  mach_model_loaded = NULL;
+  tmp_dir_name = NULL;
+  settings->read_rc (ipc_mode || rdt_mode);
+
+  init ();
+}
+
+DbeSession::~DbeSession ()
+{
+  Destroy (views);
+  Destroy (exps);
+  Destroy (dobjs);
+  Destroy (metrics);
+  Destroy (search_path);
+  Destroy (classpath);
+  Destroy (propNames);
+  Destroy (expGroups);
+  Destroy (userLabels);
+  if (hwcentries)
+    {
+      for (long i = 0, sz = hwcentries->size (); i < sz; i++)
+       {
+         Hwcentry *h = hwcentries->get (i);
+         free (h->int_name);
+         free (h->name);
+         delete h;
+       }
+      delete hwcentries;
+    }
+
+  if (idxobjs)
+    {
+      for (int i = 0; i < idxobjs->size (); ++i)
+       {
+         HashMap<uint64_t, Histable*> *hMap = idxobjs->get (i);
+         if (hMap)
+           {
+             hMap->values ()->destroy ();
+             delete hMap;
+           }
+       }
+      delete idxobjs;
+    }
+
+  for (int i = 0; i < HTableSize; i++)
+    {
+      List *list = dnameHTable[i];
+      while (list)
+       {
+         List *tmp = list;
+         list = list->next;
+         delete tmp;
+       }
+    }
+  delete[] dnameHTable;
+  delete classpath_df;
+  Destroy (objs);
+  Destroy (reg_metrics);
+  Destroy (dyn_indxobj);
+  delete lobjs;
+  delete f_special;
+  destroy_map (DbeFile *, dbeFiles);
+  destroy_map (DbeJarFile *, dbeJarFiles);
+  delete loadObjMap;
+  delete omp_functions;
+  delete sourcesMap;
+  delete sources;
+  delete comp_lobjs;
+  delete comp_dbelines;
+  delete comp_sources;
+  delete reg_metrics_tree;
+  delete settings;
+  free (mach_model_loaded);
+
+  if (defExpName != NULL)
+    {
+      StringBuilder *sb = new StringBuilder ();
+      sb->append (NTXT ("/bin/rm -rf "));
+      sb->append (defExpName);
+      char *cmd = sb->toString ();
+      system (cmd);
+      free (cmd);
+      delete sb;
+      free (defExpName);
+    }
+  unlink_tmp_files ();
+  delete tmp_files;
+  dbeSession = NULL;
+}
+
+void
+DbeSession::unlink_tmp_files ()
+{
+  if (tmp_files)
+    {
+      for (int i = 0, sz = tmp_files->size (); i < sz; i++)
+       unlink (tmp_files->fetch (i));
+      tmp_files->destroy ();
+      delete tmp_files;
+      tmp_files = NULL;
+    }
+  if (tmp_dir_name)
+    {
+      char *cmd = dbe_sprintf (NTXT ("/bin/rm -rf %s"), tmp_dir_name);
+      system (cmd);
+      free (cmd);
+      free (tmp_dir_name);
+      tmp_dir_name = NULL;
+    }
+}
+
+char *
+DbeSession::get_tmp_file_name (const char *nm, bool for_java)
+{
+  if (tmp_dir_name == NULL)
+    {
+      tmp_dir_name = dbe_sprintf (NTXT ("/tmp/analyzer.%llu.%lld"),
+                        (unsigned long long) getuid (), (long long) getpid ());
+      mkdir (tmp_dir_name, S_IRWXU);
+    }
+  char *fnm = dbe_sprintf (NTXT ("%s/%s"), tmp_dir_name, nm);
+  if (for_java)
+    for (char *s = fnm + strlen (tmp_dir_name) + 1; *s; s++)
+      if (*s == '/')
+       *s = '.';
+  return fnm;
+}
+
+void
+DbeSession::init ()
+{
+  user_exp_id_counter = 0;
+  status_ompavail = 0;
+  archive_mode = 0;
+
+#if DEBUG
+  char *s = getenv (NTXT ("MPMT_DEBUG"));
+  if (s)
+    mpmt_debug_opt = atoi (s);
+#endif /* DEBUG */
+  dbeFiles = new StringMap<DbeFile*>();
+  dbeJarFiles = new StringMap<DbeJarFile*>(128, 128);
+
+  // set up the initial (after .rc file reading) search path
+  set_search_path (settings->str_search_path, true);
+  userLabels = NULL;
+
+  // Preset all objects as they may reuse each other
+  lo_unknown = NULL;
+  f_unknown = NULL;
+  j_unknown = NULL;
+  lo_total = NULL;
+  sf_unknown = NULL;
+  f_total = NULL;
+  f_jvm = NULL;
+  d_total = NULL;
+  d_scalars = NULL;
+  d_unknown = NULL;
+  expGroups->destroy ();
+  f_special->reset ();
+  for (int i = 0; i < LastSpecialFunction; i++)
+    f_special->append (NULL);
+
+  lo_omp = NULL;
+  omp_functions->reset ();
+  for (int i = 0; i < OMP_LAST_STATE; i++)
+    omp_functions->append (NULL);
+
+  // make sure the metric list is initialized
+  register_metric (Metric::SIZES);
+  register_metric (Metric::ADDRESS);
+  register_metric (Metric::ONAME);
+
+  // This is needed only to maintain loadobject id's
+  // for <Total> and <Unknown> in tests
+  (void) get_Unknown_LoadObject ();
+  (void) get_Total_LoadObject ();
+
+  // Create the data object name hash table.
+  dnameHTable = new List*[HTableSize];
+  for (int i = 0; i < HTableSize; i++)
+    dnameHTable[i] = NULL;
+
+  d_total = createDataObject ();
+  d_total->set_name (NTXT ("<Total>"));
+
+  // XXXX <Scalars> only appropriate for Program/Data-oriented analyses
+  d_scalars = createDataObject ();
+  d_scalars->set_name (GTXT ("<Scalars>"));
+
+  d_unknown = createDataObject ();
+  d_unknown->set_name (GTXT ("<Unknown>"));
+
+  // assign d_unknown's children so data_olayout has consistent sorting
+  for (unsigned pp_code = 1; pp_code < NUM_ABS_PP_CODES + 2; pp_code++)
+    {
+      char *errcode;
+      DataObject* dobj = createDataObject ();
+      switch (pp_code)
+       {
+       case NUM_ABS_PP_CODES + 1:
+         errcode = PTXT (DOBJ_UNDETERMINED);
+         break;
+       case NUM_ABS_PP_CODES:
+         errcode = PTXT (DOBJ_UNSPECIFIED);
+         break;
+       case NUM_ABS_PP_CODES - 1:
+         errcode = PTXT (DOBJ_UNIDENTIFIED);
+         break;
+       default:
+         errcode = PTXT (ABS_PP_CODES[pp_code]);
+       }
+      dobj->parent = d_unknown;
+      dobj->set_dobjname (errcode, NULL); // dobj->parent must already be set
+    }
+
+  for (unsigned rt_code = 1; rt_code < NUM_ABS_RT_CODES - 1; rt_code++)
+    {
+      DataObject* dobj = createDataObject ();
+      dobj->parent = d_unknown;
+      dobj->set_dobjname (PTXT (ABS_RT_CODES[rt_code]), NULL); // dobj->parent must already be set
+    }
+}
+
+void
+DbeSession::reset_data ()
+{
+  for (long i = 0, sz = VecSize (idxobjs); i < sz; ++i)
+    if (idxobjs->get (i))
+      idxobjs->get (i)->reset ();
+}
+
+void
+DbeSession::reset ()
+{
+  loadObjMap->reset ();
+  DbeView *dbev;
+  int index;
+
+  Vec_loop (DbeView*, views, index, dbev)
+  {
+    dbev->reset ();
+  }
+
+  destroy_map (DbeFile *, dbeFiles);
+  destroy_map (DbeJarFile *, dbeJarFiles);
+  exps->destroy ();
+  lobjs->reset ();      // all LoadObjects belong to objs
+  dobjs->destroy ();    // deletes d_unknown and d_total as well
+  objs->destroy ();
+  comp_lobjs->clear ();
+  comp_dbelines->clear ();
+  comp_sources->clear ();
+  sourcesMap->clear ();
+  sources->reset ();
+
+  // Delete the data object name hash table.
+  for (int i = 0; i < HTableSize; i++)
+    {
+      List *list = dnameHTable[i];
+      while (list)
+       {
+         List *tmp = list;
+         list = list->next;
+         delete tmp;
+       }
+    }
+  delete[] dnameHTable;
+
+  // IndexObect definitions remain, objects themselves may go
+  for (int i = 0; i < idxobjs->size (); ++i)
+    {
+      HashMap<uint64_t, Histable*> *v = idxobjs->fetch (i);
+      if (v != NULL)
+       {
+         v->values ()->destroy ();
+         v->clear ();
+       }
+    }
+  init ();
+}
+
+Vector<SourceFile*> *
+DbeSession::get_sources ()
+{
+  return sources;
+}
+
+DbeFile *
+DbeSession::getDbeFile (char *filename, int filetype)
+{
+  Dprintf (DEBUG_DBE_FILE, NTXT ("DbeSession::getDbeFile  filetype=0x%x %s\n"), filetype, filename);
+  if (strncmp (filename, NTXT ("./"), 2) == 0)
+    filename += 2;
+  DbeFile *dbeFile = dbeFiles->get (filename);
+  if (dbeFile == NULL)
+    {
+      dbeFile = new DbeFile (filename);
+      dbeFiles->put (filename, dbeFile);
+    }
+  dbeFile->filetype |= filetype;
+  return dbeFile;
+}
+
+LoadObject *
+DbeSession::get_Total_LoadObject ()
+{
+  if (lo_total == NULL)
+    {
+      lo_total = createLoadObject (NTXT ("<Total>"));
+      lo_total->dbeFile->filetype |= DbeFile::F_FICTION;
+    }
+  return lo_total;
+}
+
+Function *
+DbeSession::get_Total_Function ()
+{
+  if (f_total == NULL)
+    {
+      f_total = createFunction ();
+      f_total->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+      f_total->set_name (NTXT ("<Total>"));
+      Module *mod = get_Total_LoadObject ()->noname;
+      f_total->module = mod;
+      mod->functions->append (f_total);
+    }
+  return f_total;
+}
+
+LoadObject *
+DbeSession::get_Unknown_LoadObject ()
+{
+  if (lo_unknown == NULL)
+    {
+      lo_unknown = createLoadObject (GTXT ("<Unknown>"));
+      lo_unknown->type = LoadObject::SEG_TEXT; // makes it expandable
+      lo_unknown->dbeFile->filetype |= DbeFile::F_FICTION;
+
+      // force creation of the <Unknown> function
+      (void) get_Unknown_Function ();
+    }
+  return lo_unknown;
+}
+
+SourceFile *
+DbeSession::get_Unknown_Source ()
+{
+  if (sf_unknown == NULL)
+    {
+      sf_unknown = createSourceFile (localized_SP_UNKNOWN_NAME);
+      sf_unknown->dbeFile->filetype |= DbeFile::F_FICTION;
+      sf_unknown->flags |= SOURCE_FLAG_UNKNOWN;
+    }
+  return sf_unknown;
+}
+
+Function *
+DbeSession::get_Unknown_Function ()
+{
+  if (f_unknown == NULL)
+    {
+      f_unknown = createFunction ();
+      f_unknown->flags |= FUNC_FLAG_SIMULATED;
+      f_unknown->set_name (GTXT ("<Unknown>"));
+      Module *mod = get_Unknown_LoadObject ()->noname;
+      f_unknown->module = mod;
+      mod->functions->append (f_unknown);
+    }
+  return f_unknown;
+}
+
+// LIBRARY_VISIBILITY
+
+Function *
+DbeSession::create_hide_function (LoadObject *lo)
+{
+  Function *h_function = createFunction ();
+  h_function->set_name (lo->get_name ());
+  h_function->module = lo->noname;
+  h_function->isHideFunc = true;
+  lo->noname->functions->append (h_function);
+  return h_function;
+}
+
+Function *
+DbeSession::get_JUnknown_Function ()
+{
+  if (j_unknown == NULL)
+    {
+      j_unknown = createFunction ();
+      j_unknown->flags |= FUNC_FLAG_SIMULATED;
+      j_unknown->set_name (GTXT ("<no Java callstack recorded>"));
+      Module *mod = get_Unknown_LoadObject ()->noname;
+      j_unknown->module = mod;
+      mod->functions->append (j_unknown);
+    }
+  return j_unknown;
+}
+
+Function *
+DbeSession::get_jvm_Function ()
+{
+  if (f_jvm == NULL)
+    {
+      f_jvm = createFunction ();
+      f_jvm->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+      f_jvm->set_name (GTXT ("<JVM-System>"));
+
+      // Find the JVM LoadObject
+      LoadObject *jvm = get_Unknown_LoadObject ();
+      for (int i = 0; i < lobjs->size (); ++i)
+       {
+         LoadObject *lo = lobjs->fetch (i);
+         if (lo->flags & SEG_FLAG_JVM)
+           {
+             jvm = lo;
+             break;
+           }
+       }
+      Module *mod = jvm->noname;
+      f_jvm->module = mod;
+      mod->functions->append (f_jvm);
+      // XXXX is it required? no consistency among all special functions
+      // jvm->functions->append( f_jvm );
+    }
+  return f_jvm;
+}
+
+Function *
+DbeSession::getSpecialFunction (SpecialFunction kind)
+{
+  if (kind < 0 || kind >= LastSpecialFunction)
+    return NULL;
+
+  Function *func = f_special->fetch (kind);
+  if (func == NULL)
+    {
+      char *fname;
+      switch (kind)
+       {
+       case TruncatedStackFunc:
+         fname = GTXT ("<Truncated-stack>");
+         break;
+       case FailedUnwindFunc:
+         fname = GTXT ("<Stack-unwind-failed>");
+         break;
+       default:
+         return NULL;
+       }
+      func = createFunction ();
+      func->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+      Module *mod = get_Total_LoadObject ()->noname;
+      func->module = mod;
+      mod->functions->append (func);
+      func->set_name (fname);
+      f_special->store (kind, func);
+    }
+  return func;
+}
+
+LoadObject *
+DbeSession::get_OMP_LoadObject ()
+{
+  if (lo_omp == NULL)
+    {
+      for (int i = 0, sz = lobjs->size (); i < sz; i++)
+       {
+         LoadObject *lo = lobjs->fetch (i);
+         if (lo->flags & SEG_FLAG_OMP)
+           {
+             lo_omp = lo;
+             return lo_omp;
+           }
+       }
+      lo_omp = createLoadObject (GTXT ("<OMP>"));
+      lo_omp->type = LoadObject::SEG_TEXT;
+      lo_omp->dbeFile->filetype |= DbeFile::F_FICTION;
+    }
+  return lo_omp;
+}
+
+Function *
+DbeSession::get_OMP_Function (int n)
+{
+  if (n < 0 || n >= OMP_LAST_STATE)
+    return NULL;
+
+  Function *func = omp_functions->fetch (n);
+  if (func == NULL)
+    {
+      char *fname;
+      switch (n)
+       {
+       case OMP_OVHD_STATE:
+         fname = GTXT ("<OMP-overhead>");
+         break;
+       case OMP_IDLE_STATE:
+         fname = GTXT ("<OMP-idle>");
+         break;
+       case OMP_RDUC_STATE:
+         fname = GTXT ("<OMP-reduction>");
+         break;
+       case OMP_IBAR_STATE:
+         fname = GTXT ("<OMP-implicit_barrier>");
+         break;
+       case OMP_EBAR_STATE:
+         fname = GTXT ("<OMP-explicit_barrier>");
+         break;
+       case OMP_LKWT_STATE:
+         fname = GTXT ("<OMP-lock_wait>");
+         break;
+       case OMP_CTWT_STATE:
+         fname = GTXT ("<OMP-critical_section_wait>");
+         break;
+       case OMP_ODWT_STATE:
+         fname = GTXT ("<OMP-ordered_section_wait>");
+         break;
+       case OMP_ATWT_STATE:
+         fname = GTXT ("<OMP-atomic_wait>");
+         break;
+       default:
+         return NULL;
+       }
+      func = createFunction ();
+      func->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+      func->set_name (fname);
+
+      LoadObject *omp = get_OMP_LoadObject ();
+      func->module = omp->noname;
+      omp->noname->functions->append (func);
+      omp->functions->append (func);
+      omp_functions->store (n, func);
+    }
+  return func;
+}
+
+// Divide the original createExperiment() into two steps
+// In part1, we just create the data structure, in part2, if
+// we decide to keep the experiment around, add it to various
+// lists in DbeSession
+Experiment *
+DbeSession::createExperimentPart1 ()
+{
+  Experiment *exp = new Experiment ();
+  return exp;
+}
+
+void
+DbeSession::createExperimentPart2 (Experiment *exp)
+{
+  int ind = expGroups->size ();
+  if (ind > 0)
+    {
+      ExpGroup *gr = expGroups->fetch (ind - 1);
+      exp->groupId = gr->groupId;
+      gr->append (exp);
+    }
+  exp->setExpIdx (exps->size ());
+  exp->setUserExpId (++user_exp_id_counter);
+  exps->append (exp);
+}
+
+Experiment *
+DbeSession::createExperiment ()
+{
+  Experiment *exp = new Experiment ();
+  append (exp);
+  return exp;
+}
+
+void
+DbeSession::append (Experiment *exp)
+{
+  exp->setExpIdx (exps->size ());
+  exp->setUserExpId (++user_exp_id_counter);
+  exps->append (exp);
+  if (exp->founder_exp)
+    {
+      if (exp->founder_exp->children_exps == NULL)
+       exp->founder_exp->children_exps = new Vector<Experiment *>;
+      exp->founder_exp->children_exps->append (exp);
+      if (exp->founder_exp->groupId > 0)
+       {
+         exp->groupId = exp->founder_exp->groupId;
+         expGroups->get (exp->groupId - 1)->append (exp);
+       }
+    }
+  if (exp->groupId == 0)
+    {
+      long ind = VecSize (expGroups);
+      if (ind > 0)
+       {
+         ExpGroup *gr = expGroups->get (ind - 1);
+         exp->groupId = gr->groupId;
+         gr->append (exp);
+       }
+    }
+}
+
+void
+DbeSession::append (Hwcentry *h)
+{
+  if (hwcentries == NULL)
+    hwcentries = new Vector<Hwcentry*>;
+  hwcentries->append (h);
+}
+
+int
+DbeSession::ngoodexps ()
+{
+  return exps->size ();
+}
+
+int
+DbeSession::createView (int index, int cloneindex)
+{
+  // ensure that there is no view with that index
+  DbeView *dbev = getView (index);
+  if (dbev != NULL)
+    abort ();
+
+  // find the view to be cloned
+  dbev = getView (cloneindex);
+  DbeView *newview;
+  if (dbev == NULL)
+    newview = new DbeView (theApplication, settings, index);
+  else
+    newview = new DbeView (dbev, index);
+  views->append (newview);
+  return index;
+}
+
+DbeView *
+DbeSession::getView (int index)
+{
+  int i;
+  DbeView *dbev;
+  Vec_loop (DbeView*, views, i, dbev)
+  {
+    if (dbev->vindex == index)
+      return dbev;
+  }
+  return NULL;
+}
+
+void
+DbeSession::dropView (int index)
+{
+  int i;
+  DbeView *dbev;
+
+  Vec_loop (DbeView*, views, i, dbev)
+  {
+    if (dbev->vindex == index)
+      {
+       views->remove (i);
+       delete dbev;
+       return;
+      }
+  }
+  // view not found; ignore for now
+}
+
+Vector<char*> *
+DbeSession::get_group_or_expt (char *path)
+{
+  Vector<char*> *exp_list = new Vector<char*>;
+  FILE *fptr;
+  char *new_path, buf[MAXPATHLEN], name[MAXPATHLEN];
+
+  fptr = fopen (path, NTXT ("r"));
+  if (!fptr || !fgets (buf, (int) sizeof (buf), fptr)
+      || strncmp (buf, SP_GROUP_HEADER, strlen (SP_GROUP_HEADER)))
+    {
+      // it's not an experiment group
+      new_path = dbe_strdup (path);
+      new_path = canonical_path (new_path);
+      exp_list->append (new_path);
+    }
+  else
+    {
+      // it is an experiment group, read the list to get them all
+      while (fgets (buf, (int) sizeof (buf), fptr))
+       {
+         if ((*buf != '#') && (sscanf (buf, NTXT ("%s"), name) == 1))
+           {
+             new_path = dbe_strdup (name);
+             new_path = canonical_path (new_path);
+             exp_list->append (new_path);
+           }
+       }
+    }
+  if (fptr)
+    fclose (fptr);
+  return exp_list;
+}
+
+#define GET_INT_VAL(v, s, len) \
+    for (v = len = 0; isdigit(*s); s++, len++) { v = v * 10 + (*s -'0'); }
+
+static int
+dir_name_cmp (const void *a, const void *b)
+{
+  char *s1 = *((char **) a);
+  char *s2 = *((char **) b);
+  while (*s1)
+    {
+      if (isdigit (*s1) && isdigit (*s2))
+       {
+         int v1, v2, len1, len2;
+         GET_INT_VAL (v1, s1, len1);
+         GET_INT_VAL (v2, s2, len2);
+         if (v1 != v2)
+           return v1 - v2;
+         if (len1 != len2)
+           return len2 - len1;
+         continue;
+       }
+      if (*s1 != *s2)
+       break;
+      s1++;
+      s2++;
+    }
+  return *s1 - *s2;
+}
+
+static int
+read_experiment_data_in_parallel (void *arg)
+{
+  exp_ctx *ctx = (exp_ctx *) arg;
+  Experiment *dexp = ctx->exp;
+  bool read_ahead = ctx->read_ahead;
+  dexp->read_experiment_data (read_ahead);
+  free (ctx);
+  return 0;
+}
+
+void
+DbeSession::open_experiment (Experiment *exp, char *path)
+{
+  exp->open (path);
+  if (exp->get_status () != Experiment::FAILURE)
+    exp->read_experiment_data (false);
+  exp->open_epilogue ();
+
+  // Update all DbeViews
+  for (int i = 0, sz = views->size (); i < sz; i++)
+    {
+      DbeView *dbev = views->fetch (i);
+      dbev->add_experiment (exp->getExpIdx (), true);
+    }
+
+  if (exp->get_status () == Experiment::FAILURE)
+    {
+      check_tab_avail ();
+      return;
+    }
+
+  char *discard_tiny = getenv (NTXT ("SP_ANALYZER_DISCARD_TINY_EXPERIMENTS"));
+  int user_specified_tiny_threshold = DEFAULT_TINY_THRESHOLD; // in milliseconds
+  if (discard_tiny != NULL)
+    {
+      user_specified_tiny_threshold = (atoi (discard_tiny));
+      if (user_specified_tiny_threshold < 0)
+       user_specified_tiny_threshold = DEFAULT_TINY_THRESHOLD;
+    }
+
+  // Open descendant experiments
+  DIR *exp_dir = opendir (path);
+  if (exp_dir == NULL)
+    {
+      check_tab_avail ();
+      return;
+    }
+
+  Vector<char*> *exp_names = new Vector<char*>();
+  struct dirent *entry = NULL;
+  while ((entry = readdir (exp_dir)) != NULL)
+    {
+      if (entry->d_name[0] != '_')
+       continue;
+      size_t len = strlen (entry->d_name);
+      if (len < 3 || strcmp (entry->d_name + len - 3, NTXT (".er")) != 0)
+       continue;
+      exp_names->append (dbe_strdup (entry->d_name));
+    }
+  closedir (exp_dir);
+  exp_names->sort (dir_name_cmp);
+  Experiment **t_exp_list = new Experiment *[exp_names->size ()];
+  int nsubexps = 0;
+
+  for (int j = 0, jsz = exp_names->size (); j < jsz; j++)
+    {
+      t_exp_list[j] = NULL;
+
+      char *lineage_name = exp_names->fetch (j);
+      struct stat64 sbuf;
+      char *dpath = dbe_sprintf (NTXT ("%s/%s"), path, lineage_name);
+
+      // look for experiments with no profile collected
+      if (user_specified_tiny_threshold == DEFAULT_TINY_THRESHOLD)
+       {
+         char *frinfoname = dbe_sprintf (NTXT ("%s/%s"), dpath, "data." SP_FRINFO_FILE);
+         int st = dbe_stat (frinfoname, &sbuf);
+         free (frinfoname);
+         if (st == 0)
+           {
+             // if no profile/trace data do not process this experiment any further
+             if (sbuf.st_size == 0)
+               {
+                 free (dpath);
+                 continue;
+               }
+           }
+       }
+      else
+       { // check if dpath is a directory
+         if (dbe_stat (dpath, &sbuf) != 0)
+           {
+             free (dpath);
+             continue;
+           }
+         else if (!S_ISDIR (sbuf.st_mode))
+           {
+             free (dpath);
+             continue;
+           }
+       }
+      size_t lineage_name_len = strlen (lineage_name);
+      lineage_name[lineage_name_len - 3] = 0; /* remove .er */
+      Experiment *dexp = new Experiment ();
+      dexp->founder_exp = exp;
+      if (user_specified_tiny_threshold > DEFAULT_TINY_THRESHOLD)
+       {
+         dexp->setTinyThreshold (user_specified_tiny_threshold);
+         dexp->open (dpath);
+         if (dexp->isDiscardedTinyExperiment ())
+           {
+             delete dexp;
+             free (dpath);
+             continue;
+           }
+       }
+      else
+       dexp->open (dpath);
+      append (dexp);
+      t_exp_list[j] = dexp;
+      nsubexps++;
+      dexp->set_clock (exp->clock);
+
+      // DbeView add_experiment() is split into two parts
+      // add_subexperiment() is called repeeatedly for
+      // all sub_experiments, later add_experiment_epilogue() finishes up the task
+      for (int i = 0, sz = views->size (); i < sz; i++)
+       {
+         DbeView *dbev = views->fetch (i);
+         bool enabled = settings->check_en_desc (lineage_name, dexp->utargname);
+         dbev->add_subexperiment (dexp->getExpIdx (), enabled);
+       }
+      free (dpath);
+    }
+
+  for (int i = 0, sz = views->size (); i < sz; i++)
+    {
+      DbeView *dbev = views->fetch (i);
+      dbev->add_experiment_epilogue ();
+    }
+
+  DbeThreadPool * threadPool = new DbeThreadPool (-1);
+  for (int j = 0, jsz = exp_names->size (); j < jsz; j++)
+    {
+      if (t_exp_list[j] == NULL) continue;
+      Experiment *dexp = t_exp_list[j];
+      exp_ctx *new_ctx = (exp_ctx*) malloc (sizeof (exp_ctx));
+      new_ctx->path = NULL;
+      new_ctx->exp = dexp;
+      new_ctx->ds = this;
+      new_ctx->read_ahead = true;
+      DbeQueue *q = new DbeQueue (read_experiment_data_in_parallel, new_ctx);
+      threadPool->put_queue (q);
+    }
+  threadPool->wait_queues ();
+  delete threadPool;
+
+  for (long j = 0, jsz = exp_names->size (); j < jsz; j++)
+    {
+      if (t_exp_list[j] == NULL) continue;
+      Experiment *dexp = t_exp_list[j];
+      dexp->open_epilogue ();
+    }
+  exp_names->destroy ();
+  delete[] t_exp_list;
+  delete exp_names;
+
+  // update setting for leaklist and dataspace
+  check_tab_avail ();
+}
+
+void
+DbeSession::append_mesgs (StringBuilder *sb, char *path, Experiment *exp)
+{
+  if (exp->fetch_errors () != NULL)
+    {
+      // yes, there were errors
+      char *ststr = pr_mesgs (exp->fetch_errors (), NTXT (""), NTXT (""));
+      sb->append (path);
+      sb->append (NTXT (": "));
+      sb->append (ststr);
+      free (ststr);
+    }
+
+  Emsg *m = exp->fetch_warnings ();
+  if (m != NULL)
+    {
+      sb->append (path);
+      sb->append (NTXT (": "));
+      if (!is_interactive ())
+       sb->append (GTXT ("Experiment has warnings, see header for details\n"));
+      else
+       sb->append (GTXT ("Experiment has warnings, see experiment panel for details\n"));
+    }
+
+  // Check for descendant experiments that are not loaded
+  int num_desc = VecSize (exp->children_exps);
+  if ((num_desc > 0) && !settings->check_en_desc (NULL, NULL))
+    {
+      char *s;
+      if (!is_interactive ())
+       s = dbe_sprintf (GTXT ("Has %d descendant(s), use commands controlling selection to load descendant data\n"), num_desc);
+      else
+       s = dbe_sprintf (GTXT ("Has %d descendant(s), use filter panel to load descendant data\n"), num_desc);
+      sb->append (path);
+      sb->append (NTXT (": "));
+      sb->append (s);
+      free (s);
+    }
+}
+
+Experiment *
+DbeSession::get_exp (int exp_ind)
+{
+  if (exp_ind < 0 || exp_ind >= exps->size ())
+    return NULL;
+  Experiment *exp = exps->fetch (exp_ind);
+  exp->setExpIdx (exp_ind);
+  return exp;
+}
+
+Vector<Vector<char*>*> *
+DbeSession::getExperimensGroups ()
+{
+  if (dbeSession->expGroups == NULL || dbeSession->expGroups->size () == 0)
+    return NULL;
+  bool compare_mode = expGroups->size () > 1;
+  Vector<Vector<char*>*> *groups = new Vector<Vector<char*>*> (
+                                        compare_mode ? expGroups->size () : 1);
+  for (int i = 0; i < expGroups->size (); i++)
+    {
+      ExpGroup *grp = expGroups->fetch (i);
+      Vector<Experiment*> *founders = grp->get_founders ();
+      if (founders && founders->size () != 0)
+       {
+         Vector<char *> *names = new Vector<char*> (founders->size ());
+         for (int j = 0; j < founders->size (); j++)
+           {
+             Experiment *exp = founders->fetch (j);
+             names->append (dbe_strdup (exp->get_expt_name ()));
+           }
+         if (compare_mode || groups->size () == 0)
+           groups->append (names);
+         else
+           groups->fetch (0)->addAll (names);
+       }
+      delete founders;
+    }
+  return groups;
+}
+
+char *
+DbeSession::setExperimentsGroups (Vector<Vector<char*>*> *groups)
+{
+  StringBuilder sb;
+  for (int i = 0; i < groups->size (); i++)
+    {
+      Vector<char *> *names = groups->fetch (i);
+      ExpGroup *grp;
+      if (names->size () == 1)
+       grp = new ExpGroup (names->fetch (0));
+      else
+       {
+         char *nm = dbe_sprintf (GTXT ("Group %d"), i + 1);
+         grp = new ExpGroup (nm);
+         free (nm);
+       }
+      expGroups->append (grp);
+      grp->groupId = expGroups->size ();
+
+      for (int j = 0; j < names->size (); j++)
+       {
+         char *path = names->fetch (j);
+         size_t len = strlen (path);
+         if ((len > 4) && !strcmp (path + len - 4, NTXT (".erg")))
+           {
+             Vector<char*> *lst = get_group_or_expt (path);
+             for (int j1 = 0; j1 < lst->size (); j1++)
+               {
+                 Experiment *exp = new Experiment ();
+                 append (exp);
+                 open_experiment (exp, lst->get (j1));
+                 if (exp->get_status () == Experiment::FAILURE)
+                   append_mesgs (&sb, path, exp);
+               }
+             lst->destroy ();
+             delete lst;
+           }
+         else
+           {
+             Experiment *exp = new Experiment ();
+             append (exp);
+             open_experiment (exp, path);
+             if (exp->get_status () == Experiment::FAILURE)
+               append_mesgs (&sb, path, exp);
+           }
+       }
+    }
+
+  for (int i = 0, sz = views->size (); i < sz; i++)
+    {
+      DbeView *dbev = views->fetch (i);
+      dbev->update_advanced_filter ();
+      int cmp = dbev->get_settings ()->get_compare_mode ();
+      dbev->set_compare_mode (CMP_DISABLE);
+      dbev->set_compare_mode (cmp);
+    }
+  return sb.length () == 0 ? NULL : sb.toString ();
+}
+
+char *
+DbeSession::drop_experiment (int exp_ind)
+{
+  DbeView *dbev;
+  int index;
+  Experiment *exp2;
+
+  status_ompavail = -1;
+  Experiment *exp = exps->fetch (exp_ind);
+
+  // If this is a sub experiment, don't do it
+  if (exp->founder_exp != NULL)     // this is a sub experiment; don't do it
+    return (dbe_strdup (GTXT ("Can not drop subexperiments")));
+
+  if (VecSize (exp->children_exps) > 0)
+    for (;;)
+      {
+       // search the list of experiments to find all that have this one as founder
+       bool found = false;
+       Vec_loop (Experiment*, exps, index, exp2)
+       {
+         if (exp2->founder_exp == exp)
+           {
+             exp2->founder_exp = NULL;
+             drop_experiment (index);
+             found = true;
+             break;
+           }
+       }
+       if (found == false)
+         break;
+      }
+
+  // then proceed to finish the drop
+  Vec_loop (DbeView*, views, index, dbev)
+  {
+    dbev->drop_experiment (exp_ind);
+  }
+
+  int old_cnt = expGroups->size ();
+  for (int i = 0; i < old_cnt; i++)
+    {
+      ExpGroup *gr = expGroups->fetch (i);
+      if (gr->groupId == exp->groupId)
+       {
+         gr->drop_experiment (exp);
+         if ((gr->founder == NULL) && (gr->exps->size () == 0))
+           {
+             delete gr;
+             expGroups->remove (i);
+           }
+         break;
+       }
+    }
+  delete exps->remove (exp_ind);
+  if (old_cnt != expGroups->size ())
+    {
+      for (int i = 0, sz = expGroups->size (); i < sz; i++)
+       {
+         ExpGroup *gr = expGroups->fetch (i);
+         gr->groupId = i + 1;
+         Vector<Experiment*> *expList = gr->exps;
+         for (int i1 = 0, sz1 = expList->size (); i1 < sz1; i1++)
+           expList->fetch (i1)->groupId = gr->groupId;
+       }
+      for (int i = 0, sz = views->size (); i < sz; i++)
+       {
+         dbev = views->fetch (i);
+         int cmp = dbev->get_compare_mode ();
+         dbev->set_compare_mode (CMP_DISABLE);
+         dbev->set_compare_mode (cmp);
+       }
+    }
+  check_tab_avail ();   // update tab availability
+  return NULL;
+}
+
+int
+DbeSession::find_experiment (char *path)
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (strcmp (exp->get_expt_name (), path) == 0)
+      return exp->getExpIdx ();
+  }
+  return -1;
+}
+
+LoadObject *
+DbeSession::createLoadObject (const char *nm, int64_t cksum)
+{
+  return loadObjMap->sync_create_item (nm, cksum);
+}
+
+LoadObject *
+DbeSession::createLoadObject (const char *nm, const char *runTimePath, DbeFile *df)
+{
+  return loadObjMap->sync_create_item (nm, runTimePath, df);
+}
+
+void
+DbeSession::append (LoadObject *lobj)
+{
+  Histable *obj = lobj; // workaround for a C++ problem
+  objs->append (obj);
+  lobj->id = objs->size () - 1;
+  lobjs->append (lobj);
+  lobj->seg_idx = lobjs->size () - 1;
+  char *loname = lobj->get_pathname ();
+  dbeFiles->put (loname, lobj->dbeFile);
+}
+
+DbeJarFile *
+DbeSession::get_JarFile (const char *name)
+{
+  DbeJarFile *jf = dbeJarFiles->get (name);
+  if (jf == NULL)
+    {
+      jf = new DbeJarFile (name);
+      dbeJarFiles->put (name, jf);
+    }
+  return jf;
+}
+
+Module *
+DbeSession::createModule (LoadObject *lo, const char *nm)
+{
+  Module *mod = new Module ();
+  Histable *obj = mod; // workaround for a C++ problem
+  objs->append (obj);
+  mod->id = objs->size () - 1;
+  mod->loadobject = lo;
+  mod->set_name (dbe_strdup (nm ? nm : localized_SP_UNKNOWN_NAME));
+  lo->seg_modules->append (mod);
+  return mod;
+}
+
+Module *
+DbeSession::createUnknownModule (LoadObject *lo)
+{
+  Module *mod = createModule (lo, localized_SP_UNKNOWN_NAME);
+  mod->flags |= MOD_FLAG_UNKNOWN;
+  mod->set_file_name (dbe_strdup (localized_SP_UNKNOWN_NAME));
+  return mod;
+}
+
+SourceFile *
+DbeSession::createSourceFile (const char *_path)
+{
+  char *path = (char *) _path;
+  if (strncmp (path, NTXT ("./"), 2) == 0)
+    path += 2;
+  SourceFile *source = sourcesMap->get (path);
+  if (source == NULL)
+    {
+      source = new SourceFile (path);
+      (void) sourcesMap->put (path, source);
+      append (source);
+    }
+  return source;
+}
+
+Function *
+DbeSession::createFunction ()
+{
+  Function *func = new Function (objs->size ());
+  Histable *obj = func; // workaround for a C++ problem
+  objs->append (obj);
+  return func;
+}
+
+JMethod *
+DbeSession::createJMethod ()
+{
+  JMethod *jmthd = new JMethod (objs->size ());
+  Histable *obj = jmthd; // workaround for a C++ problem
+  objs->append (obj);
+  return jmthd;
+}
+
+Module *
+DbeSession::createClassFile (char *className)
+{
+  ClassFile *cls = new ClassFile ();
+  cls->set_name (className);
+  char *clpath = cls->get_java_file_name (className, true);
+  cls->dbeFile = getDbeFile (clpath, DbeFile::F_JAVACLASS);
+  free (clpath);
+  Histable *obj = cls; // workaround for a C++ problem
+  objs->append (obj);
+  cls->id = objs->size () - 1;
+  return cls;
+}
+
+Histable *
+DbeSession::createHistObject (Histable::Type type)
+{
+  switch (type)
+    {
+    case Histable::DOBJECT:
+      {
+       DataObject *dataobj = new DataObject ();
+       dobjs->append (dataobj);
+       dataobj->id = dobjs->size () - 1;
+       return dataobj;
+      }
+    default:
+      assert (0);
+    }
+  return NULL;
+}
+
+DataObject *
+DbeSession::createDataObject ()
+{
+  DataObject *dataobj = new DataObject ();
+  dobjs->append (dataobj);
+  dataobj->id = dobjs->size () - 1;
+  return dataobj;
+}
+
+DataObject *
+DbeSession::createDataObject (DataObject *dobj, DataObject *parent)
+{
+  DataObject *dataobj = new DataObject ();
+  dataobj->size = dobj->size;
+  dataobj->offset = dobj->offset;
+  dataobj->parent = parent;
+  dataobj->set_dobjname (dobj->get_typename (), dobj->get_instname ());
+  dobjs->append (dataobj);
+  dataobj->id = dobjs->size () - 1;
+  return dataobj;
+}
+
+DataObject *
+DbeSession::createMasterDataObject (DataObject *dobj)
+{
+  DataObject *parent = NULL;
+  if (dobj->parent)
+    { // define master parent first
+      parent = find_dobj_master (dobj->parent);
+      if (!parent)
+       { // clone master from this dataobject parent
+         parent = createDataObject (dobj->parent);
+         parent->scope = NULL; // master is scope-less
+         Dprintf (DEBUG_DATAOBJ,
+                  "Master DataObject(%llu) cloned from (%llu) %s\n",
+                  (ull_t) parent->id, (ull_t) dobj->parent->id,
+                  dobj->parent->get_name ());
+         // clone master DataObject elements
+         Vector<DataObject*> *delem = get_dobj_elements (dobj->parent);
+         int element_index = 0;
+         DataObject *element = NULL;
+         Vec_loop (DataObject*, delem, element_index, element)
+         {
+           DataObject *master_element = createDataObject (element, parent);
+           master_element->scope = NULL; // master is scope-less
+           Dprintf (DEBUG_DATAOBJ,
+                    "Member DataObject(%llu) cloned from (%llu) %s\n",
+                    (ull_t) master_element->id, (ull_t) element->id,
+                    element->get_name ());
+         }
+       }
+      else
+       Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) clone found (%llu) %s\n",
+                (ull_t) parent->id, (ull_t) dobj->parent->id,
+                dobj->parent->get_name ());
+    }
+
+  DataObject *master = find_dobj_master (dobj);
+  if (!master)
+    { // clone master from this dataobject
+      master = createDataObject (dobj, parent);
+      master->scope = NULL; // master is scope-less
+      Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) cloned from (%llu) %s\n",
+              (ull_t) master->id, (ull_t) dobj->id, dobj->get_name ());
+    }
+  else
+    Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) clone found (%llu) %s\n",
+            (ull_t) master->id, (ull_t) dobj->id, dobj->get_name ());
+  return master;
+}
+
+void
+DbeSession::insert_metric (BaseMetric *mtr, Vector<BaseMetric*> *mlist)
+{
+  if ((mtr->get_flavors () & Metric::STATIC) == 0)
+    {
+      // insert in front of the first STATIC
+      for (int i = 0, mlist_sz = mlist->size (); i < mlist_sz; i++)
+       {
+         BaseMetric *m = mlist->fetch (i);
+         if (m->get_flavors () & Metric::STATIC)
+           {
+             mlist->insert (i, mtr);
+             return;
+           }
+       }
+    }
+  mlist->append (mtr);
+}
+
+BaseMetricTreeNode*
+DbeSession::get_reg_metrics_tree ()
+{
+  if (reg_metrics_tree == NULL)
+    // Can't init earlier because BaseMetric() requires DbeSession::ql_parse
+    reg_metrics_tree = new BaseMetricTreeNode ();
+  return reg_metrics_tree;
+}
+
+void
+DbeSession::update_metric_tree (BaseMetric *m)
+{
+  get_reg_metrics_tree ()->register_metric (m);
+}
+
+BaseMetric *
+DbeSession::register_metric_expr (BaseMetric::Type type, char *cmd, char *expr_spec)
+{
+  BaseMetric *m = find_metric (type, cmd, expr_spec);
+  if (m)
+    return m;
+  BaseMetric *bm = find_metric (type, cmd, NULL); // clone this version
+  m = new BaseMetric (*bm);
+  m->set_expr_spec (expr_spec);
+  insert_metric (m, reg_metrics);
+  return m;
+}
+
+BaseMetric *
+DbeSession::register_metric (BaseMetric::Type type)
+{
+  BaseMetric *m = find_metric (type, NULL, NULL);
+  if (m)
+    return m;
+  m = new BaseMetric (type);
+  insert_metric (m, reg_metrics);
+  update_metric_tree (m);
+  return m;
+}
+
+BaseMetric *
+DbeSession::register_metric (Hwcentry *ctr, const char* aux, const char* username)
+{
+  BaseMetric *m = find_metric (BaseMetric::HWCNTR, aux, NULL);
+  if (m)
+    // That may be a problem when metrics aren't an exact match.
+    // For example, memoryspace is disabled in one experiment and not in another.
+    return m;
+  if (ctr->timecvt)
+    {
+      char *time_cmd = dbe_sprintf (NTXT ("t%s"), aux);
+      char *time_username = dbe_sprintf (GTXT ("%s Time"),
+                                      ctr->metric ? ctr->metric :
+                                      (ctr->name ? ctr->name : ctr->int_name));
+      BaseMetric *m1;
+      if (ipc_mode)
+       {
+         // Two visible metrics are presented in GUI
+         m1 = new BaseMetric (ctr, aux, time_cmd, time_username, VAL_TIMEVAL);
+         insert_metric (m1, reg_metrics);
+         update_metric_tree (m1);
+         m = new BaseMetric (ctr, aux, username, VAL_VALUE, m1);
+       }
+      else
+       {
+         // Only one visible metric is presented in er_print
+         m1 = new BaseMetric (ctr, aux, time_cmd, time_username, VAL_TIMEVAL | VAL_INTERNAL);
+         insert_metric (m1, reg_metrics);
+         m = new BaseMetric (ctr, aux, username, VAL_TIMEVAL | VAL_VALUE, m1);
+       }
+      free (time_cmd);
+      free (time_username);
+    }
+  else
+    m = new BaseMetric (ctr, aux, username, VAL_VALUE);
+  insert_metric (m, reg_metrics);
+  update_metric_tree (m);
+  return m;
+}
+
+BaseMetric *
+DbeSession::register_metric (char *name, char *username, char *_def)
+{
+  BaseMetric *m = find_metric (BaseMetric::DERIVED, name, NULL);
+  if (m)
+    return m;
+  Definition *p = Definition::add_definition (_def);
+  if (p == NULL)
+    return NULL;
+  m = new BaseMetric (name, username, p);
+  insert_metric (m, reg_metrics);
+  update_metric_tree (m);
+  return m;
+}
+
+void
+DbeSession::drop_metric (BaseMetric *mtr)
+{
+  Countable *cnt;
+  int index;
+
+  Vec_loop (Countable*, metrics, index, cnt)
+  {
+    if (mtr == (BaseMetric *) cnt->item)
+      {
+       cnt->ref_count--;
+       if (cnt->ref_count == 0)
+         {
+           // Remove this metric from all views
+           DbeView *dbev;
+           int index2;
+           Vec_loop (DbeView*, views, index2, dbev)
+           {
+             dbev->reset_metrics ();
+           }
+           delete metrics->remove (index);
+           delete mtr;
+           return;
+         }
+      }
+  }
+}
+
+BaseMetric *
+DbeSession::find_metric (BaseMetric::Type type, const char *cmd, const char *expr_spec)
+{
+  for (int i = 0, sz = reg_metrics->size (); i < sz; i++)
+    {
+      BaseMetric *bm = reg_metrics->fetch (i);
+      if (bm->get_type () == type && dbe_strcmp (bm->get_expr_spec (), expr_spec) == 0)
+       {
+         if ((type == BaseMetric::DERIVED || type == BaseMetric::HWCNTR)
+              && dbe_strcmp (bm->get_cmd (), cmd) != 0)
+           continue;
+         return bm;
+       }
+    }
+  return NULL;
+}
+
+BaseMetric *
+DbeSession::find_base_reg_metric (char * mcmd)
+{
+  for (int i = 0, sz = reg_metrics->size (); i < sz; i++)
+    {
+      BaseMetric *bm = reg_metrics->fetch (i);
+      if (bm->get_expr_spec () != NULL)
+       continue; // skip compare metrics
+      if (dbe_strcmp (bm->get_cmd (), mcmd) == 0)
+       return bm;
+    }
+  return NULL;
+}
+
+Vector<BaseMetric*> *
+DbeSession::get_base_reg_metrics ()
+{
+  Vector<BaseMetric*> *mlist = new Vector<BaseMetric*>;
+  Vector<BaseMetric*> *ml = get_all_reg_metrics ();
+  for (int i = 0, sz = ml->size (); i < sz; i++)
+    {
+      BaseMetric *m = ml->fetch (i);
+      if (m->get_expr_spec () == NULL)
+       mlist->append (m);
+    }
+  return mlist;
+}
+
+void
+DbeSession::check_tab_avail ()
+{
+  DbeView *dbev;
+  int index;
+  // tell the views to update their tab lists
+  Vec_loop (DbeView*, views, index, dbev)
+  {
+    dbev->get_settings ()->updateTabAvailability ();
+  }
+}
+
+bool
+DbeSession::is_datamode_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->dataspaceavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_leaklist_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->leaklistavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_heapdata_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->heapdataavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_iodata_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->iodataavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_racelist_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->racelistavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_deadlocklist_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->deadlocklistavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_timeline_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->timelineavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_ifreq_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->ifreqavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_omp_available ()
+{
+  if (status_ompavail == -1)
+    {
+      status_ompavail = 0;
+      for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+       {
+         Experiment *exp = exps->fetch (i);
+         if (exp->ompavail)
+           {
+             status_ompavail = 1;
+             break;
+           }
+       }
+    }
+  return status_ompavail == 1;
+}
+
+bool
+DbeSession::has_java ()
+{
+  int status_has_java = 0;
+  for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+    {
+      Experiment *exp = exps->fetch (i);
+      if (exp->has_java)
+       {
+         status_has_java = 1;
+         break;
+       }
+    }
+  return status_has_java == 1;
+}
+
+bool
+DbeSession::has_ompavail ()
+{
+  int status_has_ompavail = 0;
+  for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+    {
+      Experiment *exp = exps->fetch (i);
+      if (exp->ompavail)
+       {
+         status_has_ompavail = 1;
+         break;
+       }
+    }
+  return status_has_ompavail == 1;
+}
+
+int
+DbeSession::get_clock (int whichexp)
+{
+  // XXXX clock frequency should be an attribute of each CPU,
+  // XXX  and not a property of the session
+  // if whichexp is -1, pick the first exp that has a clock
+  // otherwise return the clock from the numbered experiment
+  Experiment *exp;
+  if (whichexp != -1)
+    {
+      exp = get_exp (whichexp);
+      if (exp != NULL)
+       return exp->clock;
+      return 0;
+    }
+  int n = nexps ();
+  for (int i = 0; i < n; i++)
+    {
+      exp = get_exp (i);
+      if (exp != NULL && exp->clock != 0)
+       return exp->clock;
+    }
+  return 0;
+}
+
+LoadObject *
+DbeSession::find_lobj_by_name (const char *lobj_name, int64_t cksum)
+{
+  return loadObjMap->get (lobj_name, cksum);
+}
+
+static unsigned
+hash (char *s)
+{
+  unsigned res = 0;
+  for (int i = 0; i < 64 && *s; i++)
+    res = res * 13 + *s++;
+  return res;
+}
+
+// This method is introduced to fix performance
+// problems with the data space profiling in the
+// current release. A better design is desired.
+void
+DbeSession::dobj_updateHT (DataObject *dobj)
+{
+  unsigned index = hash (dobj->get_unannotated_name ()) % HTableSize;
+  List *list = new List;
+  list->val = (void*) dobj;
+  list->next = dnameHTable[index];
+  dnameHTable[index] = list;
+}
+
+DataObject *
+DbeSession::find_dobj_by_name (char *dobj_name)
+{
+  unsigned index = hash (dobj_name) % HTableSize;
+  List *list = dnameHTable[index];
+  for (; list; list = list->next)
+    {
+      DataObject *d = (DataObject*) list->val;
+      if (strcmp (d->get_unannotated_name (), dobj_name) == 0)
+       return d;
+    }
+  return (DataObject *) NULL;
+}
+
+DataObject *
+DbeSession::find_dobj_match (DataObject *dobj)
+{
+  char *dobj_name = dobj->get_unannotated_name ();
+  unsigned index = hash (dobj_name) % HTableSize;
+  List *list = dnameHTable[index];
+  for (; list; list = list->next)
+    {
+      DataObject *d = (DataObject*) list->val;
+      if (strcmp (d->get_unannotated_name (), dobj_name) == 0
+         && d->size == dobj->size && d->offset == dobj->offset
+         && d->scope == dobj->scope)
+       return d;
+    }
+  return (DataObject *) NULL;
+}
+
+DataObject *
+DbeSession::find_dobj_master (DataObject *dobj)
+{
+  char *dobj_name = dobj->get_unannotated_name ();
+  unsigned index = hash (dobj_name) % HTableSize;
+  List *list = dnameHTable[index];
+  for (; list; list = list->next)
+    {
+      DataObject *d = (DataObject*) list->val;
+      // XXXX should parent also match?
+      if (strcmp (d->get_unannotated_name (), dobj_name) == 0
+         && d->size == dobj->size && d->offset == dobj->offset
+         && d->master == NULL && d->scope == NULL)
+       return d;
+    }
+  return (DataObject *) NULL;
+}
+
+Vector<DataObject*>*
+DbeSession::get_dobj_elements (DataObject *dobj)
+{
+  DataObject *d;
+  int index;
+  Vector<DataObject*> *elements = new Vector<DataObject*>;
+  if (dobj == d_total)
+    return elements;
+  Vec_loop (DataObject*, dobjs, index, d)
+  {
+    if (d->get_parent () && d->get_parent () == dobj)
+      elements->append (d);
+  }
+  return elements;
+}
+
+Vector<LoadObject*>*
+DbeSession::get_text_segments ()
+{
+  LoadObject *lo;
+  int index;
+  Vector<LoadObject*> *tlobjs = new Vector<LoadObject*>;
+  Vec_loop (LoadObject*, lobjs, index, lo)
+  {
+    if (lo->type == LoadObject::SEG_TEXT)
+      tlobjs->append (lo);
+  }
+  return tlobjs;
+}
+
+static long long
+getNumber (const char *s, char * &last)
+{
+  long long val;
+  char *sp;
+  errno = 0;
+  val = strtoll (s, &sp, 0);
+  if (errno == EINVAL)
+    last = NULL;
+  else
+    {
+      while (isspace (*sp))
+       sp++;
+      last = sp;
+    }
+  return (val);
+}
+
+bool
+DbeSession::find_obj (FILE *dis_file, FILE *inp_file, Histable *&obj,
+                     char *name, const char *sel, Histable::Type type, bool xdefault)
+{
+  Vector<Histable*> *obj_lst;
+  int which = -1;
+  char *last = NULL;
+  if (type != Histable::FUNCTION && sel)
+    {
+      // check that a number has been provided
+      which = (int) getNumber (sel, last);
+      if (last == NULL || *last != '\0')
+       {
+         fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+         sel = NULL;
+         which = 0;
+       }
+      which--;
+    }
+  obj_lst = new Vector<Histable*>;
+  switch (type)
+    {
+    case Histable::FUNCTION:
+      obj = map_NametoFunction (name, obj_lst, sel);
+      break;
+    case Histable::MODULE:
+      obj = map_NametoModule (name, obj_lst, which);
+      break;
+    case Histable::LOADOBJECT:
+      obj = map_NametoLoadObject (name, obj_lst, which);
+      break;
+    case Histable::DOBJECT:
+      obj = map_NametoDataObject (name, obj_lst, which);
+      break;
+    default:
+      abort (); // unexpected Histable!
+    }
+
+  if ((obj == NULL) && (obj_lst->size () > 0))
+    {
+      if (obj_lst->size () == 1)
+       which = 0;
+      else
+       {
+         if (sel && (which < 0 || which >= obj_lst->size ()))
+           fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+         if (xdefault)
+           {
+             fprintf (stderr, GTXT ("Default selection \"1\" made\n"));
+             which = 0;
+           }
+         else
+           {
+             which = ask_which (dis_file, inp_file, obj_lst, name);
+             if (which == -1)
+               {
+                 delete obj_lst;
+                 return false;
+               }
+           }
+       }
+      obj = obj_lst->fetch (which);
+    }
+  delete obj_lst;
+  return true;
+}
+
+int
+DbeSession::ask_which (FILE *dis_file, FILE *inp_file,
+                      Vector<Histable*> *list, char *name)
+{
+  Histable *hitem;
+  Function *func;
+  Module *module;
+  int which, index, index1;
+  char *item_name, *lo_name, *fname, *last;
+  char buf[BUFSIZ];
+  for (;;)
+    {
+      fprintf (dis_file, GTXT ("Available name list:\n"));
+      fprintf (dis_file, GTXT ("%8d) Cancel\n"), 0);
+      Vec_loop (Histable*, list, index, hitem)
+      {
+       index1 = index + 1;
+       item_name = hitem->get_name ();
+       switch (hitem->get_type ())
+         {
+         case Histable::FUNCTION:
+           func = (Function *) hitem;
+           module = func->module;
+
+           // id == -1 indicates er_src invocation
+           if (module == NULL || (module->lang_code == Sp_lang_java
+                                  && module->loadobject->id == -1))
+               fprintf (dis_file, NTXT ("%8d) %s\n"), index1, item_name);
+           else
+             {
+               lo_name = module->loadobject->get_pathname ();
+               fname = (module->file_name && *module->file_name) ?
+                       module->file_name : module->get_name ();
+               if (fname && *fname)
+                 fprintf (dis_file, NTXT ("%8d) %s %s:0x%llx (%s)\n"), index1,
+                          item_name, lo_name, (ull_t) func->img_offset, fname);
+               else
+                 fprintf (dis_file, NTXT ("%8d) %s %s:0x%llx\n"), index1,
+                          item_name, lo_name, (ull_t) func->img_offset);
+             }
+           break;
+         case Histable::MODULE:
+           module = (Module *) hitem;
+           lo_name = module->loadobject->get_pathname ();
+           if (name[strlen (name) - 1] ==
+               module->file_name[strlen (module->file_name) - 1])
+             fprintf (dis_file, NTXT ("%8d) %s(%s)\n"), index1,
+                      module->file_name, lo_name);
+           else
+             fprintf (dis_file, NTXT ("%8d) %s(%s)\n"), index1, item_name,
+                      lo_name);
+           break;
+         default:
+           fprintf (dis_file, NTXT ("%8d) %s\n"), index1, item_name);
+           break;
+         }
+      }
+      if (inp_file != stdin)
+       return -1;
+      fprintf (dis_file, GTXT ("Enter selection: "));
+      if (fgets (buf, (int) sizeof (buf), inp_file) == NULL)
+       {
+         fprintf (stderr, GTXT ("Error: Invalid number entered:\n"));
+         return -1;
+       }
+      which = (int) getNumber (buf, last);
+      if (last && *last == '\0')
+       if (which >= 0 && which <= list->size ())
+         return which - 1;
+      fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), buf);
+    }
+}
+
+static bool
+match_basename (char *name, char *full_name, int len = -1)
+{
+  if (full_name == NULL)
+    return false;
+  if (!strchr (name, '/'))
+    full_name = get_basename (full_name);
+  if (len == -1)
+    return streq (name, full_name);
+  return strncmp (name, full_name, len) == 0;
+}
+
+LoadObject *
+DbeSession::map_NametoLoadObject (char *name, Vector<Histable*> *list, int which)
+{
+  // Search the tree to find the first module whose module name
+  //   matches "name" or whose source file name matches "name"
+  //  Issues: is the name a pathname, or a base name?
+  //   Should we look at suffix to disambiguate?
+  LoadObject *loitem;
+  int index;
+  Vec_loop (LoadObject*, lobjs, index, loitem)
+  {
+    // try pathname first
+    // if failed, try object name next
+    if (match_basename (name, loitem->get_pathname ()) ||
+       match_basename (name, loitem->get_name ()))
+      {
+       if (which == list->size ())
+         return loitem;
+       list->append (loitem);
+      }
+  }
+  return (LoadObject *) NULL;
+}
+
+Module *
+DbeSession::map_NametoModule (char *name, Vector<Histable*> *list, int which)
+{
+  // Search the tree to find the first loadobject whose loadobject name
+  //   matches "name".
+
+  //  Issues: is the name a pathname, or a base name?
+  //   Should we look at suffix to disambiguate?
+  LoadObject *loitem;
+  Module *mitem;
+  int index1, index2;
+  Vec_loop (LoadObject*, lobjs, index1, loitem)
+  {
+    Vec_loop (Module*, loitem->seg_modules, index2, mitem)
+    {
+      // try source name first
+      // if failed, try object name next
+      if (match_basename (name, mitem->file_name) ||
+         match_basename (name, mitem->get_name ()))
+       {
+         if (which == list->size ())
+           return mitem;
+         list->append (mitem);
+       }
+    }
+  }
+  return (Module *) NULL;
+}
+
+Function *
+DbeSession::map_NametoFunction (char *name, Vector<Histable*> *list,
+                               const char *sel)
+{
+  // Search the tree to find the first function whose
+  //   name matches "name".
+  //  Issues: is the name a full name, or a short name?
+  //   Is it a demangled name?  If so, what about spaces
+  //           within the name?
+  //   Is there a way to return all names that match?
+  //   How can the user specify a particular function of that name?
+  LoadObject *loitem;
+  Function *fitem, *main_func = NULL;
+  Module *mitem, *main_mod = NULL;
+  int index1, index2, index3, which = -1;
+  if (sel)
+    {
+      char *last = NULL;
+      if (*sel == '@')
+       { // 'sel' is "@seg_num:address"
+         which = (int) getNumber (sel + 1, last);
+         if (last == NULL || *last != ':' || (which < 0) || (which >= lobjs->size ()))
+           {
+             fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+             return NULL;
+           }
+         uint64_t address = getNumber (last + 1, last);
+         if (last == NULL || *last != '\0')
+           {
+             fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+             return NULL;
+           }
+         loitem = lobjs->fetch (which);
+         Vec_loop (Module*, loitem->seg_modules, index2, mitem)
+         {
+           Vec_loop (Function*, mitem->functions, index3, fitem)
+           {
+             if (address == fitem->img_offset && match_FName (name, fitem))
+               return fitem;
+           }
+         }
+         return NULL;
+       }
+
+      which = (int) getNumber (sel, last);
+      if (last == NULL || *last != '\0')
+       {
+         fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+         return NULL;
+       }
+      which--;
+    }
+
+  int len_path = 0;
+  char *with_path = name;
+  name = StrRchr (name, '`');
+  if (name != with_path)
+    len_path = (int) (name - with_path);
+  else
+    with_path = NULL;
+
+  Vec_loop (LoadObject*, lobjs, index1, loitem)
+  {
+    Vec_loop (Module*, loitem->seg_modules, index2, mitem)
+    {
+      if (with_path)
+       { // with file name
+         // try source name first
+         // if failed, try object name next
+         if (!match_basename (with_path, mitem->file_name, len_path) &&
+             !match_basename (with_path, mitem->get_name (), len_path))
+           continue;
+       }
+      Vec_loop (Function*, mitem->functions, index3, fitem)
+      {
+       if (match_FName (name, fitem))
+         {
+           if (which == list->size ())
+             return fitem;
+           list->append (fitem);
+           continue;
+         }
+       if (streq (fitem->get_name (), NTXT ("MAIN_")) && mitem->is_fortran ())
+         {
+           main_func = fitem;
+           main_mod = mitem;
+         }
+      }
+    }
+  }
+
+  if (main_mod && main_func)
+    {
+      main_mod->read_stabs ();
+      if (streq (main_func->get_match_name (), name) && which <= 1)
+       return main_func;
+    }
+  return (Function *) NULL;
+}
+
+DataObject *
+DbeSession::map_NametoDataObject (char *name, Vector<Histable*> *list,
+                                 int which)
+{
+  // Search master list to find dataobjects whose names match "name"
+  // selecting only the entry corresponding to "which" if it is not -1.
+  // Issues: is the name fully qualified or only partially?
+  DataObject *ditem = NULL;
+  int index;
+  char *full_name;
+  Vec_loop (DataObject*, dobjs, index, ditem)
+  {
+    if (ditem->scope) continue; // skip non-master dataobjects
+
+    // try fully-qualified dataobject name first
+    if ((full_name = ditem->get_name ()) != NULL)
+      {
+       if (streq (name, full_name))
+         {
+           if (which == list->size ())
+             return ditem;
+           list->append (ditem);
+         }
+      }
+  }
+  if (list->size () > 0)
+    return ditem; // return fully-qualified match
+
+  // if fully-qualified name doesn't match anything, try a partial match
+  Vec_loop (DataObject*, dobjs, index, ditem)
+  {
+    if (ditem->scope) continue; // skip non-master dataobjects
+
+    // try fully-qualified dataobject name first
+    if ((full_name = ditem->get_name ()) != NULL)
+      {
+       if (strstr (full_name, name))
+         {
+           if (which == list->size ())
+             return ditem;
+           list->append (ditem);
+         }
+      }
+  }
+  return (DataObject *) NULL;
+}
+
+bool
+DbeSession::match_FName (char *name, Function *func)
+{
+  size_t len;
+  char buf[MAXDBUF];
+  char *full_name;
+  if (streq (func->get_name (), name)) // try full name comparison
+    return true;
+  if (streq (func->get_mangled_name (), name)) // try mangled name
+    return true;
+  if (streq (func->get_match_name (), name)) // try match name
+    return true;
+
+  Module *md = func->module; // try FORTRAN name
+  if (md && md->is_fortran ())
+    {
+      char *mangled_name = func->get_mangled_name ();
+      len = strlen (name);
+      if (((len + 1) == strlen (mangled_name)) &&
+         (strncmp (name, mangled_name, len) == 0))
+       return true;
+    }
+  snprintf (buf, sizeof (buf), NTXT ("%s"), func->get_name ());
+  full_name = buf;
+  char *arg = NULL; // find modifier and C++ class name
+  int i = get_paren (buf);
+  if (i >= 0)
+    {
+      arg = buf + i;
+      *arg = '\0';
+    }
+
+  char *mod = strchr (full_name, ' ');
+  char *cls = strchr (full_name, ':');
+
+  if (mod)
+    {
+      len = mod - full_name + 1;
+      if (!strncmp (full_name, name, len))
+       name += len;
+      full_name += len;
+      if (streq (full_name, name)) // try without modifier
+       return true;
+    }
+
+  size_t len_cmp = strlen (name);
+  if (arg)
+    {
+      *arg = '(';
+      len = arg - full_name; // try without 'args'
+      if (len_cmp == len && !strncmp (full_name, name, len))
+       return true;
+      if (cls)
+       {
+         len = arg - cls - 2; // and without 'class name'
+         if ((len_cmp == len) && !strncmp (cls + 2, name, len))
+           return true;
+       }
+    }
+
+  if (cls)
+    {
+      len = cls - full_name; // try C++ class name only
+      if (len_cmp == len && !strncmp (full_name, name, len))
+       return true;
+      if (streq (cls + 2, name)) // try without 'class name'
+       return true;
+    }
+  return false;
+}
+
+bool
+DbeSession::add_path (char *path)
+{
+  return add_path (path, get_search_path ());
+}
+
+bool
+DbeSession::add_classpath (char *path)
+{
+  return add_path (path, classpath);
+}
+
+Vector<DbeFile*> *
+DbeSession::get_classpath ()
+{
+  if (classpath_df == NULL)
+    classpath_df = new Vector<DbeFile*>;
+  for (int i = classpath_df->size (), sz = classpath->size (); i < sz; i++)
+    classpath_df->store (i, getDbeFile (classpath->fetch (i),
+                                       DbeFile::F_DIR_OR_JAR));
+  return classpath_df;
+}
+
+bool
+DbeSession::add_path (char *path, Vector<char*> *pathes)
+{
+  bool result = false;
+  Vector <char *> *tokens = split_str (path, ':');
+  for (long j = 0, jsz = VecSize (tokens); j < jsz; j++)
+    {
+      char *spath = tokens->get (j);
+      // Don't append path if it's already there
+      bool got = false;
+      for (int i = 0, sz = pathes->size (); i < sz; i++)
+       {
+         char *nm = pathes->get (i);
+         if (streq (nm, spath))
+           {
+             got = true;
+             break;
+           }
+       }
+      if (!got)
+       {
+         pathes->append (spath);
+         result = true;
+       }
+      else
+       free (spath);
+    }
+  delete tokens;
+  return result;
+}
+
+void
+DbeSession::set_need_refind ()
+{
+  Vector<DbeFile*> *f_list = dbeFiles->values ();
+  for (long i = 0, sz = f_list == NULL ? 0 : f_list->size (); i < sz; i++)
+    {
+      DbeFile *f = f_list->get (i);
+      f->set_need_refind (true);
+    }
+  delete f_list;
+  for (long i = 0, sz = sources == NULL ? 0 : sources->size (); i < sz; i++)
+    {
+      SourceFile *f = sources->get (i);
+      if (f && f->dbeFile)
+       f->dbeFile->set_need_refind (true);
+    }
+}
+
+void
+DbeSession::set_search_path (Vector<char*> *path, bool reset)
+{
+  if (reset)
+    search_path->destroy ();
+  for (int i = 0, sz = path == NULL ? 0 : path->size (); i < sz; i++)
+    {
+      char *name = path->fetch (i);
+      if (add_path (name))
+       reset = true;
+    }
+  if (reset)
+    {
+      set_need_refind ();
+
+      // now reset the string setting for it
+      StringBuilder sb;
+      for (int i = 0, sz = search_path == NULL ? 0 : search_path->size (); i < sz; i++)
+       {
+         char *name = search_path->fetch (i);
+         if (sb.length () != 0)
+           sb.append (':');
+         sb.append (name);
+       }
+      free (settings->str_search_path);
+      settings->str_search_path = sb.toString ();
+    }
+}
+
+void
+DbeSession::set_search_path (char *_lpath, bool reset)
+{
+  Vector<char *> *path = new Vector<char*>;
+  char *lpath = dbe_strdup (_lpath);
+  for (char *s = lpath; s;)
+    {
+      path->append (s);
+      s = strchr (s, ':');
+      if (s)
+       {
+         *s = 0;
+         s++;
+       }
+    }
+  set_search_path (path, reset);
+  delete path;
+  free (lpath);
+}
+
+void
+DbeSession::set_pathmaps (Vector<pathmap_t*> *newPathMap)
+{
+  set_need_refind ();
+  settings->set_pathmaps (newPathMap);
+}
+
+Vector<pathmap_t*> *
+DbeSession::get_pathmaps ()
+{
+  return settings->pathmaps;
+}
+
+void
+DbeSession::mobj_define (MemObjType_t *mobj)
+{
+  settings->mobj_define (mobj, false);
+  DbeView *dbev;
+  int index;
+  Vec_loop (DbeView*, views, index, dbev)
+  {
+    dbev->get_settings ()->mobj_define (mobj, false);
+  }
+}
+
+void
+DbeSession::dump_segments (FILE *out)
+{
+  int index;
+  LoadObject *loitem;
+  Vec_loop (LoadObject*, lobjs, index, loitem)
+  {
+    fprintf (out, NTXT ("Segment %d -- %s -- %s\n\n"),
+            index, loitem->get_name (), loitem->get_pathname ());
+    loitem->dump_functions (out);
+    fprintf (out, NTXT ("\n End Segment %d -- %s -- %s\n\n"),
+            index, loitem->get_name (), loitem->get_pathname ());
+  }
+}
+
+void
+DbeSession::dump_dataobjects (FILE *out)
+{
+  DataObject *ditem;
+  int index;
+
+  fprintf (out, NTXT ("\nMaster list of DataObjects:\n"));
+  Vec_loop (DataObject*, dobjs, index, ditem)
+  {
+    Histable* scope = ditem->get_scope ();
+    DataObject* parent = ditem->get_parent ();
+    DataObject* master = ditem->get_master ();
+    if (parent != NULL)
+      fprintf (out, "id %6lld: [%4lld] parent = %6lld, offset = %+4lld %s\n",
+              (ll_t) ditem->id, (ll_t) ditem->get_size (),
+              (ll_t) parent->id, (ll_t) ditem->get_offset (),
+              ditem->get_name ());
+    else
+      {
+       // parent is NULL
+       fprintf (out, NTXT ("id %6lld: [%4lld] %s "),
+                (ll_t) ditem->id, (ll_t) ditem->get_size (),
+                ditem->get_name ());
+       if (master != NULL)
+         fprintf (out, NTXT (" master=%lld "), (ll_t) master->id);
+       else if (scope != NULL)
+         fprintf (out, NTXT (" master=?? "));
+       else
+         fprintf (out, NTXT (" MASTER "));
+#if DEBUG
+       if (scope != NULL)
+         {
+           switch (scope->get_type ())
+             {
+             case Histable::LOADOBJECT:
+             case Histable::FUNCTION:
+               fprintf (out, NTXT ("%s"), scope->get_name ());
+               break;
+             case Histable::MODULE:
+               {
+                 char *filename = get_basename (scope->get_name ());
+                 fprintf (out, NTXT ("%s"), filename);
+                 break;
+               }
+             default:
+               fprintf (out, NTXT (" Unexpected scope %d:%s"),
+                        scope->get_type (), scope->get_name ());
+             }
+         }
+#endif
+       fprintf (out, NTXT ("\n"));
+      }
+  }
+}
+
+void
+DbeSession::dump_map (FILE *out)
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    exp->dump_map (out);
+  }
+}
+
+void
+DbeSession::dump_stacks (FILE *outfile)
+{
+  Experiment *exp;
+  int n = nexps ();
+  FILE *f = (outfile == NULL ? stderr : outfile);
+  for (int i = 0; i < n; i++)
+    {
+      exp = get_exp (i);
+      fprintf (f, GTXT ("Experiment %d -- %s\n"), i, exp->get_expt_name ());
+      exp->dump_stacks (f);
+    }
+}
+
+void
+DbeSession::propNames_name_store (int propId, const char *propName)
+{
+  PropDescr *prop = new PropDescr (propId, propName);
+  prop->flags = PRFLAG_NOSHOW; // do not show descriptions
+  propNames->store (propId, prop);
+}
+
+void
+DbeSession::propNames_name_store (int propId, const char* propName,
+                                 const char* propUname, VType_type dataType,
+                                 int flags)
+{
+  PropDescr *prop = new PropDescr (propId, propName);
+  prop->vtype = dataType;
+  prop->uname = dbe_strdup (propUname);
+  prop->flags = flags;
+  propNames->store (propId, prop);
+}
+
+char *
+DbeSession::propNames_name_fetch (int i)
+{
+  PropDescr *prop = propNames->fetch (i);
+  if (prop)
+    return prop->name;
+  return NULL;
+}
+
+int
+DbeSession::registerPropertyName (const char *name)
+{
+  if (name == NULL)
+    return PROP_NONE;
+  for (int i = 0; i < propNames->size (); i++)
+    {
+      char *pname = propNames_name_fetch (i);
+      if (pname && strcasecmp (pname, name) == 0)
+       return i;
+    }
+  int propId = propNames->size ();
+  propNames_name_store (propId, name);
+  return propId;
+}
+
+int
+DbeSession::getPropIdByName (const char *name)
+{
+  if (name == NULL)
+    return PROP_NONE;
+  for (int i = 0; i < propNames->size (); i++)
+    {
+      char *pname = propNames_name_fetch (i);
+      if (pname && strcasecmp (pname, name) == 0)
+       return i;
+    }
+  return PROP_NONE;
+}
+
+char *
+DbeSession::getPropName (int propId)
+{
+  if (!propNames)
+    return NULL;
+  if (propId < 0 || propId >= propNames->size ())
+    return NULL;
+  return dbe_strdup (propNames_name_fetch (propId));
+}
+
+char *
+DbeSession::getPropUName (int propId)
+{
+  if (!propNames)
+    return NULL;
+  if (propId < 0 || propId >= propNames->size ())
+    return NULL;
+  PropDescr *prop = propNames->fetch (propId);
+  if (prop)
+    return dbe_strdup (prop->uname);
+  return NULL;
+}
+
+void
+DbeSession::append (UserLabel *lbl)
+{
+  if (lbl->expr)
+    {
+      if (userLabels == NULL)
+        userLabels = new Vector<UserLabel*> ();
+      userLabels->append (lbl);
+    }
+}
+
+void
+DbeSession::append (SourceFile *sf)
+{
+  sources->append (sf);
+  objs->append (sf);
+}
+
+UserLabel *
+DbeSession::findUserLabel (char *name)
+{
+  for (int i = 0, sz = userLabels ? userLabels->size () : 0; i < sz; i++)
+    {
+      UserLabel *lbl = userLabels->fetch (i);
+      if (strcasecmp (lbl->name, name) == 0)
+       return lbl;
+    }
+  return NULL;
+}
+
+Expression *
+DbeSession::findObjDefByName (char *name)
+{
+  Expression *expr = NULL;
+
+  MemObjType_t *mot = MemorySpace::findMemSpaceByName (name);
+  if (mot != NULL)
+    {
+      char *index_expr_str = mot->index_expr;
+      expr = ql_parse (index_expr_str);
+    }
+
+  if (expr == NULL)
+    {
+      int indxtype = findIndexSpaceByName (name);
+      expr = getIndexSpaceExpr (indxtype);
+    }
+  if (expr == NULL)
+    {
+      UserLabel *ulbl = findUserLabel (name);
+      if (ulbl)
+       expr = ulbl->expr;
+    }
+  return expr;
+}
+
+Expression *
+DbeSession::ql_parse (const char *expr_spec)
+{
+  /* (This slight duplication means we don't need to worry about copy
+     constructors for the QL::Result, nor about the lifetime of the
+     expr_spec.)  */
+  if (expr_spec != NULL)
+    {
+      QL::Result result (expr_spec);
+      QL::Parser qlparser (result);
+      if (qlparser () != 0)
+       return NULL;
+      return result ();
+    }
+  else
+    {
+      QL::Result result;
+      QL::Parser qlparser (result);
+      if (qlparser () != 0)
+       return NULL;
+      return result ();
+    }
+}
+
+Vector<void*> *
+DbeSession::getIndxObjDescriptions ()
+{
+  int size = dyn_indxobj_indx;
+  if (size == 0)
+    return NULL;
+  Vector<int> *type = new Vector<int>(dyn_indxobj_indx);
+  Vector<char*> *desc = new Vector<char*>(dyn_indxobj_indx);
+  Vector<char*> *i18ndesc = new Vector<char*>(dyn_indxobj_indx);
+  Vector<char> *mnemonic = new Vector<char>(dyn_indxobj_indx);
+  Vector<int> *orderList = new Vector<int>(dyn_indxobj_indx);
+  Vector<char*> *exprList = new Vector<char*>(dyn_indxobj_indx);
+  Vector<char*> *sdesc = new Vector<char*>(dyn_indxobj_indx);
+  Vector<char*> *ldesc = new Vector<char*>(dyn_indxobj_indx);
+
+  for (long i = 0, sz = VecSize (dyn_indxobj); i < sz; i++)
+    {
+      IndexObjType_t *tot = dyn_indxobj->get (i);
+      if (tot->memObj == NULL)
+       {
+         type->append ((int) tot->type);
+         desc->append (dbe_strdup (tot->name));
+         i18ndesc->append (dbe_strdup (tot->i18n_name));
+         sdesc->append (dbe_strdup (tot->short_description));
+         ldesc->append (dbe_strdup (tot->long_description));
+         mnemonic->append (tot->mnemonic);
+         orderList->append (settings->indx_tab_order->fetch (i));
+         exprList->append (dbe_strdup (tot->index_expr_str));
+       }
+    }
+  Vector<void*> *res = new Vector<void*>(8);
+  res->store (0, type);
+  res->store (1, desc);
+  res->store (2, mnemonic);
+  res->store (3, i18ndesc);
+  res->store (4, orderList);
+  res->store (5, exprList);
+  res->store (6, sdesc);
+  res->store (7, ldesc);
+  return (res);
+}
+
+// Static function to get a vector of custom index object definitions
+Vector<void*> *
+DbeSession::getCustomIndxObjects ()
+{
+  Vector<char*> *name = new Vector<char*>;
+  Vector<char*> *formula = new Vector<char*>;
+  for (long i = dyn_indxobj_indx_fixed, sz = VecSize (dyn_indxobj); i < sz; i++)
+    {
+      IndexObjType_t *tot = dyn_indxobj->get (i);
+      if (tot->memObj == NULL)
+       {
+         name->append (dbe_strdup (tot->name));
+         formula->append (dbe_strdup (tot->index_expr_str));
+       }
+    }
+  Vector<void*> *res = new Vector<void*>(2);
+  res->store (0, name);
+  res->store (1, formula);
+  return (res);
+}
+
+// Static function to define a new index object type
+char *
+DbeSession::indxobj_define (const char *mname, char *i18nname, const char *index_expr_str, char *short_description, char *long_description)
+{
+  if (mname == NULL)
+    return dbe_strdup (GTXT ("No index object type name has been specified."));
+  if (isalpha ((int) (mname[0])) == 0)
+    return dbe_sprintf (GTXT ("Index Object type name %s does not begin with an alphabetic character"),
+                         mname);
+  const char *p = mname;
+  while (*p != 0)
+    {
+      if ((isalnum ((int) (*p)) == 0) && (*p != '_'))
+       return dbe_sprintf (GTXT ("Index Object type name %s contains a non-alphanumeric character"),
+                           mname);
+      p++;
+    }
+
+  // make sure the name is not in use
+  if (MemorySpace::findMemSpaceByName (mname) != NULL)
+    return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
+                         mname);
+
+  int idxx = findIndexSpaceByName (mname);
+  if (idxx >= 0)
+    {
+      IndexObjType_t *mt = dyn_indxobj->fetch (idxx);
+      if (strcmp (mt->index_expr_str, index_expr_str) == 0)
+       // It's a redefinition, but the new definition is the same
+       return NULL;
+      return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
+                         mname);
+    }
+  if (index_expr_str == NULL)
+    return dbe_strdup (GTXT ("No index-expr has been specified."));
+  if (strlen (index_expr_str) == 0)
+    return dbe_sprintf (GTXT ("Index Object index expression is invalid: %s"),
+                       index_expr_str);
+
+  // verify that the index expression parses correctly
+  char *expr_str = dbe_strdup (index_expr_str);
+  Expression *expr = ql_parse (expr_str);
+  if (expr == NULL)
+    return dbe_sprintf (GTXT ("Index Object index expression is invalid: %s"),
+                       expr_str);
+
+  // It's OK, create the new table entry
+  IndexObjType_t *tot = new IndexObjType_t;
+  tot->type = dyn_indxobj_indx++;
+  tot->name = dbe_strdup (mname);
+  tot->i18n_name = dbe_strdup (i18nname);
+  tot->short_description = dbe_strdup (short_description);
+  tot->long_description = dbe_strdup (long_description);
+  tot->index_expr_str = expr_str;
+  tot->index_expr = expr;
+  tot->mnemonic = mname[0];
+
+  // add it to the list
+  dyn_indxobj->append (tot);
+  idxobjs->append (new HashMap<uint64_t, Histable*>);
+
+  // tell the session
+  settings->indxobj_define (tot->type, false);
+
+  DbeView *dbev;
+  int index;
+  Vec_loop (DbeView*, views, index, dbev)
+  {
+    dbev->addIndexSpace (tot->type);
+  }
+  return NULL;
+}
+
+char *
+DbeSession::getIndexSpaceName (int index)
+{
+  if (index < 0 || index >= dyn_indxobj->size ())
+    return NULL;
+  return dyn_indxobj->fetch (index)->name;
+}
+
+char *
+DbeSession::getIndexSpaceDescr (int index)
+{
+  if (index < 0 || index >= dyn_indxobj->size ())
+    return NULL;
+  return dyn_indxobj->fetch (index)->i18n_name;
+}
+
+Expression *
+DbeSession::getIndexSpaceExpr (int index)
+{
+  if (index < 0 || index >= dyn_indxobj->size ())
+    return NULL;
+  return dyn_indxobj->fetch (index)->index_expr;
+}
+
+char *
+DbeSession::getIndexSpaceExprStr (int index)
+{
+  if (index < 0 || index >= dyn_indxobj->size ())
+    return NULL;
+  return dyn_indxobj->fetch (index)->index_expr_str;
+}
+
+int
+DbeSession::findIndexSpaceByName (const char *mname)
+{
+  int idx;
+  IndexObjType_t *mt;
+  Vec_loop (IndexObjType_t*, dyn_indxobj, idx, mt)
+  {
+    if (strcasecmp (mt->name, mname) == 0)
+      return idx;
+  }
+  return -1;
+}
+
+void
+DbeSession::removeIndexSpaceByName (const char *mname)
+{
+  IndexObjType_t *indObj = findIndexSpace (mname);
+  if (indObj)
+    indObj->name[0] = 0;
+}
+
+IndexObjType_t *
+DbeSession::getIndexSpace (int index)
+{
+  return ((index < 0) || (index >= VecSize (dyn_indxobj))) ? NULL : dyn_indxobj->get (index);
+}
+
+IndexObjType_t *
+DbeSession::findIndexSpace (const char *mname)
+{
+  return getIndexSpace (findIndexSpaceByName (mname));
+}
+
+void
+DbeSession::get_filter_keywords (Vector<void*> *res)
+{
+  Vector <char*> *kwCategory = (Vector<char*>*) res->fetch (0);
+  Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1);
+  Vector <char*> *kwDataType = (Vector<char*>*) res->fetch (2);
+  Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3);
+  Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4);
+  Vector <char*> *kwDescription = (Vector<char*>*) res->fetch (5);
+  Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6);
+
+  char *vtypeNames[] = VTYPE_TYPE_NAMES;
+  for (long i = 0, sz = userLabels ? userLabels->size () : 0; i < sz; i++)
+    {
+      UserLabel *lbl = userLabels->fetch (i);
+      kwCategory->append (dbe_strdup (NTXT ("FK_LABEL")));
+      kwCategoryI18N->append (dbe_strdup (GTXT ("Labels")));
+      kwDataType->append (dbe_strdup (vtypeNames[TYPE_BOOL]));
+      kwKeyword->append (dbe_strdup (lbl->name));
+      kwFormula->append (dbe_strdup (lbl->str_expr));
+      kwDescription->append (dbe_strdup (lbl->comment));
+      kwEnumDescs->append (NULL);
+    }
+
+  for (long i = 0, sz = propNames ? propNames->size () : 0; i < sz; i++)
+    {
+      PropDescr *prop = propNames->fetch (i);
+      char *pname = prop ? prop->name : NULL;
+      if (pname == NULL || *pname == 0 || prop->flags & PRFLAG_NOSHOW)
+       continue;
+      int vtypeNum = prop->vtype;
+      if (vtypeNum < 0 || vtypeNum >= TYPE_LAST)
+       vtypeNum = TYPE_NONE;
+      kwCategory->append (dbe_strdup (NTXT ("FK_EVTPROP"))); //Event Property
+      kwCategoryI18N->append (dbe_strdup (GTXT ("Misc. Definitions")));
+      kwDataType->append (dbe_strdup (vtypeNames[vtypeNum]));
+      kwKeyword->append (dbe_strdup (pname));
+      kwFormula->append (NULL);
+      kwDescription->append (dbe_strdup (prop->uname));
+      kwEnumDescs->append (NULL);
+    }
+
+  for (long i = 0, sz = dyn_indxobj ? dyn_indxobj->size () : 0; i < sz; i++)
+    {
+      IndexObjType_t *obj = dyn_indxobj->get (i);
+      if (obj->memObj)
+       continue;
+      kwCategory->append (dbe_strdup (NTXT ("FK_IDXOBJ")));
+      kwCategoryI18N->append (dbe_strdup (GTXT ("Index Object Definitions")));
+      kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT64]));
+      kwKeyword->append (dbe_strdup (obj->name));
+      kwFormula->append (dbe_strdup (obj->index_expr_str));
+      kwDescription->append (dbe_strdup (obj->i18n_name));
+      kwEnumDescs->append (NULL);
+    }
+}
+
+Histable *
+DbeSession::findIndexObject (int idxtype, uint64_t idx)
+{
+  HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
+  return iobjs->get (idx);
+}
+
+Histable *
+DbeSession::createIndexObject (int idxtype, int64_t idx)
+{
+  HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
+
+  Histable *idxobj = iobjs->get (idx);
+  if (idxobj == NULL)
+    {
+      idxobj = new IndexObject (idxtype, idx);
+      if (idx == -1)
+       idxobj->set_name (dbe_strdup (GTXT ("<Unknown>")));
+      iobjs->put (idx, idxobj);
+    }
+
+  return idxobj;
+}
+
+Histable *
+DbeSession::createIndexObject (int idxtype, Histable *hobj)
+{
+  HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
+  int64_t idx = hobj ? hobj->id : -1;
+  Histable *idxobj = iobjs->get (idx);
+  if (idxobj == NULL)
+    {
+      idxobj = new IndexObject (idxtype, hobj);
+      if (idx == -1)
+       idxobj->set_name (dbe_strdup (GTXT ("<Unknown>")));
+      iobjs->put (idx, idxobj);
+    }
+
+  return idxobj;
+}
+
+Histable *
+DbeSession::findObjectById (Histable::Type type, int subtype, uint64_t id)
+{
+  switch (type)
+    {
+    case Histable::FUNCTION:
+    case Histable::MODULE:
+    case Histable::LOADOBJECT:
+      return ( id < (uint64_t) objs->size ()) ? objs->fetch ((int) id) : NULL;
+    case Histable::INDEXOBJ:
+      return findIndexObject (subtype, id);
+      // ignoring the following cases
+    case Histable::INSTR:
+    case Histable::LINE:
+    case Histable::EADDR:
+    case Histable::MEMOBJ:
+    case Histable::PAGE:
+    case Histable::DOBJECT:
+    case Histable::SOURCEFILE:
+    case Histable::IOACTFILE:
+    case Histable::IOACTVFD:
+    case Histable::IOCALLSTACK:
+    case Histable::HEAPCALLSTACK:
+    case Histable::OTHER:
+    case Histable::EXPERIMENT:
+      break;
+    }
+  return NULL;
+}
+
+// return a vector of Functions that match the regular expression input string
+Vector<JThread *> *
+DbeSession::match_java_threads (char *ustr, int matchParent,
+                               Vector<uint64_t> * &grids,
+                               Vector<uint64_t> * &expids)
+{
+  if (ustr == NULL)
+    return NULL;
+
+  char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+  regex_t regex_desc;
+  int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+  free (str);
+  if (rc)   // syntax error in parsing string
+    return NULL;
+
+  // allocate the new vector
+  Vector<JThread *> *ret = new Vector<JThread*>;
+  grids = new Vector<uint64_t>;
+  expids = new Vector<uint64_t>;
+
+  int index;
+  JThread *jthread;
+  int expid;
+  Experiment* exp;
+  Vec_loop (Experiment*, exps, expid, exp)
+  {
+
+    Vec_loop (JThread*, exp->get_jthreads (), index, jthread)
+    {
+      const char * name;
+      if (matchParent)
+       name = jthread->parent_name;
+      else
+       name = jthread->group_name;
+      if (name == NULL)
+       name = "";
+      if (!regexec (&regex_desc, name, 0, NULL, 0))
+       {
+         // this one matches
+         ret->append (jthread);
+         grids->append (exp->groupId);
+         expids->append (exp->getUserExpId ());
+       }
+    }
+  }
+
+  regfree (&regex_desc);
+  return ret;
+}
+
+// return a vector of Functions that match the regular expression input string
+Vector<Function *> *
+DbeSession::match_func_names (const char *ustr, Histable::NameFormat nfmt)
+{
+  if (ustr == NULL)
+    return NULL;
+  char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+  regex_t regex_desc;
+  int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+  free (str);
+  if (rc)   // syntax error in parsing string
+    return NULL;
+
+  // allocate the new vector
+  Vector<Function *> *ret = new Vector<Function*>;
+
+  int index;
+  Histable *obj;
+  Vec_loop (Histable*, objs, index, obj)
+  {
+    if (obj->get_type () == Histable::FUNCTION)
+      {
+       Function *func = (Function*) obj;
+       if (!regexec (&regex_desc, func->get_name (nfmt), 0, NULL, 0))
+         // this one matches
+         ret->append (func);
+      }
+  }
+  regfree (&regex_desc);
+  return ret;
+}
+
+// return a vector of Functions that match the regular expression input string
+Vector<FileData *> *
+DbeSession::match_file_names (char *ustr, Histable::NameFormat nfmt)
+{
+  if (ustr == NULL)
+    return NULL;
+  char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+  regex_t regex_desc;
+  int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+  free (str);
+  if (rc)   // syntax error in parsing string
+    return NULL;
+
+  // allocate the new vector
+  Vector<FileData *> *ret = new Vector<FileData*>;
+  int numExps = nexps ();
+  DefaultMap<int64_t, FileData*>* fDataMap;
+  Vector<FileData *> *fDataObjs;
+  FileData *fData;
+  int size;
+  for (int i = 0; i < numExps; i++)
+    {
+      Experiment *exp = get_exp (i);
+      fDataMap = exp->getFDataMap ();
+      fDataObjs = fDataMap->values ();
+      size = fDataObjs->size ();
+      for (int j = 0; j < size; j++)
+       {
+         fData = fDataObjs->fetch (j);
+         if (fData
+             && !regexec (&regex_desc, fData->get_raw_name (nfmt), 0, NULL, 0))
+           // this one matches
+           ret->append (fData);
+       }
+    }
+  regfree (&regex_desc);
+  return ret;
+}
+
+// return a vector of DataObjects that match the regular expression input string
+Vector<DataObject *> *
+DbeSession::match_dobj_names (char *ustr)
+{
+  if (ustr == NULL)
+    return NULL;
+  char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+  regex_t regex_desc;
+  int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+  free (str);
+  if (rc)   // syntax error in parsing string
+    return NULL;
+
+  // allocate the new vector
+  Vector<DataObject *> *ret = new Vector<DataObject*>;
+  int index;
+  DataObject *ditem;
+  Vec_loop (DataObject*, dobjs, index, ditem)
+  {
+    // does this one match
+    if (!regexec (&regex_desc, ditem->get_name (), 0, NULL, 0))
+      // this one matches
+      ret->append (ditem);
+  }
+  regfree (&regex_desc);
+  return ret;
+}
+
+void
+DbeSession::dump (char *msg, Vector<BaseMetric*> *mlist)
+{
+  if (msg)
+    fprintf (stderr, "%s\n", msg);
+  int sz = mlist ? mlist->size () : -1;
+  for (int i = 0; i < sz; i++)
+    {
+      BaseMetric *m = mlist->fetch (i);
+      char *s = m->dump ();
+      fprintf (stderr, "%2d %s\n", i, s);
+      free (s);
+    }
+  fprintf (stderr, "======END of mlist[%d] =========\n", sz);
+}
+
+void
+DbeSession::dump (char *msg, Vector<Metric*> *mlist)
+{
+  if (msg)
+    fprintf (stderr, "%s\n", msg);
+  int sz = mlist ? mlist->size () : -1;
+  for (int i = 0; i < sz; i++)
+    {
+      Metric *m = mlist->fetch (i);
+      char *s = m->dump ();
+      fprintf (stderr, "%2d %s\n", i, s);
+      free (s);
+    }
+  fprintf (stderr, "======END of mlist[%d] =========\n", sz);
+}
diff --git a/gprofng/src/DbeSession.cc.1 b/gprofng/src/DbeSession.cc.1
new file mode 100644 (file)
index 0000000..7d635d2
--- /dev/null
@@ -0,0 +1,3531 @@
+/* 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 <ctype.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/param.h>
+
+#include "util.h"
+#include "Application.h"
+#include "Experiment.h"
+#include "ExpGroup.h"
+#include "Expression.h"
+#include "DataObject.h"
+#include "Elf.h"
+#include "Function.h"
+#include "DbeSession.h"
+#include "LoadObject.h"
+#include "DbeSyncMap.h"
+#include "DbeThread.h"
+#include "ClassFile.h"
+#include "IndexObject.h"
+#include "PathTree.h"
+#include "Print.h"
+#include "QLParser.tab.hh"
+#include "DbeView.h"
+#include "MemorySpace.h"
+#include "Module.h"
+#include "SourceFile.h"
+#include "StringBuilder.h"
+#include "BaseMetric.h"
+#include "BaseMetricTreeNode.h"
+#include "Command.h"
+#include "UserLabel.h"
+#include "StringMap.h"
+#include "DbeFile.h"
+#include "DbeJarFile.h"
+#include "IOActivity.h"
+#include "HeapActivity.h"
+
+// This is a universal List structure to organize objects
+// of various types, even if different.
+struct List
+{
+  List *next;
+  void *val;
+};
+
+struct Countable
+{
+  Countable (void *_item)
+  {
+    item = _item;
+    ref_count = 0;
+  }
+
+  void *item;
+  int ref_count;
+};
+
+Platform_t DbeSession::platform =
+#if ARCH(SPARC)
+        Sparc;
+#elif ARCH(Aarch64)
+        Aarch64;
+#else   // ARCH(Intel)
+        Intel;
+#endif
+
+// This constant determines the size of the data object name hash table.
+static const int HTableSize         = 8192;
+static int DEFAULT_TINY_THRESHOLD   = -1;
+
+unsigned int mpmt_debug_opt = 0;
+DbeSession *dbeSession = NULL;
+
+DbeSession::DbeSession (Settings *_settings, bool _ipc_mode, bool _rdt_mode)
+{
+  dbeSession = this;
+  ipc_mode = _ipc_mode;
+  rdt_mode = _rdt_mode;
+  settings = new Settings (_settings);
+  views = new Vector<DbeView*>;
+  exps = new Vector<Experiment*>;
+  lobjs = new Vector<LoadObject*>;
+  objs = new Vector<Histable*>;
+  dobjs = new Vector<DataObject*>;
+  metrics = new Vector<Countable*>;
+  reg_metrics = new Vector<BaseMetric*>;
+  hwcentries = NULL;
+  reg_metrics_tree = NULL; // BaseMetric() requires DbeSession::ql_parse
+  idxobjs = new Vector<HashMap<uint64_t, Histable*>*>;
+  tmp_files = new Vector<char*>;
+  search_path = new Vector<char*>;
+  classpath = new Vector<char*>;
+  classpath_df = NULL;
+  expGroups = new Vector<ExpGroup*>;
+  sourcesMap = new HashMap<char*, SourceFile*>;
+  sources = new Vector<SourceFile*>;
+  comp_lobjs = new HashMap<char*, LoadObject*>;
+  comp_dbelines = new HashMap<char*, DbeLine*>;
+  comp_sources = new HashMap<char*, SourceFile*>;
+  loadObjMap = new DbeSyncMap<LoadObject>;
+  f_special = new Vector<Function*>(LastSpecialFunction);
+  omp_functions = new Vector<Function*>(OMP_LAST_STATE);
+  interactive = false;
+  lib_visibility_used = false;
+
+  // Define all known property names
+  propNames = new Vector<PropDescr*>;
+  propNames_name_store (PROP_NONE, NTXT (""));
+  propNames_name_store (PROP_ATSTAMP, NTXT ("ATSTAMP"));
+  propNames_name_store (PROP_ETSTAMP, NTXT ("ETSTAMP"));
+  propNames_name_store (PROP_TSTAMP, NTXT ("TSTAMP"));
+  propNames_name_store (PROP_THRID, NTXT ("THRID"));
+  propNames_name_store (PROP_LWPID, NTXT ("LWPID"));
+  propNames_name_store (PROP_CPUID, NTXT ("CPUID"));
+  propNames_name_store (PROP_FRINFO, NTXT ("FRINFO"));
+  propNames_name_store (PROP_EVT_TIME, NTXT ("EVT_TIME"));
+
+  // Samples
+  propNames_name_store (PROP_SMPLOBJ, NTXT ("SMPLOBJ"));
+  propNames_name_store (PROP_SAMPLE, NTXT ("SAMPLE"));
+
+  // GCEvents
+  propNames_name_store (PROP_GCEVENTOBJ, NTXT ("GCEVENTOBJ"));
+  propNames_name_store (PROP_GCEVENT, NTXT ("GCEVENT"));
+
+  // Metadata used by some packet types
+  propNames_name_store (PROP_VOIDP_OBJ, NTXT ("VOIDP_OBJ"),
+                        NULL, TYPE_UINT64, DDFLAG_NOSHOW);
+
+  // Clock profiling properties
+  propNames_name_store (PROP_UCPU, NTXT ("UCPU"));
+  propNames_name_store (PROP_SCPU, NTXT ("SCPU"));
+  propNames_name_store (PROP_TRAP, NTXT ("TRAP"));
+  propNames_name_store (PROP_TFLT, NTXT ("TFLT"));
+  propNames_name_store (PROP_DFLT, NTXT ("DFLT"));
+  propNames_name_store (PROP_KFLT, NTXT ("KFLT"));
+  propNames_name_store (PROP_ULCK, NTXT ("ULCK"));
+  propNames_name_store (PROP_TSLP, NTXT ("TSLP"));
+  propNames_name_store (PROP_WCPU, NTXT ("WCPU"));
+  propNames_name_store (PROP_TSTP, NTXT ("TSTP"));
+
+  propNames_name_store (PROP_MSTATE, NTXT ("MSTATE"));
+  propNames_name_store (PROP_NTICK, NTXT ("NTICK"));
+  propNames_name_store (PROP_OMPSTATE, NTXT ("OMPSTATE"));
+
+  // Synchronization tracing properties
+  propNames_name_store (PROP_SRQST, NTXT ("SRQST"));
+  propNames_name_store (PROP_SOBJ, NTXT ("SOBJ"));
+
+  // Hardware counter profiling properties
+  propNames_name_store (PROP_HWCTAG, NTXT ("HWCTAG"));
+  propNames_name_store (PROP_HWCINT, NTXT ("HWCINT"));
+  propNames_name_store (PROP_VADDR, NTXT ("VADDR"));
+  propNames_name_store (PROP_PADDR, NTXT ("PADDR"));
+  propNames_name_store (PROP_VIRTPC, NTXT ("VIRTPC"));
+  propNames_name_store (PROP_PHYSPC, NTXT ("PHYSPC"));
+  propNames_name_store (PROP_LWP_LGRP_HOME, NTXT ("LWP_LGRP_HOME"));
+  propNames_name_store (PROP_PS_LGRP_HOME, NTXT ("PS_LGRP_HOME"));
+  propNames_name_store (PROP_EA_PAGESIZE, NTXT ("EA_PAGESIZE"));
+  propNames_name_store (PROP_EA_LGRP, NTXT ("EA_LGRP"));
+  propNames_name_store (PROP_PC_PAGESIZE, NTXT ("PC_PAGESIZE"));
+  propNames_name_store (PROP_PC_LGRP, NTXT ("PC_LGRP"));
+  propNames_name_store (PROP_HWCDOBJ, NTXT ("HWCDOBJ"));
+  propNames_name_store (PROP_MEM_LAT, NTXT ("MEM_LAT"));
+  propNames_name_store (PROP_MEM_SRC, NTXT ("MEM_SRC"));
+
+  // Heap tracing properties
+  propNames_name_store (PROP_HTYPE, NTXT ("HTYPE"));
+  propNames_name_store (PROP_HSIZE, NTXT ("HSIZE"));
+  propNames_name_store (PROP_HVADDR, NTXT ("HVADDR"));
+  propNames_name_store (PROP_HOVADDR, NTXT ("HOVADDR"));
+  propNames_name_store (PROP_HLEAKED, NTXT ("HLEAKED"),
+                        GTXT ("Leaked bytes"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_HMEM_USAGE, NTXT ("HMEM_USAGE"));
+  propNames_name_store (PROP_HFREED, NTXT ("HFREED"),
+                        GTXT ("Freed bytes"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_HCUR_ALLOCS, NTXT ("HCUR_ALLOCS"),
+                        GTXT ("Current allocations"), TYPE_INT64, 0);
+  propNames_name_store (PROP_HCUR_NET_ALLOC, NTXT ("HCUR_NET_ALLOC"),
+                        NULL, TYPE_INT64, DDFLAG_NOSHOW);
+  propNames_name_store (PROP_HCUR_LEAKS, NTXT ("HCUR_LEAKS"),
+                        GTXT ("Current leaks"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_DDSCR_LNK, NTXT ("DDSCR_LNK"),
+                        NULL, TYPE_UINT64, DDFLAG_NOSHOW);
+
+  // IO tracing properties
+  propNames_name_store (PROP_IOTYPE, NTXT ("IOTYPE"));
+  propNames_name_store (PROP_IOFD, NTXT ("IOFD"));
+  propNames_name_store (PROP_IONBYTE, NTXT ("IONBYTE"));
+  propNames_name_store (PROP_IORQST, NTXT ("IORQST"));
+  propNames_name_store (PROP_IOOFD, NTXT ("IOOFD"));
+  propNames_name_store (PROP_IOFNAME, NTXT ("IOFNAME"));
+  propNames_name_store (PROP_IOVFD, NTXT ("IOVFD"));
+  propNames_name_store (PROP_IOFSTYPE, NTXT ("IOFSTYPE"));
+
+  // omptrace raw properties
+  propNames_name_store (PROP_CPRID, NTXT ("CPRID"));
+  propNames_name_store (PROP_PPRID, NTXT ("PPRID"));
+  propNames_name_store (PROP_TSKID, NTXT ("TSKID"));
+  propNames_name_store (PROP_PTSKID, NTXT ("PTSKID"));
+  propNames_name_store (PROP_PRPC, NTXT ("PRPC"));
+
+  // Data race detection properties
+  propNames_name_store (PROP_RID, NTXT ("RID"));
+  propNames_name_store (PROP_RTYPE, NTXT ("RTYPE"));
+  propNames_name_store (PROP_LEAFPC, NTXT ("LEAFPC"));
+  propNames_name_store (PROP_RVADDR, NTXT ("RVADDR"));
+  propNames_name_store (PROP_RCNT, NTXT ("RCNT"));
+
+  // Deadlock detection properties
+  propNames_name_store (PROP_DID, NTXT ("DID"));
+  propNames_name_store (PROP_DLTYPE, NTXT ("DLTYPE"));
+  propNames_name_store (PROP_DTYPE, NTXT ("DTYPE"));
+  propNames_name_store (PROP_DVADDR, NTXT ("DVADDR"));
+
+  // Synthetic properties (queries only)
+  propNames_name_store (PROP_STACK, NTXT ("STACK"));
+  propNames_name_store (PROP_MSTACK, NTXT ("MSTACK"));
+  propNames_name_store (PROP_USTACK, NTXT ("USTACK"));
+  propNames_name_store (PROP_XSTACK, NTXT ("XSTACK"));
+  propNames_name_store (PROP_HSTACK, NTXT ("HSTACK"));
+  propNames_name_store (PROP_STACKID, NTXT ("STACKID"));
+  //propNames_name_store( PROP_CPRID,   NTXT("CPRID") );
+  //propNames_name_store( PROP_TSKID,   NTXT("TSKID") );
+  propNames_name_store (PROP_JTHREAD, NTXT ("JTHREAD"),
+                        GTXT ("Java thread number"), TYPE_UINT64, 0);
+
+  propNames_name_store (PROP_LEAF, NTXT ("LEAF"));
+  propNames_name_store (PROP_DOBJ, NTXT ("DOBJ"));
+  propNames_name_store (PROP_SAMPLE_MAP, NTXT ("SAMPLE_MAP"));
+  propNames_name_store (PROP_GCEVENT_MAP, NTXT ("GCEVENT_MAP"));
+  propNames_name_store (PROP_PID, NTXT ("PID"),
+                        GTXT ("Process id"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_EXPID, NTXT ("EXPID"),
+                        GTXT ("Experiment id"), TYPE_UINT64, DDFLAG_NOSHOW);
+  propNames_name_store (PROP_EXPID_CMP, NTXT ("EXPID_CMP"),
+                        GTXT ("Comparable Experiment Id"), TYPE_UINT64,
+                        DDFLAG_NOSHOW); //YXXX find better description
+  propNames_name_store (PROP_EXPGRID, NTXT ("EXPGRID"),
+                        GTXT ("Comparison Group id"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_PARREG, NTXT ("PARREG"));
+  propNames_name_store (PROP_TSTAMP_LO, NTXT ("TSTAMP_LO"),
+                        GTXT ("Start Timestamp (nanoseconds)"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_TSTAMP_HI, NTXT ("TSTAMP_HI"),
+                        GTXT ("End Timestamp (nanoseconds)"), TYPE_UINT64, 0);
+  propNames_name_store (PROP_TSTAMP2, NTXT ("TSTAMP2"),
+                        GTXT ("End Timestamp (nanoseconds)"), TYPE_UINT64,
+                        DDFLAG_NOSHOW);
+  propNames_name_store (PROP_FREQ_MHZ, NTXT ("FREQ_MHZ"),
+                        GTXT ("CPU Frequency, MHz"), TYPE_UINT32, 0);
+  propNames_name_store (PROP_NTICK_USEC, NTXT ("NTICK_USEC"),
+                        GTXT ("Clock Profiling Interval, Microseconds"),
+                        TYPE_UINT64, 0);
+
+  propNames_name_store (PROP_IOHEAPBYTES, NTXT ("IOHEAPBYTES"));
+
+  propNames_name_store (PROP_STACKL, NTXT ("STACKL"));
+  propNames_name_store (PROP_MSTACKL, NTXT ("MSTACKL"));
+  propNames_name_store (PROP_USTACKL, NTXT ("USTACKL"));
+  propNames_name_store (PROP_XSTACKL, NTXT ("XSTACKL"));
+
+  propNames_name_store (PROP_STACKI, NTXT ("STACKI"));
+  propNames_name_store (PROP_MSTACKI, NTXT ("MSTACKI"));
+  propNames_name_store (PROP_USTACKI, NTXT ("USTACKI"));
+  propNames_name_store (PROP_XSTACKI, NTXT ("XSTACKI"));
+
+  // Make sure predefined names are not used for dynamic properties
+  propNames_name_store (PROP_LAST, NTXT (""));
+
+  localized_SP_UNKNOWN_NAME = GTXT ("(unknown)");
+
+  // define Index objects
+  dyn_indxobj = new Vector<IndexObjType_t*>();
+  dyn_indxobj_indx = 0;
+  char *s = dbe_sprintf (NTXT ("((EXPID_CMP<<%llu) | THRID)"),
+                         (unsigned long long) IndexObject::INDXOBJ_EXPID_SHIFT);
+  indxobj_define (NTXT ("Threads"), GTXT ("Threads"), s, NULL, NULL);
+  free (s);
+  indxobj_define (NTXT ("CPUs"), GTXT ("CPUs"), NTXT ("(CPUID)"), NULL, NULL);
+  indxobj_define (NTXT ("Samples"), GTXT ("Samples"), NTXT ("(SAMPLE_MAP)"),
+                  NULL, NULL);
+  indxobj_define (NTXT ("GCEvents"), GTXT ("GCEvents"), NTXT ("(GCEVENT_MAP)"),
+                  NULL, NULL);
+  indxobj_define (NTXT ("Seconds"), GTXT ("Seconds"),
+                  NTXT ("(TSTAMP/1000000000)"), NULL, NULL);
+  indxobj_define (NTXT ("Processes"), GTXT ("Processes"), NTXT ("(EXPID_CMP)"),
+                  NULL, NULL);
+  s = dbe_sprintf (NTXT ("((EXPGRID<<%llu) | (EXPID<<%llu))"),
+                   (unsigned long long) IndexObject::INDXOBJ_EXPGRID_SHIFT,
+                   (unsigned long long) IndexObject::INDXOBJ_EXPID_SHIFT);
+  indxobj_define (NTXT ("Experiment_IDs"), GTXT ("Experiment_IDs"), s, NULL, NULL);
+  free (s);
+  indxobj_define (NTXT ("Datasize"), GTXT ("Datasize"),
+                  "(IOHEAPBYTES==0?0:"
+                  "((IOHEAPBYTES<=(1<<0)?(1<<0):"
+                  "((IOHEAPBYTES<=(1<<2)?(1<<2):"
+                  "((IOHEAPBYTES<=(1<<4)?(1<<4):"
+                  "((IOHEAPBYTES<=(1<<6)?(1<<6):"
+                  "((IOHEAPBYTES<=(1<<8)?(1<<8):"
+                  "((IOHEAPBYTES<=(1<<10)?(1<<10):"
+                  "((IOHEAPBYTES<=(1<<12)?(1<<12):"
+                  "((IOHEAPBYTES<=(1<<14)?(1<<14):"
+                  "((IOHEAPBYTES<=(1<<16)?(1<<16):"
+                  "((IOHEAPBYTES<=(1<<18)?(1<<18):"
+                  "((IOHEAPBYTES<=(1<<20)?(1<<20):"
+                  "((IOHEAPBYTES<=(1<<22)?(1<<22):"
+                  "((IOHEAPBYTES<=(1<<24)?(1<<24):"
+                  "((IOHEAPBYTES<=(1<<26)?(1<<26):"
+                  "((IOHEAPBYTES<=(1<<28)?(1<<28):"
+                  "((IOHEAPBYTES<=(1<<30)?(1<<30):"
+                  "((IOHEAPBYTES<=(1<<32)?(1<<32):"
+                  "((IOHEAPBYTES<=(1<<34)?(1<<34):"
+                  "((IOHEAPBYTES<=(1<<36)?(1<<36):"
+                  "((IOHEAPBYTES<=(1<<38)?(1<<38):"
+                  "((IOHEAPBYTES<=(1<<40)?(1<<40):"
+                  "((IOHEAPBYTES<=(1<<42)?(1<<42):"
+                  "((IOHEAPBYTES<=(1<<44)?(1<<44):"
+                  "((IOHEAPBYTES<=(1<<46)?(1<<46):"
+                  "((IOHEAPBYTES<=(1<<48)?(1<<48):"
+                  "((IOHEAPBYTES<=(1<<50)?(1<<50):"
+                  "(IOHEAPBYTES==-1?-1:(1<<50|1)"
+                  "))))))))))))))))))))))))))))))))))))))))))))))))))))))",
+                  NULL, NULL);
+  indxobj_define (NTXT ("Duration"), GTXT ("Duration"),
+                  "((TSTAMP_HI-TSTAMP_LO)==0?0:"
+                  "(((TSTAMP_HI-TSTAMP_LO)<=1000?1000:"
+                  "(((TSTAMP_HI-TSTAMP_LO)<=10000?10000:"
+                  "(((TSTAMP_HI-TSTAMP_LO)<=100000?100000:"
+                  "(((TSTAMP_HI-TSTAMP_LO)<=1000000?1000000:"
+                  "(((TSTAMP_HI-TSTAMP_LO)<=10000000?10000000:"
+                  "(((TSTAMP_HI-TSTAMP_LO)<=100000000?100000000:"
+                  "(((TSTAMP_HI-TSTAMP_LO)<=1000000000?1000000000:"
+                  "(((TSTAMP_HI-TSTAMP_LO)<=10000000000?10000000000:"
+                  "(((TSTAMP_HI-TSTAMP_LO)<=100000000000?100000000000:"
+                  "(((TSTAMP_HI-TSTAMP_LO)<=1000000000000?1000000000000:"
+                  "(((TSTAMP_HI-TSTAMP_LO)<=10000000000000?10000000000000:"
+                  "(10000000000001))))))))))))))))))))))))", NULL, NULL);
+  dyn_indxobj_indx_fixed = dyn_indxobj_indx;
+  Elf::elf_init ();
+  defExpName = NULL;
+  mach_model_loaded = NULL;
+  tmp_dir_name = NULL;
+  settings->read_rc (ipc_mode || rdt_mode);
+
+  init ();
+}
+
+DbeSession::~DbeSession ()
+{
+  Destroy (views);
+  Destroy (exps);
+  Destroy (dobjs);
+  Destroy (metrics);
+  Destroy (search_path);
+  Destroy (classpath);
+  Destroy (propNames);
+  Destroy (expGroups);
+  Destroy (userLabels);
+  if (hwcentries)
+    {
+      for (long i = 0, sz = hwcentries->size (); i < sz; i++)
+        {
+          Hwcentry *h = hwcentries->get (i);
+          free (h->int_name);
+          free (h->name);
+          delete h;
+        }
+      delete hwcentries;
+    }
+
+  if (idxobjs)
+    {
+      for (int i = 0; i < idxobjs->size (); ++i)
+        {
+          HashMap<uint64_t, Histable*> *hMap = idxobjs->get (i);
+          if (hMap)
+            {
+              hMap->values ()->destroy ();
+              delete hMap;
+            }
+        }
+      delete idxobjs;
+    }
+
+  for (int i = 0; i < HTableSize; i++)
+    {
+      List *list = dnameHTable[i];
+      while (list)
+        {
+          List *tmp = list;
+          list = list->next;
+          delete tmp;
+        }
+    }
+  delete[] dnameHTable;
+  delete classpath_df;
+  Destroy (objs);
+  Destroy (reg_metrics);
+  Destroy (dyn_indxobj);
+  delete lobjs;
+  delete f_special;
+  destroy_map (DbeFile *, dbeFiles);
+  destroy_map (DbeJarFile *, dbeJarFiles);
+  delete loadObjMap;
+  delete omp_functions;
+  delete sourcesMap;
+  delete sources;
+  delete comp_lobjs;
+  delete comp_dbelines;
+  delete comp_sources;
+  delete reg_metrics_tree;
+  delete settings;
+  free (mach_model_loaded);
+
+  if (defExpName != NULL)
+    {
+      StringBuilder *sb = new StringBuilder ();
+      sb->append (NTXT ("/bin/rm -rf "));
+      sb->append (defExpName);
+      char *cmd = sb->toString ();
+      system (cmd);
+      free (cmd);
+      delete sb;
+      free (defExpName);
+    }
+  unlink_tmp_files ();
+  delete tmp_files;
+  dbeSession = NULL;
+}
+
+void
+DbeSession::unlink_tmp_files ()
+{
+  if (tmp_files)
+    {
+      for (int i = 0, sz = tmp_files->size (); i < sz; i++)
+        unlink (tmp_files->fetch (i));
+      tmp_files->destroy ();
+      delete tmp_files;
+      tmp_files = NULL;
+    }
+  if (tmp_dir_name)
+    {
+      char *cmd = dbe_sprintf (NTXT ("/bin/rm -rf %s"), tmp_dir_name);
+      system (cmd);
+      free (cmd);
+      free (tmp_dir_name);
+      tmp_dir_name = NULL;
+    }
+}
+
+char *
+DbeSession::get_tmp_file_name (const char *nm, bool for_java)
+{
+  if (tmp_dir_name == NULL)
+    {
+      tmp_dir_name = dbe_sprintf (NTXT ("/tmp/analyzer.%llu.%lld"),
+                         (unsigned long long) getuid (), (long long) getpid ());
+      mkdir (tmp_dir_name, S_IRWXU);
+    }
+  char *fnm = dbe_sprintf (NTXT ("%s/%s"), tmp_dir_name, nm);
+  if (for_java)
+    for (char *s = fnm + strlen (tmp_dir_name) + 1; *s; s++)
+      if (*s == '/')
+        *s = '.';
+  return fnm;
+}
+
+void
+DbeSession::init ()
+{
+  user_exp_id_counter = 0;
+  status_ompavail = 0;
+  archive_mode = 0;
+
+#if DEBUG
+  char *s = getenv (NTXT ("MPMT_DEBUG"));
+  if (s)
+    mpmt_debug_opt = atoi (s);
+#endif /* DEBUG */
+  dbeFiles = new StringMap<DbeFile*>();
+  dbeJarFiles = new StringMap<DbeJarFile*>(128, 128);
+
+  // set up the initial (after .rc file reading) search path
+  set_search_path (settings->str_search_path, true);
+  userLabels = NULL;
+
+  // Preset all objects as they may reuse each other
+  lo_unknown = NULL;
+  f_unknown = NULL;
+  j_unknown = NULL;
+  lo_total = NULL;
+  sf_unknown = NULL;
+  f_total = NULL;
+  f_jvm = NULL;
+  d_total = NULL;
+  d_scalars = NULL;
+  d_unknown = NULL;
+  expGroups->destroy ();
+  f_special->reset ();
+  for (int i = 0; i < LastSpecialFunction; i++)
+    f_special->append (NULL);
+
+  lo_omp = NULL;
+  omp_functions->reset ();
+  for (int i = 0; i < OMP_LAST_STATE; i++)
+    omp_functions->append (NULL);
+
+  // make sure the metric list is initialized
+  register_metric (Metric::SIZES);
+  register_metric (Metric::ADDRESS);
+  register_metric (Metric::ONAME);
+
+  // This is needed only to maintain loadobject id's
+  // for <Total> and <Unknown> in tests 
+  (void) get_Unknown_LoadObject ();
+  (void) get_Total_LoadObject ();
+
+  // Create the data object name hash table.
+  dnameHTable = new List*[HTableSize];
+  for (int i = 0; i < HTableSize; i++)
+    dnameHTable[i] = NULL;
+
+  d_total = createDataObject ();
+  d_total->set_name (NTXT ("<Total>"));
+
+  // XXXX <Scalars> only appropriate for Program/Data-oriented analyses
+  d_scalars = createDataObject ();
+  d_scalars->set_name (GTXT ("<Scalars>"));
+
+  d_unknown = createDataObject ();
+  d_unknown->set_name (GTXT ("<Unknown>"));
+
+  // assign d_unknown's children so data_olayout has consistent sorting
+  for (unsigned pp_code = 1; pp_code < NUM_ABS_PP_CODES + 2; pp_code++)
+    {
+      char *errcode;
+      DataObject* dobj = createDataObject ();
+      switch (pp_code)
+        {
+        case NUM_ABS_PP_CODES + 1:
+          errcode = PTXT (DOBJ_UNDETERMINED);
+          break;
+        case NUM_ABS_PP_CODES:
+          errcode = PTXT (DOBJ_UNSPECIFIED);
+          break;
+        case NUM_ABS_PP_CODES - 1:
+          errcode = PTXT (DOBJ_UNIDENTIFIED);
+          break;
+        default:
+          errcode = PTXT (ABS_PP_CODES[pp_code]);
+        }
+      dobj->parent = d_unknown;
+      dobj->set_dobjname (errcode, NULL); // dobj->parent must already be set
+    }
+
+  for (unsigned rt_code = 1; rt_code < NUM_ABS_RT_CODES - 1; rt_code++)
+    {
+      DataObject* dobj = createDataObject ();
+      dobj->parent = d_unknown;
+      dobj->set_dobjname (PTXT (ABS_RT_CODES[rt_code]), NULL); // dobj->parent must already be set
+    }
+}
+
+void
+DbeSession::reset_data ()
+{
+  for (long i = 0, sz = VecSize (idxobjs); i < sz; ++i)
+    if (idxobjs->get (i))
+      idxobjs->get (i)->reset ();
+}
+
+void
+DbeSession::reset ()
+{
+  loadObjMap->reset ();
+  DbeView *dbev;
+  int index;
+
+  Vec_loop (DbeView*, views, index, dbev)
+  {
+    dbev->reset ();
+  }
+
+  destroy_map (DbeFile *, dbeFiles);
+  destroy_map (DbeJarFile *, dbeJarFiles);
+  exps->destroy ();
+  lobjs->reset ();      // all LoadObjects belong to objs
+  dobjs->destroy ();    // deletes d_unknown and d_total as well
+  objs->destroy ();
+  comp_lobjs->clear ();
+  comp_dbelines->clear ();
+  comp_sources->clear ();
+  sourcesMap->clear ();
+  sources->reset ();
+
+  // Delete the data object name hash table.
+  for (int i = 0; i < HTableSize; i++)
+    {
+      List *list = dnameHTable[i];
+      while (list)
+        {
+          List *tmp = list;
+          list = list->next;
+          delete tmp;
+        }
+    }
+  delete[] dnameHTable;
+
+  // IndexObect definitions remain, objects themselves may go
+  for (int i = 0; i < idxobjs->size (); ++i)
+    {
+      HashMap<uint64_t, Histable*> *v = idxobjs->fetch (i);
+      if (v != NULL)
+        {
+          v->values ()->destroy ();
+          v->clear ();
+        }
+    }
+  init ();
+}
+
+Vector<SourceFile*> *
+DbeSession::get_sources ()
+{
+  return sources;
+}
+
+DbeFile *
+DbeSession::getDbeFile (char *filename, int filetype)
+{
+  Dprintf (DEBUG_DBE_FILE, NTXT ("DbeSession::getDbeFile  filetype=0x%x %s\n"), filetype, filename);
+  if (strncmp (filename, NTXT ("./"), 2) == 0)
+    filename += 2;
+  DbeFile *dbeFile = dbeFiles->get (filename);
+  if (dbeFile == NULL)
+    {
+      dbeFile = new DbeFile (filename);
+      dbeFiles->put (filename, dbeFile);
+    }
+  dbeFile->filetype |= filetype;
+  return dbeFile;
+}
+
+LoadObject *
+DbeSession::get_Total_LoadObject ()
+{
+  if (lo_total == NULL)
+    {
+      lo_total = createLoadObject (NTXT ("<Total>"));
+      lo_total->dbeFile->filetype |= DbeFile::F_FICTION;
+    }
+  return lo_total;
+}
+
+Function *
+DbeSession::get_Total_Function ()
+{
+  if (f_total == NULL)
+    {
+      f_total = createFunction ();
+      f_total->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+      f_total->set_name (NTXT ("<Total>"));
+      Module *mod = get_Total_LoadObject ()->noname;
+      f_total->module = mod;
+      mod->functions->append (f_total);
+    }
+  return f_total;
+}
+
+LoadObject *
+DbeSession::get_Unknown_LoadObject ()
+{
+  if (lo_unknown == NULL)
+    {
+      lo_unknown = createLoadObject (GTXT ("<Unknown>"));
+      lo_unknown->type = LoadObject::SEG_TEXT; // makes it expandable
+      lo_unknown->dbeFile->filetype |= DbeFile::F_FICTION;
+
+      // force creation of the <Unknown> function
+      (void) get_Unknown_Function ();
+    }
+  return lo_unknown;
+}
+
+SourceFile *
+DbeSession::get_Unknown_Source ()
+{
+  if (sf_unknown == NULL)
+    {
+      sf_unknown = createSourceFile (localized_SP_UNKNOWN_NAME);
+      sf_unknown->dbeFile->filetype |= DbeFile::F_FICTION;
+      sf_unknown->flags |= SOURCE_FLAG_UNKNOWN;
+    }
+  return sf_unknown;
+}
+
+Function *
+DbeSession::get_Unknown_Function ()
+{
+  if (f_unknown == NULL)
+    {
+      f_unknown = createFunction ();
+      f_unknown->flags |= FUNC_FLAG_SIMULATED;
+      f_unknown->set_name (GTXT ("<Unknown>"));
+      Module *mod = get_Unknown_LoadObject ()->noname;
+      f_unknown->module = mod;
+      mod->functions->append (f_unknown);
+    }
+  return f_unknown;
+}
+
+// LIBRARY_VISIBILITY
+
+Function *
+DbeSession::create_hide_function (LoadObject *lo)
+{
+  Function *h_function = createFunction ();
+  h_function->set_name (lo->get_name ());
+  h_function->module = lo->noname;
+  h_function->isHideFunc = true;
+  lo->noname->functions->append (h_function);
+  return h_function;
+}
+
+Function *
+DbeSession::get_JUnknown_Function ()
+{
+  if (j_unknown == NULL)
+    {
+      j_unknown = createFunction ();
+      j_unknown->flags |= FUNC_FLAG_SIMULATED;
+      j_unknown->set_name (GTXT ("<no Java callstack recorded>"));
+      Module *mod = get_Unknown_LoadObject ()->noname;
+      j_unknown->module = mod;
+      mod->functions->append (j_unknown);
+    }
+  return j_unknown;
+}
+
+Function *
+DbeSession::get_jvm_Function ()
+{
+  if (f_jvm == NULL)
+    {
+      f_jvm = createFunction ();
+      f_jvm->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+      f_jvm->set_name (GTXT ("<JVM-System>"));
+
+      // Find the JVM LoadObject
+      LoadObject *jvm = get_Unknown_LoadObject ();
+      for (int i = 0; i < lobjs->size (); ++i)
+        {
+          LoadObject *lo = lobjs->fetch (i);
+          if (lo->flags & SEG_FLAG_JVM)
+            {
+              jvm = lo;
+              break;
+            }
+        }
+      Module *mod = jvm->noname;
+      f_jvm->module = mod;
+      mod->functions->append (f_jvm);
+      // XXXX is it required? no consistency among all special functions
+      // jvm->functions->append( f_jvm );
+    }
+  return f_jvm;
+}
+
+Function *
+DbeSession::getSpecialFunction (SpecialFunction kind)
+{
+  if (kind < 0 || kind >= LastSpecialFunction)
+    return NULL;
+
+  Function *func = f_special->fetch (kind);
+  if (func == NULL)
+    {
+      char *fname;
+      switch (kind)
+        {
+        case TruncatedStackFunc:
+          fname = GTXT ("<Truncated-stack>");
+          break;
+        case FailedUnwindFunc:
+          fname = GTXT ("<Stack-unwind-failed>");
+          break;
+        default:
+          return NULL;
+        }
+      func = createFunction ();
+      func->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+      Module *mod = get_Total_LoadObject ()->noname;
+      func->module = mod;
+      mod->functions->append (func);
+      func->set_name (fname);
+      f_special->store (kind, func);
+    }
+  return func;
+}
+
+LoadObject *
+DbeSession::get_OMP_LoadObject ()
+{
+  if (lo_omp == NULL)
+    {
+      for (int i = 0, sz = lobjs->size (); i < sz; i++)
+        {
+          LoadObject *lo = lobjs->fetch (i);
+          if (lo->flags & SEG_FLAG_OMP)
+            {
+              lo_omp = lo;
+              return lo_omp;
+            }
+        }
+      lo_omp = createLoadObject (GTXT ("<OMP>"));
+      lo_omp->type = LoadObject::SEG_TEXT;
+      lo_omp->dbeFile->filetype |= DbeFile::F_FICTION;
+    }
+  return lo_omp;
+}
+
+Function *
+DbeSession::get_OMP_Function (int n)
+{
+  if (n < 0 || n >= OMP_LAST_STATE)
+    return NULL;
+
+  Function *func = omp_functions->fetch (n);
+  if (func == NULL)
+    {
+      char *fname;
+      switch (n)
+        {
+        case OMP_OVHD_STATE:
+          fname = GTXT ("<OMP-overhead>");
+          break;
+        case OMP_IDLE_STATE:
+          fname = GTXT ("<OMP-idle>");
+          break;
+        case OMP_RDUC_STATE:
+          fname = GTXT ("<OMP-reduction>");
+          break;
+        case OMP_IBAR_STATE:
+          fname = GTXT ("<OMP-implicit_barrier>");
+          break;
+        case OMP_EBAR_STATE:
+          fname = GTXT ("<OMP-explicit_barrier>");
+          break;
+        case OMP_LKWT_STATE:
+          fname = GTXT ("<OMP-lock_wait>");
+          break;
+        case OMP_CTWT_STATE:
+          fname = GTXT ("<OMP-critical_section_wait>");
+          break;
+        case OMP_ODWT_STATE:
+          fname = GTXT ("<OMP-ordered_section_wait>");
+          break;
+        case OMP_ATWT_STATE:
+          fname = GTXT ("<OMP-atomic_wait>");
+          break;
+        default:
+          return NULL;
+        }
+      func = createFunction ();
+      func->flags |= FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET;
+      func->set_name (fname);
+
+      LoadObject *omp = get_OMP_LoadObject ();
+      func->module = omp->noname;
+      omp->noname->functions->append (func);
+      omp->functions->append (func);
+      omp_functions->store (n, func);
+    }
+  return func;
+}
+
+// Divide the original createExperiment() into two steps
+// In part1, we just create the data structure, in part2, if
+// we decide to keep the experiment around, add it to various
+// lists in DbeSession
+Experiment *
+DbeSession::createExperimentPart1 ()
+{
+  Experiment *exp = new Experiment ();
+  return exp;
+}
+
+void
+DbeSession::createExperimentPart2 (Experiment *exp)
+{
+  int ind = expGroups->size ();
+  if (ind > 0)
+    {
+      ExpGroup *gr = expGroups->fetch (ind - 1);
+      exp->groupId = gr->groupId;
+      gr->append (exp);
+    }
+  exp->setExpIdx (exps->size ());
+  exp->setUserExpId (++user_exp_id_counter);
+  exps->append (exp);
+}
+
+Experiment *
+DbeSession::createExperiment ()
+{
+  Experiment *exp = new Experiment ();
+  append (exp);
+  return exp;
+}
+
+void
+DbeSession::append (Experiment *exp)
+{
+  exp->setExpIdx (exps->size ());
+  exp->setUserExpId (++user_exp_id_counter);
+  exps->append (exp);
+  if (exp->founder_exp)
+    {
+      if (exp->founder_exp->children_exps == NULL)
+        exp->founder_exp->children_exps = new Vector<Experiment *>;
+      exp->founder_exp->children_exps->append (exp);
+      if (exp->founder_exp->groupId > 0)
+        {
+          exp->groupId = exp->founder_exp->groupId;
+          expGroups->get (exp->groupId - 1)->append (exp);
+        }
+    }
+  if (exp->groupId == 0)
+    {
+      long ind = VecSize (expGroups);
+      if (ind > 0)
+        {
+          ExpGroup *gr = expGroups->get (ind - 1);
+          exp->groupId = gr->groupId;
+          gr->append (exp);
+        }
+    }
+}
+
+void
+DbeSession::append (Hwcentry *h)
+{
+  if (hwcentries == NULL)
+    hwcentries = new Vector<Hwcentry*>;
+  hwcentries->append (h);
+}
+
+int
+DbeSession::ngoodexps ()
+{
+  int cnt = 0;
+  for (long i = 0, sz = VecSize (exps); i < sz; i++)
+    if (exps->get (i)->get_status () == Experiment::SUCCESS)
+      cnt++;
+  return cnt;
+}
+
+int
+DbeSession::createView (int index, int cloneindex)
+{
+  // ensure that there is no view with that index
+  DbeView *dbev = getView (index);
+  if (dbev != NULL)
+    abort ();
+
+  // find the view to be cloned
+  dbev = getView (cloneindex);
+  DbeView *newview;
+  if (dbev == NULL)
+    newview = new DbeView (theApplication, settings, index);
+  else
+    newview = new DbeView (dbev, index);
+  views->append (newview);
+  return index;
+}
+
+DbeView *
+DbeSession::getView (int index)
+{
+  int i;
+  DbeView *dbev;
+  Vec_loop (DbeView*, views, i, dbev)
+  {
+    if (dbev->vindex == index)
+      return dbev;
+  }
+  return NULL;
+}
+
+void
+DbeSession::dropView (int index)
+{
+  int i;
+  DbeView *dbev;
+
+  Vec_loop (DbeView*, views, i, dbev)
+  {
+    if (dbev->vindex == index)
+      {
+        views->remove (i);
+        delete dbev;
+        return;
+      }
+  }
+  // view not found; ignore for now
+}
+
+Vector<char*> *
+DbeSession::get_group_or_expt (char *path)
+{
+  Vector<char*> *exp_list = new Vector<char*>;
+  FILE *fptr;
+  char *new_path, buf[MAXPATHLEN], name[MAXPATHLEN];
+
+  fptr = fopen (path, NTXT ("r"));
+  if (!fptr || !fgets (buf, (int) sizeof (buf), fptr)
+      || strncmp (buf, SP_GROUP_HEADER, strlen (SP_GROUP_HEADER)))
+    {
+      // it's not an experiment group
+      new_path = dbe_strdup (path);
+      new_path = canonical_path (new_path);
+      exp_list->append (new_path);
+    }
+  else
+    {
+      // it is an experiment group, read the list to get them all
+      while (fgets (buf, (int) sizeof (buf), fptr))
+        {
+          if ((*buf != '#') && (sscanf (buf, NTXT ("%s"), name) == 1))
+            {
+              new_path = dbe_strdup (name);
+              new_path = canonical_path (new_path);
+              exp_list->append (new_path);
+            }
+        }
+    }
+  if (fptr)
+    fclose (fptr);
+  return exp_list;
+}
+
+#define GET_INT_VAL(v, s, len) \
+    for (v = len = 0; isdigit(*s); s++, len++) { v = v * 10 + (*s -'0'); }
+
+static int
+dir_name_cmp (const void *a, const void *b)
+{
+  char *s1 = *((char **) a);
+  char *s2 = *((char **) b);
+  while (*s1)
+    {
+      if (isdigit (*s1) && isdigit (*s2))
+        {
+          int v1, v2, len1, len2;
+          GET_INT_VAL (v1, s1, len1);
+          GET_INT_VAL (v2, s2, len2);
+          if (v1 != v2)
+            return v1 - v2;
+          if (len1 != len2)
+            return len2 - len1;
+          continue;
+        }
+      if (*s1 != *s2)
+        break;
+      s1++;
+      s2++;
+    }
+  return *s1 - *s2;
+}
+
+static int
+read_experiment_data_in_parallel (void *arg)
+{
+  exp_ctx *ctx = (exp_ctx *) arg;
+  Experiment *dexp = ctx->exp;
+  bool read_ahead = ctx->read_ahead;
+  dexp->read_experiment_data (read_ahead);
+  free (ctx);
+  return 0;
+}
+
+void
+DbeSession::open_experiment (Experiment *exp, char *path)
+{
+  exp->open (path);
+  if (exp->get_status () != Experiment::FAILURE)
+    exp->read_experiment_data (false);
+  exp->open_epilogue ();
+
+  // Update all DbeViews 
+  for (int i = 0, sz = views->size (); i < sz; i++)
+    {
+      DbeView *dbev = views->fetch (i);
+      dbev->add_experiment (exp->getExpIdx (), true);
+    }
+
+  if (exp->get_status () == Experiment::FAILURE)
+    {
+      check_tab_avail ();
+      return;
+    }
+
+  char *discard_tiny = getenv (NTXT ("SP_ANALYZER_DISCARD_TINY_EXPERIMENTS"));
+  int user_specified_tiny_threshold = DEFAULT_TINY_THRESHOLD; // in milliseconds
+  if (discard_tiny != NULL)
+    {
+      user_specified_tiny_threshold = (atoi (discard_tiny));
+      if (user_specified_tiny_threshold < 0)
+        user_specified_tiny_threshold = DEFAULT_TINY_THRESHOLD;
+    }
+
+  // Open descendant experiments
+  DIR *exp_dir = opendir (path);
+  if (exp_dir == NULL)
+    {
+      check_tab_avail ();
+      return;
+    }
+
+  Vector<char*> *exp_names = new Vector<char*>();
+  struct dirent *entry = NULL;
+  while ((entry = readdir (exp_dir)) != NULL)
+    {
+      if (entry->d_name[0] != '_')
+        continue;
+      size_t len = strlen (entry->d_name);
+      if (len < 3 || strcmp (entry->d_name + len - 3, NTXT (".er")) != 0)
+        continue;
+      exp_names->append (dbe_strdup (entry->d_name));
+    }
+  closedir (exp_dir);
+  exp_names->sort (dir_name_cmp);
+  Experiment **t_exp_list = new Experiment *[exp_names->size ()];
+  int nsubexps = 0;
+
+  for (int j = 0, jsz = exp_names->size (); j < jsz; j++)
+    {
+      t_exp_list[j] = NULL;
+
+      char *lineage_name = exp_names->fetch (j);
+      struct stat64 sbuf;
+      char *dpath = dbe_sprintf (NTXT ("%s/%s"), path, lineage_name);
+
+      // look for experiments with no profile collected
+      if (user_specified_tiny_threshold == DEFAULT_TINY_THRESHOLD)
+        {
+          char *frinfoname = dbe_sprintf (NTXT ("%s/%s"), dpath, "data." SP_FRINFO_FILE);
+          int st = dbe_stat (frinfoname, &sbuf);
+          free (frinfoname);
+          if (st == 0)
+            {
+              // if no profile/trace data do not process this experiment any further
+              if (sbuf.st_size == 0)
+                {
+                  free (dpath);
+                  continue;
+                }
+            }
+        }
+      else
+        { // check if dpath is a directory
+          if (dbe_stat (dpath, &sbuf) != 0)
+            {
+              free (dpath);
+              continue;
+            }
+          else if (!S_ISDIR (sbuf.st_mode))
+            {
+              free (dpath);
+              continue;
+            }
+        }
+      size_t lineage_name_len = strlen (lineage_name);
+      lineage_name[lineage_name_len - 3] = 0; /* remove .er */
+      Experiment *dexp = new Experiment ();
+      dexp->founder_exp = exp;
+      if (user_specified_tiny_threshold > DEFAULT_TINY_THRESHOLD)
+        {
+          dexp->setTinyThreshold (user_specified_tiny_threshold);
+          dexp->open (dpath);
+          if (dexp->isDiscardedTinyExperiment ())
+            {
+              delete dexp;
+              free (dpath);
+              continue;
+            }
+        }
+      else
+        dexp->open (dpath);
+      append (dexp);
+      t_exp_list[j] = dexp;
+      nsubexps++;
+      dexp->set_clock (exp->clock);
+
+      // DbeView add_experiment() is split into two parts
+      // add_subexperiment() is called repeeatedly for
+      // all sub_experiments, later add_experiment_epilogue() finishes up the task
+      for (int i = 0, sz = views->size (); i < sz; i++)
+        {
+          DbeView *dbev = views->fetch (i);
+          bool enabled = settings->check_en_desc (lineage_name, dexp->utargname);
+          dbev->add_subexperiment (dexp->getExpIdx (), enabled);
+        }
+      free (dpath);
+    }
+
+  for (int i = 0, sz = views->size (); i < sz; i++)
+    {
+      DbeView *dbev = views->fetch (i);
+      dbev->add_experiment_epilogue ();
+    }
+
+  DbeThreadPool * threadPool = new DbeThreadPool (-1);
+  for (int j = 0, jsz = exp_names->size (); j < jsz; j++)
+    {
+      if (t_exp_list[j] == NULL) continue;
+      Experiment *dexp = t_exp_list[j];
+      exp_ctx *new_ctx = (exp_ctx*) malloc (sizeof (exp_ctx));
+      new_ctx->path = NULL;
+      new_ctx->exp = dexp;
+      new_ctx->ds = this;
+      new_ctx->read_ahead = true;
+      DbeQueue *q = new DbeQueue (read_experiment_data_in_parallel, new_ctx);
+      threadPool->put_queue (q);
+    }
+  threadPool->wait_queues ();
+  delete threadPool;
+
+  for (long j = 0, jsz = exp_names->size (); j < jsz; j++)
+    {
+      if (t_exp_list[j] == NULL) continue;
+      Experiment *dexp = t_exp_list[j];
+      dexp->open_epilogue ();
+    }
+  exp_names->destroy ();
+  delete[] t_exp_list;
+  delete exp_names;
+
+  // update setting for leaklist and dataspace
+  check_tab_avail ();
+}
+
+void
+DbeSession::append_mesgs (StringBuilder *sb, char *path, Experiment *exp)
+{
+  if (exp->fetch_errors () != NULL)
+    {
+      // yes, there were errors
+      char *ststr = pr_mesgs (exp->fetch_errors (), NTXT (""), NTXT (""));
+      sb->append (path);
+      sb->append (NTXT (": "));
+      sb->append (ststr);
+      free (ststr);
+    }
+
+  Emsg *m = exp->fetch_warnings ();
+  if (m != NULL)
+    {
+      sb->append (path);
+      sb->append (NTXT (": "));
+      if (!is_interactive ())
+        sb->append (GTXT ("Experiment has warnings, see header for details\n"));
+      else
+        sb->append (GTXT ("Experiment has warnings, see experiment panel for details\n"));
+    }
+
+  // Check for descendant experiments that are not loaded
+  int num_desc = VecSize (exp->children_exps);
+  if ((num_desc > 0) && !settings->check_en_desc (NULL, NULL))
+    {
+      char *s;
+      if (!is_interactive ())
+        s = dbe_sprintf (GTXT ("Has %d descendant(s), use commands controlling selection to load descendant data\n"), num_desc);
+      else
+        s = dbe_sprintf (GTXT ("Has %d descendant(s), use filter panel to load descendant data\n"), num_desc);
+      sb->append (path);
+      sb->append (NTXT (": "));
+      sb->append (s);
+      free (s);
+    }
+}
+
+Experiment *
+DbeSession::get_exp (int exp_ind)
+{
+  if (exp_ind < 0 || exp_ind >= exps->size ())
+    return NULL;
+  Experiment *exp = exps->fetch (exp_ind);
+  exp->setExpIdx (exp_ind);
+  return exp;
+}
+
+Vector<Vector<char*>*> *
+DbeSession::getExperimensGroups ()
+{
+  if (dbeSession->expGroups == NULL || dbeSession->expGroups->size () == 0)
+    return NULL;
+  bool compare_mode = expGroups->size () > 1;
+  Vector<Vector<char*>*> *groups = new Vector<Vector<char*>*> (
+                                         compare_mode ? expGroups->size () : 1);
+  for (int i = 0; i < expGroups->size (); i++)
+    {
+      ExpGroup *grp = expGroups->fetch (i);
+      Vector<Experiment*> *founders = grp->get_founders ();
+      if (founders && founders->size () != 0)
+        {
+          Vector<char *> *names = new Vector<char*> (founders->size ());
+          for (int j = 0; j < founders->size (); j++)
+            {
+              Experiment *exp = founders->fetch (j);
+              names->append (dbe_strdup (exp->get_expt_name ()));
+            }
+          if (compare_mode || groups->size () == 0)
+            groups->append (names);
+          else
+            groups->fetch (0)->addAll (names);
+        }
+      delete founders;
+    }
+  return groups;
+}
+
+char *
+DbeSession::setExperimentsGroups (Vector<Vector<char*>*> *groups)
+{
+  StringBuilder sb;
+  for (int i = 0; i < groups->size (); i++)
+    {
+      Vector<char *> *names = groups->fetch (i);
+      ExpGroup *grp;
+      if (names->size () == 1)
+        grp = new ExpGroup (names->fetch (0));
+      else
+        {
+          char *nm = dbe_sprintf (GTXT ("Group %d"), i + 1);
+          grp = new ExpGroup (nm);
+          free (nm);
+        }
+      expGroups->append (grp);
+      grp->groupId = expGroups->size ();
+
+      for (int j = 0; j < names->size (); j++)
+        {
+          char *path = names->fetch (j);
+          size_t len = strlen (path);
+          if ((len > 4) && !strcmp (path + len - 4, NTXT (".erg")))
+            {
+              Vector<char*> *lst = get_group_or_expt (path);
+              for (int j1 = 0; j1 < lst->size (); j1++)
+                {
+                  Experiment *exp = new Experiment ();
+                  append (exp);
+                  open_experiment (exp, lst->get (j1));
+                  if (exp->get_status () == Experiment::FAILURE)
+                    append_mesgs (&sb, path, exp);
+                }
+              lst->destroy ();
+              delete lst;
+            }
+          else
+            {
+              Experiment *exp = new Experiment ();
+              append (exp);
+              open_experiment (exp, path);
+              if (exp->get_status () == Experiment::FAILURE)
+                append_mesgs (&sb, path, exp);
+            }
+        }
+    }
+
+  for (int i = 0, sz = views->size (); i < sz; i++)
+    {
+      DbeView *dbev = views->fetch (i);
+      dbev->update_advanced_filter ();
+      int cmp = dbev->get_settings ()->get_compare_mode ();
+      dbev->set_compare_mode (CMP_DISABLE);
+      dbev->set_compare_mode (cmp);
+    }
+  return sb.length () == 0 ? NULL : sb.toString ();
+}
+
+char *
+DbeSession::drop_experiment (int exp_ind)
+{
+  DbeView *dbev;
+  int index;
+  Experiment *exp2;
+
+  status_ompavail = -1;
+  Experiment *exp = exps->fetch (exp_ind);
+
+  // If this is a sub experiment, don't do it
+  if (exp->founder_exp != NULL)     // this is a sub experiment; don't do it
+    return (dbe_strdup (GTXT ("Can not drop subexperiments")));
+
+  if (VecSize (exp->children_exps) > 0)
+    for (;;)
+      {
+        // search the list of experiments to find all that have this one as founder
+        bool found = false;
+        Vec_loop (Experiment*, exps, index, exp2)
+        {
+          if (exp2->founder_exp == exp)
+            {
+              exp2->founder_exp = NULL;
+              drop_experiment (index);
+              found = true;
+              break;
+            }
+        }
+        if (found == false)
+          break;
+      }
+
+  // then proceed to finish the drop
+  Vec_loop (DbeView*, views, index, dbev)
+  {
+    dbev->drop_experiment (exp_ind);
+  }
+
+  int old_cnt = expGroups->size ();
+  for (int i = 0; i < old_cnt; i++)
+    {
+      ExpGroup *gr = expGroups->fetch (i);
+      if (gr->groupId == exp->groupId)
+        {
+          gr->drop_experiment (exp);
+          if ((gr->founder == NULL) && (gr->exps->size () == 0))
+            {
+              delete gr;
+              expGroups->remove (i);
+            }
+          break;
+        }
+    }
+  delete exps->remove (exp_ind);
+  if (old_cnt != expGroups->size ())
+    {
+      for (int i = 0, sz = expGroups->size (); i < sz; i++)
+        {
+          ExpGroup *gr = expGroups->fetch (i);
+          gr->groupId = i + 1;
+          Vector<Experiment*> *expList = gr->exps;
+          for (int i1 = 0, sz1 = expList->size (); i1 < sz1; i1++)
+            expList->fetch (i1)->groupId = gr->groupId;
+        }
+      for (int i = 0, sz = views->size (); i < sz; i++)
+        {
+          dbev = views->fetch (i);
+          int cmp = dbev->get_compare_mode ();
+          dbev->set_compare_mode (CMP_DISABLE);
+          dbev->set_compare_mode (cmp);
+        }
+    }
+  check_tab_avail ();   // update tab availability
+  return NULL;
+}
+
+int
+DbeSession::find_experiment (char *path)
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (strcmp (exp->get_expt_name (), path) == 0)
+      return exp->getExpIdx ();
+  }
+  return -1;
+}
+
+LoadObject *
+DbeSession::createLoadObject (const char *nm, int64_t cksum)
+{
+  return loadObjMap->sync_create_item (nm, cksum);
+}
+
+LoadObject *
+DbeSession::createLoadObject (const char *nm, const char *runTimePath, DbeFile *df)
+{
+  return loadObjMap->sync_create_item (nm, runTimePath, df);
+}
+
+void
+DbeSession::append (LoadObject *lobj)
+{
+  Histable *obj = lobj; // workaround for a C++ problem
+  objs->append (obj);
+  lobj->id = objs->size () - 1;
+  lobjs->append (lobj);
+  lobj->seg_idx = lobjs->size () - 1;
+  char *loname = lobj->get_pathname ();
+  dbeFiles->put (loname, lobj->dbeFile);
+}
+
+DbeJarFile *
+DbeSession::get_JarFile (const char *name)
+{
+  DbeJarFile *jf = dbeJarFiles->get (name);
+  if (jf == NULL)
+    {
+      jf = new DbeJarFile (name);
+      dbeJarFiles->put (name, jf);
+    }
+  return jf;
+}
+
+Module *
+DbeSession::createModule (LoadObject *lo, const char *nm)
+{
+  Module *mod = new Module ();
+  Histable *obj = mod; // workaround for a C++ problem
+  objs->append (obj);
+  mod->id = objs->size () - 1;
+  mod->loadobject = lo;
+  mod->set_name (dbe_strdup (nm ? nm : localized_SP_UNKNOWN_NAME));
+  lo->seg_modules->append (mod);
+  return mod;
+}
+
+Module *
+DbeSession::createUnknownModule (LoadObject *lo)
+{
+  Module *mod = createModule (lo, localized_SP_UNKNOWN_NAME);
+  mod->flags |= MOD_FLAG_UNKNOWN;
+  mod->set_file_name (dbe_strdup (localized_SP_UNKNOWN_NAME));
+  return mod;
+}
+
+SourceFile *
+DbeSession::createSourceFile (const char *_path)
+{
+  char *path = (char *) _path;
+  if (strncmp (path, NTXT ("./"), 2) == 0)
+    path += 2;
+  SourceFile *source = sourcesMap->get (path);
+  if (source == NULL)
+    {
+      source = new SourceFile (path);
+      (void) sourcesMap->put (path, source);
+      append (source);
+    }
+  return source;
+}
+
+Function *
+DbeSession::createFunction ()
+{
+  Function *func = new Function (objs->size ());
+  Histable *obj = func; // workaround for a C++ problem
+  objs->append (obj);
+  return func;
+}
+
+JMethod *
+DbeSession::createJMethod ()
+{
+  JMethod *jmthd = new JMethod (objs->size ());
+  Histable *obj = jmthd; // workaround for a C++ problem
+  objs->append (obj);
+  return jmthd;
+}
+
+Module *
+DbeSession::createClassFile (char *className)
+{
+  ClassFile *cls = new ClassFile ();
+  cls->set_name (className);
+  char *clpath = cls->get_java_file_name (className, true);
+  cls->dbeFile = getDbeFile (clpath, DbeFile::F_JAVACLASS);
+  free (clpath);
+  Histable *obj = cls; // workaround for a C++ problem
+  objs->append (obj);
+  cls->id = objs->size () - 1;
+  return cls;
+}
+
+Histable *
+DbeSession::createHistObject (Histable::Type type)
+{
+  switch (type)
+    {
+    case Histable::DOBJECT:
+      {
+        DataObject *dataobj = new DataObject ();
+        dobjs->append (dataobj);
+        dataobj->id = dobjs->size () - 1;
+        return dataobj;
+      }
+    default:
+      assert (0);
+    }
+  return NULL;
+}
+
+DataObject *
+DbeSession::createDataObject ()
+{
+  DataObject *dataobj = new DataObject ();
+  dobjs->append (dataobj);
+  dataobj->id = dobjs->size () - 1;
+  return dataobj;
+}
+
+DataObject *
+DbeSession::createDataObject (DataObject *dobj, DataObject *parent)
+{
+  DataObject *dataobj = new DataObject ();
+  dataobj->size = dobj->size;
+  dataobj->offset = dobj->offset;
+  dataobj->parent = parent;
+  dataobj->set_dobjname (dobj->get_typename (), dobj->get_instname ());
+  dobjs->append (dataobj);
+  dataobj->id = dobjs->size () - 1;
+  return dataobj;
+}
+
+DataObject *
+DbeSession::createMasterDataObject (DataObject *dobj)
+{
+  DataObject *parent = NULL;
+  if (dobj->parent)
+    { // define master parent first
+      parent = find_dobj_master (dobj->parent);
+      if (!parent)
+        { // clone master from this dataobject parent
+          parent = createDataObject (dobj->parent);
+          parent->scope = NULL; // master is scope-less
+          Dprintf (DEBUG_DATAOBJ,
+                   "Master DataObject(%llu) cloned from (%llu) %s\n",
+                   (ull_t) parent->id, (ull_t) dobj->parent->id,
+                   dobj->parent->get_name ());
+          // clone master DataObject elements
+          Vector<DataObject*> *delem = get_dobj_elements (dobj->parent);
+          int element_index = 0;
+          DataObject *element = NULL;
+          Vec_loop (DataObject*, delem, element_index, element)
+          {
+            DataObject *master_element = createDataObject (element, parent);
+            master_element->scope = NULL; // master is scope-less
+            Dprintf (DEBUG_DATAOBJ,
+                     "Member DataObject(%llu) cloned from (%llu) %s\n",
+                     (ull_t) master_element->id, (ull_t) element->id,
+                     element->get_name ());
+          }
+        }
+      else
+        Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) clone found (%llu) %s\n",
+                 (ull_t) parent->id, (ull_t) dobj->parent->id,
+                 dobj->parent->get_name ());
+    }
+
+  DataObject *master = find_dobj_master (dobj);
+  if (!master)
+    { // clone master from this dataobject
+      master = createDataObject (dobj, parent);
+      master->scope = NULL; // master is scope-less
+      Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) cloned from (%llu) %s\n",
+               (ull_t) master->id, (ull_t) dobj->id, dobj->get_name ());
+    }
+  else
+    Dprintf (DEBUG_DATAOBJ, "Master DataObject(%llu) clone found (%llu) %s\n",
+             (ull_t) master->id, (ull_t) dobj->id, dobj->get_name ());
+  return master;
+}
+
+void
+DbeSession::insert_metric (BaseMetric *mtr, Vector<BaseMetric*> *mlist)
+{
+  if ((mtr->get_flavors () & Metric::STATIC) == 0)
+    {
+      // insert in front of the first STATIC
+      for (int i = 0, mlist_sz = mlist->size (); i < mlist_sz; i++)
+        {
+          BaseMetric *m = mlist->fetch (i);
+          if (m->get_flavors () & Metric::STATIC)
+            {
+              mlist->insert (i, mtr);
+              return;
+            }
+        }
+    }
+  mlist->append (mtr);
+}
+
+BaseMetricTreeNode*
+DbeSession::get_reg_metrics_tree ()
+{
+  if (reg_metrics_tree == NULL)
+    // Can't init earlier because BaseMetric() requires DbeSession::ql_parse
+    reg_metrics_tree = new BaseMetricTreeNode ();
+  return reg_metrics_tree;
+}
+
+void
+DbeSession::update_metric_tree (BaseMetric *m)
+{
+  get_reg_metrics_tree ()->register_metric (m);
+}
+
+BaseMetric *
+DbeSession::register_metric_expr (BaseMetric::Type type, char *cmd, char *expr_spec)
+{
+  BaseMetric *m = find_metric (type, cmd, expr_spec);
+  if (m)
+    return m;
+  BaseMetric *bm = find_metric (type, cmd, NULL); // clone this version
+  m = new BaseMetric (*bm);
+  m->set_expr_spec (expr_spec);
+  insert_metric (m, reg_metrics);
+  return m;
+}
+
+BaseMetric *
+DbeSession::register_metric (BaseMetric::Type type)
+{
+  BaseMetric *m = find_metric (type, NULL, NULL);
+  if (m)
+    return m;
+  m = new BaseMetric (type);
+  insert_metric (m, reg_metrics);
+  update_metric_tree (m);
+  return m;
+}
+
+BaseMetric *
+DbeSession::register_metric (Hwcentry *ctr, const char* aux, const char* username)
+{
+  BaseMetric *m = find_metric (BaseMetric::HWCNTR, aux, NULL);
+  if (m)
+    // That may be a problem when metrics aren't an exact match.
+    // For example, memoryspace is disabled in one experiment and not in another.
+    return m;
+  if (ctr->timecvt)
+    {
+      char *time_cmd = dbe_sprintf (NTXT ("t%s"), aux);
+      char *time_username = dbe_sprintf (GTXT ("%s Time"),
+                                       ctr->metric ? ctr->metric :
+                                       (ctr->name ? ctr->name : ctr->int_name));
+      BaseMetric *m1;
+      if (ipc_mode)
+        {
+          // Two visible metrics are presented in GUI
+          m1 = new BaseMetric (ctr, aux, time_cmd, time_username, VAL_TIMEVAL);
+          insert_metric (m1, reg_metrics);
+          update_metric_tree (m1);
+          m = new BaseMetric (ctr, aux, username, VAL_VALUE, m1);
+        }
+      else
+        {
+          // Only one visible metric is presented in er_print
+          m1 = new BaseMetric (ctr, aux, time_cmd, time_username, VAL_TIMEVAL | VAL_INTERNAL);
+          insert_metric (m1, reg_metrics);
+          m = new BaseMetric (ctr, aux, username, VAL_TIMEVAL | VAL_VALUE, m1);
+        }
+      free (time_cmd);
+      free (time_username);
+    }
+  else
+    m = new BaseMetric (ctr, aux, username, VAL_VALUE);
+  insert_metric (m, reg_metrics);
+  update_metric_tree (m);
+  return m;
+}
+
+BaseMetric *
+DbeSession::register_metric (char *name, char *username, char *_def)
+{
+  BaseMetric *m = find_metric (BaseMetric::DERIVED, name, NULL);
+  if (m)
+    return m;
+  Definition *p = Definition::add_definition (_def);
+  if (p == NULL)
+    return NULL;
+  m = new BaseMetric (name, username, p);
+  insert_metric (m, reg_metrics);
+  update_metric_tree (m);
+  return m;
+}
+
+void
+DbeSession::drop_metric (BaseMetric *mtr)
+{
+  Countable *cnt;
+  int index;
+
+  Vec_loop (Countable*, metrics, index, cnt)
+  {
+    if (mtr == (BaseMetric *) cnt->item)
+      {
+        cnt->ref_count--;
+        if (cnt->ref_count == 0)
+          {
+            // Remove this metric from all views
+            DbeView *dbev;
+            int index2;
+            Vec_loop (DbeView*, views, index2, dbev)
+            {
+              dbev->reset_metrics ();
+            }
+            delete metrics->remove (index);
+            delete mtr;
+            return;
+          }
+      }
+  }
+}
+
+BaseMetric *
+DbeSession::find_metric (BaseMetric::Type type, const char *cmd, const char *expr_spec)
+{
+  for (int i = 0, sz = reg_metrics->size (); i < sz; i++)
+    {
+      BaseMetric *bm = reg_metrics->fetch (i);
+      if (bm->get_type () == type && dbe_strcmp (bm->get_expr_spec (), expr_spec) == 0)
+        {
+          if ((type == BaseMetric::DERIVED || type == BaseMetric::HWCNTR)
+               && dbe_strcmp (bm->get_cmd (), cmd) != 0)
+            continue;
+          return bm;
+        }
+    }
+  return NULL;
+}
+
+BaseMetric *
+DbeSession::find_base_reg_metric (char * mcmd)
+{
+  for (int i = 0, sz = reg_metrics->size (); i < sz; i++)
+    {
+      BaseMetric *bm = reg_metrics->fetch (i);
+      if (bm->get_expr_spec () != NULL)
+        continue; // skip compare metrics
+      if (dbe_strcmp (bm->get_cmd (), mcmd) == 0)
+        return bm;
+    }
+  return NULL;
+}
+
+Vector<BaseMetric*> *
+DbeSession::get_base_reg_metrics ()
+{
+  Vector<BaseMetric*> *mlist = new Vector<BaseMetric*>;
+  Vector<BaseMetric*> *ml = get_all_reg_metrics ();
+  for (int i = 0, sz = ml->size (); i < sz; i++)
+    {
+      BaseMetric *m = ml->fetch (i);
+      if (m->get_expr_spec () == NULL)
+        mlist->append (m);
+    }
+  return mlist;
+}
+
+void
+DbeSession::check_tab_avail ()
+{
+  DbeView *dbev;
+  int index;
+  // tell the views to update their tab lists
+  Vec_loop (DbeView*, views, index, dbev)
+  {
+    dbev->get_settings ()->updateTabAvailability ();
+  }
+}
+
+bool
+DbeSession::is_datamode_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->dataspaceavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_leaklist_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->leaklistavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_heapdata_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->heapdataavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_iodata_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->iodataavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_racelist_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->racelistavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_deadlocklist_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->deadlocklistavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_timeline_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->timelineavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_ifreq_available ()
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    if (exp->ifreqavail)
+      return true;
+  }
+  return false;
+}
+
+bool
+DbeSession::is_omp_available ()
+{
+  if (status_ompavail == -1)
+    {
+      status_ompavail = 0;
+      for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+        {
+          Experiment *exp = exps->fetch (i);
+          if (exp->ompavail)
+            {
+              status_ompavail = 1;
+              break;
+            }
+        }
+    }
+  return status_ompavail == 1;
+}
+
+bool
+DbeSession::has_java ()
+{
+  int status_has_java = 0;
+  for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+    {
+      Experiment *exp = exps->fetch (i);
+      if (exp->has_java)
+        {
+          status_has_java = 1;
+          break;
+        }
+    }
+  return status_has_java == 1;
+}
+
+bool
+DbeSession::has_ompavail ()
+{
+  int status_has_ompavail = 0;
+  for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+    {
+      Experiment *exp = exps->fetch (i);
+      if (exp->ompavail)
+        {
+          status_has_ompavail = 1;
+          break;
+        }
+    }
+  return status_has_ompavail == 1;
+}
+
+int
+DbeSession::get_clock (int whichexp)
+{
+  // XXXX clock frequency should be an attribute of each CPU,
+  // XXX  and not a property of the session
+  // if whichexp is -1, pick the first exp that has a clock
+  // otherwise return the clock from the numbered experiment
+  Experiment *exp;
+  if (whichexp != -1)
+    {
+      exp = get_exp (whichexp);
+      if (exp != NULL)
+        return exp->clock;
+      return 0;
+    }
+  int n = nexps ();
+  for (int i = 0; i < n; i++)
+    {
+      exp = get_exp (i);
+      if (exp != NULL && exp->clock != 0)
+        return exp->clock;
+    }
+  return 0;
+}
+
+LoadObject *
+DbeSession::find_lobj_by_name (const char *lobj_name, int64_t cksum)
+{
+  return loadObjMap->get (lobj_name, cksum);
+}
+
+static unsigned
+hash (char *s)
+{
+  unsigned res = 0;
+  for (int i = 0; i < 64 && *s; i++)
+    res = res * 13 + *s++;
+  return res;
+}
+
+// This method is introduced to fix performance
+// problems with the data space profiling in the
+// current release. A better design is desired.
+void
+DbeSession::dobj_updateHT (DataObject *dobj)
+{
+  unsigned index = hash (dobj->get_unannotated_name ()) % HTableSize;
+  List *list = new List;
+  list->val = (void*) dobj;
+  list->next = dnameHTable[index];
+  dnameHTable[index] = list;
+}
+
+DataObject *
+DbeSession::find_dobj_by_name (char *dobj_name)
+{
+  unsigned index = hash (dobj_name) % HTableSize;
+  List *list = dnameHTable[index];
+  for (; list; list = list->next)
+    {
+      DataObject *d = (DataObject*) list->val;
+      if (strcmp (d->get_unannotated_name (), dobj_name) == 0)
+        return d;
+    }
+  return (DataObject *) NULL;
+}
+
+DataObject *
+DbeSession::find_dobj_match (DataObject *dobj)
+{
+  char *dobj_name = dobj->get_unannotated_name ();
+  unsigned index = hash (dobj_name) % HTableSize;
+  List *list = dnameHTable[index];
+  for (; list; list = list->next)
+    {
+      DataObject *d = (DataObject*) list->val;
+      if (strcmp (d->get_unannotated_name (), dobj_name) == 0
+          && d->size == dobj->size && d->offset == dobj->offset
+          && d->scope == dobj->scope)
+        return d;
+    }
+  return (DataObject *) NULL;
+}
+
+DataObject *
+DbeSession::find_dobj_master (DataObject *dobj)
+{
+  char *dobj_name = dobj->get_unannotated_name ();
+  unsigned index = hash (dobj_name) % HTableSize;
+  List *list = dnameHTable[index];
+  for (; list; list = list->next)
+    {
+      DataObject *d = (DataObject*) list->val;
+      // XXXX should parent also match?
+      if (strcmp (d->get_unannotated_name (), dobj_name) == 0
+          && d->size == dobj->size && d->offset == dobj->offset
+          && d->master == NULL && d->scope == NULL)
+        return d;
+    }
+  return (DataObject *) NULL;
+}
+
+Vector<DataObject*>*
+DbeSession::get_dobj_elements (DataObject *dobj)
+{
+  DataObject *d;
+  int index;
+  Vector<DataObject*> *elements = new Vector<DataObject*>;
+  if (dobj == d_total)
+    return elements;
+  Vec_loop (DataObject*, dobjs, index, d)
+  {
+    if (d->get_parent () && d->get_parent () == dobj)
+      elements->append (d);
+  }
+  return elements;
+}
+
+Vector<LoadObject*>*
+DbeSession::get_text_segments ()
+{
+  LoadObject *lo;
+  int index;
+  Vector<LoadObject*> *tlobjs = new Vector<LoadObject*>;
+  Vec_loop (LoadObject*, lobjs, index, lo)
+  {
+    if (lo->type == LoadObject::SEG_TEXT)
+      tlobjs->append (lo);
+  }
+  return tlobjs;
+}
+
+static long long
+getNumber (const char *s, char * &last)
+{
+  long long val;
+  char *sp;
+  errno = 0;
+  val = strtoll (s, &sp, 0);
+  if (errno == EINVAL)
+    last = NULL;
+  else
+    {
+      while (isspace (*sp))
+        sp++;
+      last = sp;
+    }
+  return (val);
+}
+
+bool
+DbeSession::find_obj (FILE *dis_file, FILE *inp_file, Histable *&obj,
+                      char *name, const char *sel, Histable::Type type, bool xdefault)
+{
+  Vector<Histable*> *obj_lst;
+  int which = -1;
+  char *last = NULL;
+  if (type != Histable::FUNCTION && sel)
+    {
+      // check that a number has been provided
+      which = (int) getNumber (sel, last);
+      if (last == NULL || *last != '\0')
+        {
+          fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+          sel = NULL;
+          which = 0;
+        }
+      which--;
+    }
+  obj_lst = new Vector<Histable*>;
+  switch (type)
+    {
+    case Histable::FUNCTION:
+      obj = map_NametoFunction (name, obj_lst, sel);
+      break;
+    case Histable::MODULE:
+      obj = map_NametoModule (name, obj_lst, which);
+      break;
+    case Histable::LOADOBJECT:
+      obj = map_NametoLoadObject (name, obj_lst, which);
+      break;
+    case Histable::DOBJECT:
+      obj = map_NametoDataObject (name, obj_lst, which);
+      break;
+    default:
+      abort (); // unexpected Histable!
+    }
+
+  if ((obj == NULL) && (obj_lst->size () > 0))
+    {
+      if (obj_lst->size () == 1)
+        which = 0;
+      else
+        {
+          if (sel && (which < 0 || which >= obj_lst->size ()))
+            fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+          if (xdefault)
+            {
+              fprintf (stderr, GTXT ("Default selection \"1\" made\n"));
+              which = 0;
+            }
+          else
+            {
+              which = ask_which (dis_file, inp_file, obj_lst, name);
+              if (which == -1)
+                {
+                  delete obj_lst;
+                  return false;
+                }
+            }
+        }
+      obj = obj_lst->fetch (which);
+    }
+  delete obj_lst;
+  return true;
+}
+
+int
+DbeSession::ask_which (FILE *dis_file, FILE *inp_file,
+                       Vector<Histable*> *list, char *name)
+{
+  Histable *hitem;
+  Function *func;
+  Module *module;
+  int which, index, index1;
+  char *item_name, *lo_name, *fname, *last;
+  char buf[BUFSIZ];
+  for (;;)
+    {
+      fprintf (dis_file, GTXT ("Available name list:\n"));
+      fprintf (dis_file, GTXT ("%8d) Cancel\n"), 0);
+      Vec_loop (Histable*, list, index, hitem)
+      {
+        index1 = index + 1;
+        item_name = hitem->get_name ();
+        switch (hitem->get_type ())
+          {
+          case Histable::FUNCTION:
+            func = (Function *) hitem;
+            module = func->module;
+
+            // id == -1 indicates er_src invocation
+            if (module == NULL || (module->lang_code == Sp_lang_java
+                                   && module->loadobject->id == -1))
+                fprintf (dis_file, NTXT ("%8d) %s\n"), index1, item_name);
+            else
+              {
+                lo_name = module->loadobject->get_pathname ();
+                fname = (module->file_name && *module->file_name) ?
+                        module->file_name : module->get_name ();
+                if (fname && *fname)
+                  fprintf (dis_file, NTXT ("%8d) %s %s:0x%llx (%s)\n"), index1,
+                           item_name, lo_name, (ull_t) func->img_offset, fname);
+                else
+                  fprintf (dis_file, NTXT ("%8d) %s %s:0x%llx\n"), index1,
+                           item_name, lo_name, (ull_t) func->img_offset);
+              }
+            break;
+          case Histable::MODULE:
+            module = (Module *) hitem;
+            lo_name = module->loadobject->get_pathname ();
+            if (name[strlen (name) - 1] ==
+                module->file_name[strlen (module->file_name) - 1])
+              fprintf (dis_file, NTXT ("%8d) %s(%s)\n"), index1,
+                       module->file_name, lo_name);
+            else
+              fprintf (dis_file, NTXT ("%8d) %s(%s)\n"), index1, item_name,
+                       lo_name);
+            break;
+          default:
+            fprintf (dis_file, NTXT ("%8d) %s\n"), index1, item_name);
+            break;
+          }
+      }
+      if (inp_file != stdin)
+        return -1;
+      fprintf (dis_file, GTXT ("Enter selection: "));
+      if (fgets (buf, (int) sizeof (buf), inp_file) == NULL)
+        {
+          fprintf (stderr, GTXT ("Error: Invalid number entered:\n"));
+          return -1;
+        }
+      which = (int) getNumber (buf, last);
+      if (last && *last == '\0')
+        if (which >= 0 && which <= list->size ())
+          return which - 1;
+      fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), buf);
+    }
+}
+
+static bool
+match_basename (char *name, char *full_name, int len = -1)
+{
+  if (full_name == NULL)
+    return false;
+  if (!strchr (name, '/'))
+    full_name = get_basename (full_name);
+  if (len == -1)
+    return streq (name, full_name);
+  return strncmp (name, full_name, len) == 0;
+}
+
+LoadObject *
+DbeSession::map_NametoLoadObject (char *name, Vector<Histable*> *list, int which)
+{
+  // Search the tree to find the first module whose module name
+  //   matches "name" or whose source file name matches "name"
+  //  Issues: is the name a pathname, or a base name?
+  //   Should we look at suffix to disambiguate?
+  LoadObject *loitem;
+  int index;
+  Vec_loop (LoadObject*, lobjs, index, loitem)
+  {
+    // try pathname first
+    // if failed, try object name next
+    if (match_basename (name, loitem->get_pathname ()) ||
+        match_basename (name, loitem->get_name ()))
+      {
+        if (which == list->size ())
+          return loitem;
+        list->append (loitem);
+      }
+  }
+  return (LoadObject *) NULL;
+}
+
+Module *
+DbeSession::map_NametoModule (char *name, Vector<Histable*> *list, int which)
+{
+  // Search the tree to find the first loadobject whose loadobject name
+  //   matches "name".
+
+  //  Issues: is the name a pathname, or a base name?
+  //   Should we look at suffix to disambiguate?
+  LoadObject *loitem;
+  Module *mitem;
+  int index1, index2;
+  Vec_loop (LoadObject*, lobjs, index1, loitem)
+  {
+    Vec_loop (Module*, loitem->seg_modules, index2, mitem)
+    {
+      // try source name first
+      // if failed, try object name next
+      if (match_basename (name, mitem->file_name) ||
+          match_basename (name, mitem->get_name ()))
+        {
+          if (which == list->size ())
+            return mitem;
+          list->append (mitem);
+        }
+    }
+  }
+  return (Module *) NULL;
+}
+
+Function *
+DbeSession::map_NametoFunction (char *name, Vector<Histable*> *list,
+                                const char *sel)
+{
+  // Search the tree to find the first function whose
+  //   name matches "name".
+  //  Issues: is the name a full name, or a short name?
+  //   Is it a demangled name?  If so, what about spaces
+  //           within the name?
+  //   Is there a way to return all names that match?
+  //   How can the user specify a particular function of that name?
+  LoadObject *loitem;
+  Function *fitem, *main_func = NULL;
+  Module *mitem, *main_mod = NULL;
+  int index1, index2, index3, which = -1;
+  if (sel)
+    {
+      char *last = NULL;
+      if (*sel == '@')
+        { // 'sel' is "@seg_num:address"
+          which = (int) getNumber (sel + 1, last);
+          if (last == NULL || *last != ':' || (which < 0) || (which >= lobjs->size ()))
+            {
+              fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+              return NULL;
+            }
+          uint64_t address = getNumber (last + 1, last);
+          if (last == NULL || *last != '\0')
+            {
+              fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+              return NULL;
+            }
+          loitem = lobjs->fetch (which);
+          Vec_loop (Module*, loitem->seg_modules, index2, mitem)
+          {
+            Vec_loop (Function*, mitem->functions, index3, fitem)
+            {
+              if (address == fitem->img_offset && match_FName (name, fitem))
+                return fitem;
+            }
+          }
+          return NULL;
+        }
+
+      which = (int) getNumber (sel, last);
+      if (last == NULL || *last != '\0')
+        {
+          fprintf (stderr, GTXT ("Error: Invalid number entered: %s\n"), sel);
+          return NULL;
+        }
+      which--;
+    }
+
+  int len_path = 0;
+  char *with_path = name;
+  name = StrRchr (name, '`');
+  if (name != with_path)
+    len_path = (int) (name - with_path);
+  else
+    with_path = NULL;
+
+  Vec_loop (LoadObject*, lobjs, index1, loitem)
+  {
+    Vec_loop (Module*, loitem->seg_modules, index2, mitem)
+    {
+      if (with_path)
+        { // with file name
+          // try source name first
+          // if failed, try object name next
+          if (!match_basename (with_path, mitem->file_name, len_path) &&
+              !match_basename (with_path, mitem->get_name (), len_path))
+            continue;
+        }
+      Vec_loop (Function*, mitem->functions, index3, fitem)
+      {
+        if (match_FName (name, fitem))
+          {
+            if (which == list->size ())
+              return fitem;
+            list->append (fitem);
+            continue;
+          }
+        if (streq (fitem->get_name (), NTXT ("MAIN_")) && mitem->is_fortran ())
+          {
+            main_func = fitem;
+            main_mod = mitem;
+          }
+      }
+    }
+  }
+
+  if (main_mod && main_func)
+    {
+      main_mod->read_stabs ();
+      if (streq (main_func->get_match_name (), name) && which <= 1)
+        return main_func;
+    }
+  return (Function *) NULL;
+}
+
+DataObject *
+DbeSession::map_NametoDataObject (char *name, Vector<Histable*> *list,
+                                  int which)
+{
+  // Search master list to find dataobjects whose names match "name"
+  // selecting only the entry corresponding to "which" if it is not -1.
+  // Issues: is the name fully qualified or only partially?
+  DataObject *ditem = NULL;
+  int index;
+  char *full_name;
+  Vec_loop (DataObject*, dobjs, index, ditem)
+  {
+    if (ditem->scope) continue; // skip non-master dataobjects
+
+    // try fully-qualified dataobject name first
+    if ((full_name = ditem->get_name ()) != NULL)
+      {
+        if (streq (name, full_name))
+          {
+            if (which == list->size ())
+              return ditem;
+            list->append (ditem);
+          }
+      }
+  }
+  if (list->size () > 0)
+    return ditem; // return fully-qualified match
+
+  // if fully-qualified name doesn't match anything, try a partial match
+  Vec_loop (DataObject*, dobjs, index, ditem)
+  {
+    if (ditem->scope) continue; // skip non-master dataobjects
+
+    // try fully-qualified dataobject name first
+    if ((full_name = ditem->get_name ()) != NULL)
+      {
+        if (strstr (full_name, name))
+          {
+            if (which == list->size ())
+              return ditem;
+            list->append (ditem);
+          }
+      }
+  }
+  return (DataObject *) NULL;
+}
+
+bool
+DbeSession::match_FName (char *name, Function *func)
+{
+  size_t len;
+  char buf[MAXDBUF];
+  char *full_name;
+  if (streq (func->get_name (), name)) // try full name comparison
+    return true;
+  if (streq (func->get_mangled_name (), name)) // try mangled name
+    return true;
+  if (streq (func->get_match_name (), name)) // try match name
+    return true;
+
+  Module *md = func->module; // try FORTRAN name
+  if (md && md->is_fortran ())
+    {
+      char *mangled_name = func->get_mangled_name ();
+      len = strlen (name);
+      if (((len + 1) == strlen (mangled_name)) &&
+          (strncmp (name, mangled_name, len) == 0))
+        return true;
+    }
+  snprintf (buf, sizeof (buf), NTXT ("%s"), func->get_name ());
+  full_name = buf;
+  char *arg = NULL; // find modifier and C++ class name
+  int i = get_paren (buf);
+  if (i >= 0)
+    {
+      arg = buf + i;
+      *arg = '\0';
+    }
+
+  char *mod = strchr (full_name, ' ');
+  char *cls = strchr (full_name, ':');
+
+  if (mod)
+    {
+      len = mod - full_name + 1;
+      if (!strncmp (full_name, name, len))
+        name += len;
+      full_name += len;
+      if (streq (full_name, name)) // try without modifier
+        return true;
+    }
+
+  size_t len_cmp = strlen (name);
+  if (arg)
+    {
+      *arg = '(';
+      len = arg - full_name; // try without 'args'
+      if (len_cmp == len && !strncmp (full_name, name, len))
+        return true;
+      if (cls)
+        {
+          len = arg - cls - 2; // and without 'class name'
+          if ((len_cmp == len) && !strncmp (cls + 2, name, len))
+            return true;
+        }
+    }
+
+  if (cls)
+    {
+      len = cls - full_name; // try C++ class name only
+      if (len_cmp == len && !strncmp (full_name, name, len))
+        return true;
+      if (streq (cls + 2, name)) // try without 'class name'
+        return true;
+    }
+  return false;
+}
+
+bool
+DbeSession::add_path (char *path)
+{
+  return add_path (path, get_search_path ());
+}
+
+bool
+DbeSession::add_classpath (char *path)
+{
+  return add_path (path, classpath);
+}
+
+Vector<DbeFile*> *
+DbeSession::get_classpath ()
+{
+  if (classpath_df == NULL)
+    classpath_df = new Vector<DbeFile*>;
+  for (int i = classpath_df->size (), sz = classpath->size (); i < sz; i++)
+    classpath_df->store (i, getDbeFile (classpath->fetch (i),
+                                        DbeFile::F_DIR_OR_JAR));
+  return classpath_df;
+}
+
+bool
+DbeSession::add_path (char *path, Vector<char*> *pathes)
+{
+  bool result = false;
+  Vector <char *> *tokens = split_str (path, ':');
+  for (long j = 0, jsz = VecSize (tokens); j < jsz; j++)
+    {
+      char *spath = tokens->get (j);
+      // Don't append path if it's already there
+      bool got = false;
+      for (int i = 0, sz = pathes->size (); i < sz; i++)
+        {
+          char *nm = pathes->get (i);
+          if (streq (nm, spath))
+            {
+              got = true;
+              break;
+            }
+        }
+      if (!got)
+        {
+          pathes->append (spath);
+          result = true;
+        }
+      else
+        free (spath);
+    }
+  delete tokens;
+  return result;
+}
+
+void
+DbeSession::set_need_refind ()
+{
+  Vector<DbeFile*> *f_list = dbeFiles->values ();
+  for (long i = 0, sz = f_list == NULL ? 0 : f_list->size (); i < sz; i++)
+    {
+      DbeFile *f = f_list->get (i);
+      f->set_need_refind (true);
+    }
+  delete f_list;
+  for (long i = 0, sz = sources == NULL ? 0 : sources->size (); i < sz; i++)
+    {
+      SourceFile *f = sources->get (i);
+      if (f && f->dbeFile)
+        f->dbeFile->set_need_refind (true);
+    }
+}
+
+void
+DbeSession::set_search_path (Vector<char*> *path, bool reset)
+{
+  if (reset)
+    search_path->destroy ();
+  for (int i = 0, sz = path == NULL ? 0 : path->size (); i < sz; i++)
+    {
+      char *name = path->fetch (i);
+      if (add_path (name))
+        reset = true;
+    }
+  if (reset)
+    {
+      set_need_refind ();
+
+      // now reset the string setting for it
+      StringBuilder sb;
+      for (int i = 0, sz = search_path == NULL ? 0 : search_path->size (); i < sz; i++)
+        {
+          char *name = search_path->fetch (i);
+          if (sb.length () != 0)
+            sb.append (':');
+          sb.append (name);
+        }
+      free (settings->str_search_path);
+      settings->str_search_path = sb.toString ();
+    }
+}
+
+void
+DbeSession::set_search_path (char *_lpath, bool reset)
+{
+  Vector<char *> *path = new Vector<char*>;
+  char *lpath = dbe_strdup (_lpath);
+  for (char *s = lpath; s;)
+    {
+      path->append (s);
+      s = strchr (s, ':');
+      if (s)
+        {
+          *s = 0;
+          s++;
+        }
+    }
+  set_search_path (path, reset);
+  delete path;
+  free (lpath);
+}
+
+void
+DbeSession::set_pathmaps (Vector<pathmap_t*> *newPathMap)
+{
+  set_need_refind ();
+  settings->set_pathmaps (newPathMap);
+}
+
+Vector<pathmap_t*> *
+DbeSession::get_pathmaps ()
+{
+  return settings->pathmaps;
+}
+
+void
+DbeSession::mobj_define (MemObjType_t *mobj)
+{
+  settings->mobj_define (mobj, false);
+  DbeView *dbev;
+  int index;
+  Vec_loop (DbeView*, views, index, dbev)
+  {
+    dbev->get_settings ()->mobj_define (mobj, false);
+  }
+}
+
+void
+DbeSession::dump_segments (FILE *out)
+{
+  int index;
+  LoadObject *loitem;
+  Vec_loop (LoadObject*, lobjs, index, loitem)
+  {
+    fprintf (out, NTXT ("Segment %d -- %s -- %s\n\n"),
+             index, loitem->get_name (), loitem->get_pathname ());
+    loitem->dump_functions (out);
+    fprintf (out, NTXT ("\n End Segment %d -- %s -- %s\n\n"),
+             index, loitem->get_name (), loitem->get_pathname ());
+  }
+}
+
+void
+DbeSession::dump_dataobjects (FILE *out)
+{
+  DataObject *ditem;
+  int index;
+
+  fprintf (out, NTXT ("\nMaster list of DataObjects:\n"));
+  Vec_loop (DataObject*, dobjs, index, ditem)
+  {
+    Histable* scope = ditem->get_scope ();
+    DataObject* parent = ditem->get_parent ();
+    DataObject* master = ditem->get_master ();
+    if (parent != NULL)
+      fprintf (out, "id %6lld: [%4lld] parent = %6lld, offset = %+4lld %s\n",
+               (ll_t) ditem->id, (ll_t) ditem->get_size (),
+               (ll_t) parent->id, (ll_t) ditem->get_offset (),
+               ditem->get_name ());
+    else
+      {
+        // parent is NULL
+        fprintf (out, NTXT ("id %6lld: [%4lld] %s "),
+                 (ll_t) ditem->id, (ll_t) ditem->get_size (),
+                 ditem->get_name ());
+        if (master != NULL)
+          fprintf (out, NTXT (" master=%lld "), (ll_t) master->id);
+        else if (scope != NULL)
+          fprintf (out, NTXT (" master=?? "));
+        else
+          fprintf (out, NTXT (" MASTER "));
+#if DEBUG
+        if (scope != NULL)
+          {
+            switch (scope->get_type ())
+              {
+              case Histable::LOADOBJECT:
+              case Histable::FUNCTION:
+                fprintf (out, NTXT ("%s"), scope->get_name ());
+                break;
+              case Histable::MODULE:
+                {
+                  char *filename = get_basename (scope->get_name ());
+                  fprintf (out, NTXT ("%s"), filename);
+                  break;
+                }
+              default:
+                fprintf (out, NTXT (" Unexpected scope %d:%s"),
+                         scope->get_type (), scope->get_name ());
+              }
+          }
+#endif
+        fprintf (out, NTXT ("\n"));
+      }
+  }
+}
+
+void
+DbeSession::dump_map (FILE *out)
+{
+  Experiment *exp;
+  int index;
+  Vec_loop (Experiment*, exps, index, exp)
+  {
+    exp->dump_map (out);
+  }
+}
+
+void
+DbeSession::dump_stacks (FILE *outfile)
+{
+  Experiment *exp;
+  int n = nexps ();
+  FILE *f = (outfile == NULL ? stderr : outfile);
+  for (int i = 0; i < n; i++)
+    {
+      exp = get_exp (i);
+      fprintf (f, GTXT ("Experiment %d -- %s\n"), i, exp->get_expt_name ());
+      exp->dump_stacks (f);
+    }
+}
+
+void
+DbeSession::propNames_name_store (int propId, const char *propName)
+{
+  PropDescr *prop = new PropDescr (propId, propName);
+  prop->flags = PRFLAG_NOSHOW; // do not show descriptions
+  propNames->store (propId, prop);
+}
+
+void
+DbeSession::propNames_name_store (int propId, const char* propName,
+                                  const char* propUname, VType_type dataType,
+                                  int flags)
+{
+  PropDescr *prop = new PropDescr (propId, propName);
+  prop->vtype = dataType;
+  prop->uname = dbe_strdup (propUname);
+  prop->flags = flags;
+  propNames->store (propId, prop);
+}
+
+char *
+DbeSession::propNames_name_fetch (int i)
+{
+  PropDescr *prop = propNames->fetch (i);
+  if (prop)
+    return prop->name;
+  return NULL;
+}
+
+int
+DbeSession::registerPropertyName (const char *name)
+{
+  if (name == NULL)
+    return PROP_NONE;
+  for (int i = 0; i < propNames->size (); i++)
+    {
+      char *pname = propNames_name_fetch (i);
+      if (pname && strcasecmp (pname, name) == 0)
+        return i;
+    }
+  int propId = propNames->size ();
+  propNames_name_store (propId, name);
+  return propId;
+}
+
+int
+DbeSession::getPropIdByName (const char *name)
+{
+  if (name == NULL)
+    return PROP_NONE;
+  for (int i = 0; i < propNames->size (); i++)
+    {
+      char *pname = propNames_name_fetch (i);
+      if (pname && strcasecmp (pname, name) == 0)
+        return i;
+    }
+  return PROP_NONE;
+}
+
+char *
+DbeSession::getPropName (int propId)
+{
+  if (!propNames)
+    return NULL;
+  if (propId < 0 || propId >= propNames->size ())
+    return NULL;
+  return dbe_strdup (propNames_name_fetch (propId));
+}
+
+char *
+DbeSession::getPropUName (int propId)
+{
+  if (!propNames)
+    return NULL;
+  if (propId < 0 || propId >= propNames->size ())
+    return NULL;
+  PropDescr *prop = propNames->fetch (propId);
+  if (prop)
+    return dbe_strdup (prop->uname);
+  return NULL;
+}
+
+void
+DbeSession::append (UserLabel *lbl)
+{
+  if (lbl->expr)
+    {
+      if (userLabels == NULL)
+         userLabels = new Vector<UserLabel*> ();
+      userLabels->append (lbl);
+    }
+}
+
+void
+DbeSession::append (SourceFile *sf)
+{
+  sources->append (sf);
+  objs->append (sf);
+}
+
+UserLabel *
+DbeSession::findUserLabel (char *name)
+{
+  for (int i = 0, sz = userLabels ? userLabels->size () : 0; i < sz; i++)
+    {
+      UserLabel *lbl = userLabels->fetch (i);
+      if (strcasecmp (lbl->name, name) == 0)
+        return lbl;
+    }
+  return NULL;
+}
+
+Expression *
+DbeSession::findObjDefByName (char *name)
+{
+  Expression *expr = NULL;
+
+  MemObjType_t *mot = MemorySpace::findMemSpaceByName (name);
+  if (mot != NULL)
+    {
+      char *index_expr_str = mot->index_expr;
+      expr = ql_parse (index_expr_str);
+    }
+
+  if (expr == NULL)
+    {
+      int indxtype = findIndexSpaceByName (name);
+      expr = getIndexSpaceExpr (indxtype);
+    }
+  if (expr == NULL)
+    {
+      UserLabel *ulbl = findUserLabel (name);
+      if (ulbl)
+        expr = ulbl->expr;
+    }
+  return expr;
+}
+
+Expression *
+DbeSession::ql_parse (const char *expr_spec)
+{
+  /* (This slight duplication means we don't need to worry about copy
+     constructors for the QL::Result, nor about the lifetime of the
+     expr_spec.)  */
+  if (expr_spec != NULL)
+    {
+      QL::Result result (expr_spec);
+      QL::Parser qlparser (result);
+      if (qlparser () != 0)
+        return NULL;
+      return result ();
+    }
+  else
+    {
+      QL::Result result;
+      QL::Parser qlparser (result);
+      if (qlparser () != 0)
+        return NULL;
+      return result ();
+    }
+}
+
+Vector<void*> *
+DbeSession::getIndxObjDescriptions ()
+{
+  int size = dyn_indxobj_indx;
+  if (size == 0)
+    return NULL;
+  Vector<int> *type = new Vector<int>(dyn_indxobj_indx);
+  Vector<char*> *desc = new Vector<char*>(dyn_indxobj_indx);
+  Vector<char*> *i18ndesc = new Vector<char*>(dyn_indxobj_indx);
+  Vector<char> *mnemonic = new Vector<char>(dyn_indxobj_indx);
+  Vector<int> *orderList = new Vector<int>(dyn_indxobj_indx);
+  Vector<char*> *exprList = new Vector<char*>(dyn_indxobj_indx);
+  Vector<char*> *sdesc = new Vector<char*>(dyn_indxobj_indx);
+  Vector<char*> *ldesc = new Vector<char*>(dyn_indxobj_indx);
+
+  for (long i = 0, sz = VecSize (dyn_indxobj); i < sz; i++)
+    {
+      IndexObjType_t *tot = dyn_indxobj->get (i);
+      if (tot->memObj == NULL)
+        {
+          type->append ((int) tot->type);
+          desc->append (dbe_strdup (tot->name));
+          i18ndesc->append (dbe_strdup (tot->i18n_name));
+          sdesc->append (dbe_strdup (tot->short_description));
+          ldesc->append (dbe_strdup (tot->long_description));
+          mnemonic->append (tot->mnemonic);
+          orderList->append (settings->indx_tab_order->fetch (i));
+          exprList->append (dbe_strdup (tot->index_expr_str));
+        }
+    }
+  Vector<void*> *res = new Vector<void*>(8);
+  res->store (0, type);
+  res->store (1, desc);
+  res->store (2, mnemonic);
+  res->store (3, i18ndesc);
+  res->store (4, orderList);
+  res->store (5, exprList);
+  res->store (6, sdesc);
+  res->store (7, ldesc);
+  return (res);
+}
+
+// Static function to get a vector of custom index object definitions
+Vector<void*> *
+DbeSession::getCustomIndxObjects ()
+{
+  Vector<char*> *name = new Vector<char*>;
+  Vector<char*> *formula = new Vector<char*>;
+  for (long i = dyn_indxobj_indx_fixed, sz = VecSize (dyn_indxobj); i < sz; i++)
+    {
+      IndexObjType_t *tot = dyn_indxobj->get (i);
+      if (tot->memObj == NULL)
+        {
+          name->append (dbe_strdup (tot->name));
+          formula->append (dbe_strdup (tot->index_expr_str));
+        }
+    }
+  Vector<void*> *res = new Vector<void*>(2);
+  res->store (0, name);
+  res->store (1, formula);
+  return (res);
+}
+
+// Static function to define a new index object type
+char *
+DbeSession::indxobj_define (const char *mname, char *i18nname, const char *index_expr_str, char *short_description, char *long_description)
+{
+  if (mname == NULL)
+    return dbe_strdup (GTXT ("No index object type name has been specified."));
+  if (isalpha ((int) (mname[0])) == 0)
+    return dbe_sprintf (GTXT ("Index Object type name %s does not begin with an alphabetic character"),
+                          mname);
+  const char *p = mname;
+  while (*p != 0)
+    {
+      if ((isalnum ((int) (*p)) == 0) && (*p != '_'))
+        return dbe_sprintf (GTXT ("Index Object type name %s contains a non-alphanumeric character"),
+                            mname);
+      p++;
+    }
+
+  // make sure the name is not in use
+  if (MemorySpace::findMemSpaceByName (mname) != NULL)
+    return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
+                          mname);
+
+  int idxx = findIndexSpaceByName (mname);
+  if (idxx >= 0)
+    {
+      IndexObjType_t *mt = dyn_indxobj->fetch (idxx);
+      if (strcmp (mt->index_expr_str, index_expr_str) == 0)
+        // It's a redefinition, but the new definition is the same
+        return NULL;
+      return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
+                          mname);
+    }
+  if (index_expr_str == NULL)
+    return dbe_strdup (GTXT ("No index-expr has been specified."));
+  if (strlen (index_expr_str) == 0)
+    return dbe_sprintf (GTXT ("Index Object index expression is invalid: %s"),
+                        index_expr_str);
+
+  // verify that the index expression parses correctly
+  char *expr_str = dbe_strdup (index_expr_str);
+  Expression *expr = ql_parse (expr_str);
+  if (expr == NULL)
+    return dbe_sprintf (GTXT ("Index Object index expression is invalid: %s"),
+                        expr_str);
+
+  // It's OK, create the new table entry
+  IndexObjType_t *tot = new IndexObjType_t;
+  tot->type = dyn_indxobj_indx++;
+  tot->name = dbe_strdup (mname);
+  tot->i18n_name = dbe_strdup (i18nname);
+  tot->short_description = dbe_strdup (short_description);
+  tot->long_description = dbe_strdup (long_description);
+  tot->index_expr_str = expr_str;
+  tot->index_expr = expr;
+  tot->mnemonic = mname[0];
+
+  // add it to the list
+  dyn_indxobj->append (tot);
+  idxobjs->append (new HashMap<uint64_t, Histable*>);
+
+  // tell the session
+  settings->indxobj_define (tot->type, false);
+
+  DbeView *dbev;
+  int index;
+  Vec_loop (DbeView*, views, index, dbev)
+  {
+    dbev->addIndexSpace (tot->type);
+  }
+  return NULL;
+}
+
+char *
+DbeSession::getIndexSpaceName (int index)
+{
+  if (index < 0 || index >= dyn_indxobj->size ())
+    return NULL;
+  return dyn_indxobj->fetch (index)->name;
+}
+
+char *
+DbeSession::getIndexSpaceDescr (int index)
+{
+  if (index < 0 || index >= dyn_indxobj->size ())
+    return NULL;
+  return dyn_indxobj->fetch (index)->i18n_name;
+}
+
+Expression *
+DbeSession::getIndexSpaceExpr (int index)
+{
+  if (index < 0 || index >= dyn_indxobj->size ())
+    return NULL;
+  return dyn_indxobj->fetch (index)->index_expr;
+}
+
+char *
+DbeSession::getIndexSpaceExprStr (int index)
+{
+  if (index < 0 || index >= dyn_indxobj->size ())
+    return NULL;
+  return dyn_indxobj->fetch (index)->index_expr_str;
+}
+
+int
+DbeSession::findIndexSpaceByName (const char *mname)
+{
+  int idx;
+  IndexObjType_t *mt;
+  Vec_loop (IndexObjType_t*, dyn_indxobj, idx, mt)
+  {
+    if (strcasecmp (mt->name, mname) == 0)
+      return idx;
+  }
+  return -1;
+}
+
+void
+DbeSession::removeIndexSpaceByName (const char *mname)
+{
+  IndexObjType_t *indObj = findIndexSpace (mname);
+  if (indObj)
+    indObj->name[0] = 0;
+}
+
+IndexObjType_t *
+DbeSession::getIndexSpace (int index)
+{
+  return ((index < 0) || (index >= VecSize (dyn_indxobj))) ? NULL : dyn_indxobj->get (index);
+}
+
+IndexObjType_t *
+DbeSession::findIndexSpace (const char *mname)
+{
+  return getIndexSpace (findIndexSpaceByName (mname));
+}
+
+void
+DbeSession::get_filter_keywords (Vector<void*> *res)
+{
+  Vector <char*> *kwCategory = (Vector<char*>*) res->fetch (0);
+  Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1);
+  Vector <char*> *kwDataType = (Vector<char*>*) res->fetch (2);
+  Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3);
+  Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4);
+  Vector <char*> *kwDescription = (Vector<char*>*) res->fetch (5);
+  Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6);
+
+  char *vtypeNames[] = VTYPE_TYPE_NAMES;
+  for (long i = 0, sz = userLabels ? userLabels->size () : 0; i < sz; i++)
+    {
+      UserLabel *lbl = userLabels->fetch (i);
+      kwCategory->append (dbe_strdup (NTXT ("FK_LABEL")));
+      kwCategoryI18N->append (dbe_strdup (GTXT ("Labels")));
+      kwDataType->append (dbe_strdup (vtypeNames[TYPE_BOOL]));
+      kwKeyword->append (dbe_strdup (lbl->name));
+      kwFormula->append (dbe_strdup (lbl->str_expr));
+      kwDescription->append (dbe_strdup (lbl->comment));
+      kwEnumDescs->append (NULL);
+    }
+
+  for (long i = 0, sz = propNames ? propNames->size () : 0; i < sz; i++)
+    {
+      PropDescr *prop = propNames->fetch (i);
+      char *pname = prop ? prop->name : NULL;
+      if (pname == NULL || *pname == 0 || prop->flags & PRFLAG_NOSHOW)
+        continue;
+      int vtypeNum = prop->vtype;
+      if (vtypeNum < 0 || vtypeNum >= TYPE_LAST)
+        vtypeNum = TYPE_NONE;
+      kwCategory->append (dbe_strdup (NTXT ("FK_EVTPROP"))); //Event Property
+      kwCategoryI18N->append (dbe_strdup (GTXT ("Misc. Definitions")));
+      kwDataType->append (dbe_strdup (vtypeNames[vtypeNum]));
+      kwKeyword->append (dbe_strdup (pname));
+      kwFormula->append (NULL);
+      kwDescription->append (dbe_strdup (prop->uname));
+      kwEnumDescs->append (NULL);
+    }
+
+  for (long i = 0, sz = dyn_indxobj ? dyn_indxobj->size () : 0; i < sz; i++)
+    {
+      IndexObjType_t *obj = dyn_indxobj->get (i);
+      if (obj->memObj)
+        continue;
+      kwCategory->append (dbe_strdup (NTXT ("FK_IDXOBJ")));
+      kwCategoryI18N->append (dbe_strdup (GTXT ("Index Object Definitions")));
+      kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT64]));
+      kwKeyword->append (dbe_strdup (obj->name));
+      kwFormula->append (dbe_strdup (obj->index_expr_str));
+      kwDescription->append (dbe_strdup (obj->i18n_name));
+      kwEnumDescs->append (NULL);
+    }
+}
+
+Histable *
+DbeSession::findIndexObject (int idxtype, uint64_t idx)
+{
+  HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
+  return iobjs->get (idx);
+}
+
+Histable *
+DbeSession::createIndexObject (int idxtype, int64_t idx)
+{
+  HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
+
+  Histable *idxobj = iobjs->get (idx);
+  if (idxobj == NULL)
+    {
+      idxobj = new IndexObject (idxtype, idx);
+      if (idx == -1)
+        idxobj->set_name (dbe_strdup (GTXT ("<Unknown>")));
+      iobjs->put (idx, idxobj);
+    }
+
+  return idxobj;
+}
+
+Histable *
+DbeSession::createIndexObject (int idxtype, Histable *hobj)
+{
+  HashMap<uint64_t, Histable*> *iobjs = idxobjs->fetch (idxtype);
+  int64_t idx = hobj ? hobj->id : -1;
+  Histable *idxobj = iobjs->get (idx);
+  if (idxobj == NULL)
+    {
+      idxobj = new IndexObject (idxtype, hobj);
+      if (idx == -1)
+        idxobj->set_name (dbe_strdup (GTXT ("<Unknown>")));
+      iobjs->put (idx, idxobj);
+    }
+
+  return idxobj;
+}
+
+Histable *
+DbeSession::findObjectById (Histable::Type type, int subtype, uint64_t id)
+{
+  switch (type)
+    {
+    case Histable::FUNCTION:
+    case Histable::MODULE:
+    case Histable::LOADOBJECT:
+      return ( id < (uint64_t) objs->size ()) ? objs->fetch ((int) id) : NULL;
+    case Histable::INDEXOBJ:
+      return findIndexObject (subtype, id);
+      // ignoring the following cases
+    case Histable::INSTR:
+    case Histable::LINE:
+    case Histable::EADDR:
+    case Histable::MEMOBJ:
+    case Histable::PAGE:
+    case Histable::DOBJECT:
+    case Histable::SOURCEFILE:
+    case Histable::IOACTFILE:
+    case Histable::IOACTVFD:
+    case Histable::IOCALLSTACK:
+    case Histable::HEAPCALLSTACK:
+    case Histable::OTHER:
+    case Histable::EXPERIMENT:
+      break;
+    }
+  return NULL;
+}
+
+// return a vector of Functions that match the regular expression input string
+Vector<JThread *> *
+DbeSession::match_java_threads (char *ustr, int matchParent,
+                                Vector<uint64_t> * &grids,
+                                Vector<uint64_t> * &expids)
+{
+  if (ustr == NULL)
+    return NULL;
+
+  char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+  regex_t regex_desc;
+  int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+  free (str);
+  if (rc)   // syntax error in parsing string
+    return NULL;
+
+  // allocate the new vector
+  Vector<JThread *> *ret = new Vector<JThread*>;
+  grids = new Vector<uint64_t>;
+  expids = new Vector<uint64_t>;
+
+  int index;
+  JThread *jthread;
+  int expid;
+  Experiment* exp;
+  Vec_loop (Experiment*, exps, expid, exp)
+  {
+
+    Vec_loop (JThread*, exp->get_jthreads (), index, jthread)
+    {
+      const char * name;
+      if (matchParent)
+        name = jthread->parent_name;
+      else
+        name = jthread->group_name;
+      if (name == NULL)
+        name = "";
+      if (!regexec (&regex_desc, name, 0, NULL, 0))
+        {
+          // this one matches
+          ret->append (jthread);
+          grids->append (exp->groupId);
+          expids->append (exp->getUserExpId ());
+        }
+    }
+  }
+
+  regfree (&regex_desc);
+  return ret;
+}
+
+// return a vector of Functions that match the regular expression input string
+Vector<Function *> *
+DbeSession::match_func_names (const char *ustr, Histable::NameFormat nfmt)
+{
+  if (ustr == NULL)
+    return NULL;
+  char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+  regex_t regex_desc;
+  int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+  free (str);
+  if (rc)   // syntax error in parsing string
+    return NULL;
+
+  // allocate the new vector
+  Vector<Function *> *ret = new Vector<Function*>;
+
+  int index;
+  Histable *obj;
+  Vec_loop (Histable*, objs, index, obj)
+  {
+    if (obj->get_type () == Histable::FUNCTION)
+      {
+        Function *func = (Function*) obj;
+        if (!regexec (&regex_desc, func->get_name (nfmt), 0, NULL, 0))
+          // this one matches
+          ret->append (func);
+      }
+  }
+  regfree (&regex_desc);
+  return ret;
+}
+
+// return a vector of Functions that match the regular expression input string
+Vector<FileData *> *
+DbeSession::match_file_names (char *ustr, Histable::NameFormat nfmt)
+{
+  if (ustr == NULL)
+    return NULL;
+  char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+  regex_t regex_desc;
+  int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+  free (str);
+  if (rc)   // syntax error in parsing string
+    return NULL;
+
+  // allocate the new vector
+  Vector<FileData *> *ret = new Vector<FileData*>;
+  int numExps = nexps ();
+  DefaultMap<int64_t, FileData*>* fDataMap;
+  Vector<FileData *> *fDataObjs;
+  FileData *fData;
+  int size;
+  for (int i = 0; i < numExps; i++)
+    {
+      Experiment *exp = get_exp (i);
+      fDataMap = exp->getFDataMap ();
+      fDataObjs = fDataMap->values ();
+      size = fDataObjs->size ();
+      for (int j = 0; j < size; j++)
+        {
+          fData = fDataObjs->fetch (j);
+          if (fData
+              && !regexec (&regex_desc, fData->get_raw_name (nfmt), 0, NULL, 0))
+            // this one matches
+            ret->append (fData);
+        }
+    }
+  regfree (&regex_desc);
+  return ret;
+}
+
+// return a vector of DataObjects that match the regular expression input string
+Vector<DataObject *> *
+DbeSession::match_dobj_names (char *ustr)
+{
+  if (ustr == NULL)
+    return NULL;
+  char *str = dbe_sprintf (NTXT ("^%s$"), ustr);
+  regex_t regex_desc;
+  int rc = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+  free (str);
+  if (rc)   // syntax error in parsing string
+    return NULL;
+
+  // allocate the new vector
+  Vector<DataObject *> *ret = new Vector<DataObject*>;
+  int index;
+  DataObject *ditem;
+  Vec_loop (DataObject*, dobjs, index, ditem)
+  {
+    // does this one match
+    if (!regexec (&regex_desc, ditem->get_name (), 0, NULL, 0))
+      // this one matches
+      ret->append (ditem);
+  }
+  regfree (&regex_desc);
+  return ret;
+}
+
+void
+DbeSession::dump (char *msg, Vector<BaseMetric*> *mlist)
+{
+  if (msg)
+    fprintf (stderr, "%s\n", msg);
+  int sz = mlist ? mlist->size () : -1;
+  for (int i = 0; i < sz; i++)
+    {
+      BaseMetric *m = mlist->fetch (i);
+      char *s = m->dump ();
+      fprintf (stderr, "%2d %s\n", i, s);
+      free (s);
+    }
+  fprintf (stderr, "======END of mlist[%d] =========\n", sz);
+}
+
+void
+DbeSession::dump (char *msg, Vector<Metric*> *mlist)
+{
+  if (msg)
+    fprintf (stderr, "%s\n", msg);
+  int sz = mlist ? mlist->size () : -1;
+  for (int i = 0; i < sz; i++)
+    {
+      Metric *m = mlist->fetch (i);
+      char *s = m->dump ();
+      fprintf (stderr, "%2d %s\n", i, s);
+      free (s);
+    }
+  fprintf (stderr, "======END of mlist[%d] =========\n", sz);
+}
diff --git a/gprofng/src/DbeSession.h b/gprofng/src/DbeSession.h
new file mode 100644 (file)
index 0000000..0a5c01c
--- /dev/null
@@ -0,0 +1,481 @@
+/* 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.  */
+
+/* The DbeSession class is instantiated by a DbeApplication, and contains
+ *     all the data referring to a set of loaded experiments
+ *
+ *     It manages a set of tables for the Experiments, for the LoadObjects
+ *     referenced in them, and for the other objects representing the
+ *     elements in the program hierarchy that can have metrics associated
+ *     with them.  It also has a master list of all the metrics available
+ *     from all the loaded experiments.
+ *
+ *     It gets an instance of the Settings class, instantiated as a copy
+ *     of the one in the DbeApplication that instantiated the DbeSession.
+ *
+ *     In addition, it manages a vector of DbeView's (q.v.); each DbeView
+ *     represents a window into the DbeSession, and has its own set of
+ *     Settings, and FilterSets for the Experiments, and is the access point
+ *     for all processed data.
+ */
+
+#ifndef _DBESESSION_H
+#define _DBESESSION_H
+
+
+#include <stdio.h>
+#include "dbe_structs.h"
+#include "vec.h"
+#include "Hist_data.h"
+#include "Histable.h"
+#include "BaseMetric.h"
+#include "BaseMetricTreeNode.h"
+#include "MemorySpace.h"
+#include "hwcentry.h"
+#include "dbe_types.h"
+#include "Settings.h"
+#include "HashMap.h"
+#include "Table.h"
+#include "Experiment.h"
+
+class DbeSession;
+class Experiment;
+class Expression;
+class ExpGroup;
+class Function;
+class JMethod;
+class Histable;
+class DbeView;
+class Module;
+class LoadObject;
+class DataObject;
+class SourceFile;
+class Settings;
+class StringBuilder;
+class UserLabel;
+class DbeFile;
+class DbeJarFile;
+class FileData;
+class HeapData;
+template <typename ITEM> class DbeSyncMap;
+template <class ITEM> class Vector;
+
+struct DispTab;
+struct List;
+struct Countable;
+class IndexObjType_t;
+
+typedef struct
+{
+  char *path;
+  Experiment *exp;
+  DbeSession *ds;
+  bool read_ahead;
+} exp_ctx;
+
+class DbeSession
+{
+public:
+  DbeSession (Settings *_settings, bool _ipc_mode, bool _rdt_mode);
+  ~DbeSession ();
+
+  void reset ();
+  void reset_data ();
+
+  void
+  set_interactive (bool _interactive)
+  {
+    interactive = _interactive;
+  }
+
+  bool
+  is_interactive ()
+  {
+    return interactive;
+  }
+
+  bool is_datamode_available ();
+  bool is_leaklist_available ();
+  bool is_heapdata_available ();
+  bool is_iodata_available ();
+  bool is_racelist_available ();
+  bool is_deadlocklist_available ();
+  bool is_timeline_available ();
+  bool is_ifreq_available ();
+  bool is_omp_available ();
+  bool has_java ();
+  bool has_ompavail ();
+
+  // XXX  get_clock should be removed, to support cpus with different clocks
+  // XXX    means reworking time-convertible HWC code
+  int get_clock (int id);
+
+  // Access functions for DbeView's
+  int createView ();
+  int createView (int index, int cloneindex);
+  DbeView *getView (int index);
+  void dropView (int index);
+
+  // Access functions controlling the experiment list
+  Vector<char*> *get_group_or_expt (char *path); // load an experiment or group
+
+  void open_experiment (Experiment *exp, char *path);
+  Experiment *get_exp (int exp_ind);
+  Vector<Vector<char*>*> *getExperimensGroups ();
+  char *setExperimentsGroups (Vector<Vector<char*>*> *groups);
+  char *drop_experiment (int exp_ind);
+  int find_experiment (char *path);
+
+  int
+  nexps ()
+  {
+    return exps->size ();
+  }
+  int ngoodexps ();
+
+  // Access functions controlling the DataObject list
+  DataObject *createDataObject ();
+  DataObject *createDataObject (DataObject *d, DataObject *p = NULL);
+  DataObject *createMasterDataObject (DataObject *);
+  Vector<DataObject*> *get_dobj_elements (DataObject *);
+
+  DataObject *
+  get_Total_DataObject ()
+  {
+    return d_total;
+  };
+
+  DataObject *
+  get_Unknown_DataObject ()
+  {
+    return d_unknown;
+  };
+
+  DataObject *
+  get_Scalars_DataObject ()
+  {
+    return d_scalars;
+  };
+
+  DataObject *find_dobj_by_name (char *dobj_name);
+  DataObject *find_dobj_match (DataObject *dobj);
+  DataObject *find_dobj_master (DataObject *dobj);
+
+  int
+  ndobjs ()
+  {
+    return dobjs->size ();
+  }
+
+  // check if no -xhwcprof should be ignored
+  bool
+  check_ignore_no_xhwcprof ()
+  {
+    return settings->get_ignore_no_xhwcprof ();
+  };
+
+  // check if FS warning should be comment, or real warning
+  bool
+  check_ignore_fs_warn ()
+  {
+    return settings->get_ignore_fs_warn ();
+  };
+
+  // Access functions controlling the LoadObject list
+  DbeSyncMap<LoadObject> *loadObjMap;
+  void append (LoadObject *lobj);
+  LoadObject *createLoadObject (const char *nm, int64_t cksum = 0);
+  LoadObject *createLoadObject (const char *nm, const char *runTimePath, DbeFile *df);
+
+  Vector<LoadObject *> *
+  get_LoadObjects ()
+  {
+    return lobjs;
+  };
+
+  void dobj_updateHT (DataObject *dobj);
+  LoadObject *get_Total_LoadObject ();
+  Vector<LoadObject*> *get_text_segments ();
+  LoadObject *get_Unknown_LoadObject ();
+  LoadObject *find_lobj_by_name (const char *lobj_name, int64_t cksum = 0);
+
+  // Access functions controlling the Tab list
+  Vector<DispTab*> *
+  get_TabList ()
+  {
+    return settings->get_TabList ();
+  };
+
+  Vector<bool> *
+  get_MemTabList ()
+  {
+    return settings->get_MemTabState ();
+  };
+
+  void mobj_define (MemObjType_t *);
+
+  // Access functions controlling metrics
+  BaseMetric *find_base_reg_metric (char *mcmd);
+  Vector<BaseMetric*> *get_base_reg_metrics (); // excludes comparison (expr) variants
+
+  Vector<BaseMetric*> *
+  get_all_reg_metrics ()
+  {
+    return reg_metrics;     // includes comparison (expr) variants
+  };
+
+  BaseMetricTreeNode *get_reg_metrics_tree ();
+  BaseMetric *register_metric_expr (BaseMetric::Type type, char *aux, char *expr_spec);
+  BaseMetric *register_metric (BaseMetric::Type type);
+  BaseMetric *register_metric (char *name, char *username, char *_def);
+  BaseMetric *register_metric (Hwcentry *ctr, const char* cmdname, const char* username);
+  void drop_metric (BaseMetric *);
+  Module *createModule (LoadObject *lo, const char *nm);
+  Module *createUnknownModule (LoadObject *lo);
+  Module *createClassFile (char *className);
+  DbeFile *getDbeFile (char *filename, int filetype);
+  SourceFile *get_Unknown_Source ();
+  SourceFile *createSourceFile (const char *path);
+  Histable *createHistObject (Histable::Type);
+  Function *createFunction ();
+  Function *create_hide_function (LoadObject *lo);
+  Function *get_Total_Function ();
+  Function *get_Unknown_Function ();
+  Function *get_JUnknown_Function ();
+  Function *get_jvm_Function ();
+  LoadObject *get_OMP_LoadObject ();
+  Function *get_OMP_Function (int);
+  JMethod *createJMethod ();
+  Histable *createIndexObject (int idxtype, int64_t idx);
+  Histable *createIndexObject (int idxtype, Histable *hobj);
+
+  enum SpecialFunction
+  {
+    TruncatedStackFunc,
+    FailedUnwindFunc,
+    LastSpecialFunction
+  };
+  Function *getSpecialFunction (SpecialFunction);
+
+  Histable *
+  findObjectById (uint64_t _id)
+  {
+    long id = (long) _id;
+    return (id >= 0 && id < objs->size ()) ? objs->fetch (id) : NULL;
+  }
+
+  Histable *findObjectById (Histable::Type type, int subtype, uint64_t id);
+
+  // Other access functions
+  bool find_obj (FILE *dis_file, FILE *inp_file, Histable *&obj, char *name,
+                const char *sel, Histable::Type type, bool xdefault);
+  int ask_which (FILE *dis_file, FILE *inp_file, Vector<Histable*> *list, char *name);
+  LoadObject *map_NametoLoadObject (char *name, Vector<Histable*> *, int which);
+  Module *map_NametoModule (char *name, Vector<Histable*> *, int which);
+  Function *map_NametoFunction (char *, Vector<Histable*> *, const char *);
+  DataObject *map_NametoDataObject (char *name, Vector<Histable*> *, int which);
+  bool match_FName (char *name, Function *func);
+
+  // Functions to convert a string to all matching Functions/DataObjects
+  Vector<Function *> *match_func_names (const char *ustr, Histable::NameFormat nfmt);
+  Vector<DataObject *> *match_dobj_names (char *);
+
+  // Functions to convert a string to all matching JThreads
+  Vector<JThread*> *match_java_threads (char *ustr, int matchParent,
+                                       Vector<uint64_t> * &grids,
+                                       Vector<uint64_t> * &expids);
+  // Function to convert a string to all matching File names
+  Vector<FileData *> *match_file_names (char *ustr, Histable::NameFormat nfmt);
+
+  // Access functions concerning the search path
+  Vector<char*> *
+  get_search_path ()
+  {
+    return search_path;
+  }
+
+  Vector<DbeFile*>*get_classpath ();
+  void set_search_path (Vector<char*> *path, bool reset);
+  void set_search_path (char *lpath, bool reset);
+  bool add_classpath (char *path);
+  bool add_path (char *path);
+  void set_pathmaps (Vector<pathmap_t*> *newPathMap);
+  Vector<pathmap_t*> *get_pathmaps ();
+
+  // functions to aid debugging
+  void dump_stacks (FILE *);
+  void dump_dataobjects (FILE *);
+  void dump_segments (FILE *);
+  void dump_map (FILE *);
+
+  // Find dynamic property by name
+  int registerPropertyName (const char *name);
+  int getPropIdByName (const char *name);
+  char* getPropName (int propId);
+  char* getPropUName (int propId);
+
+  Vector<UserLabel*> *userLabels; // List of er_labels
+  UserLabel *findUserLabel (char *name);
+  DbeJarFile *get_JarFile (const char *name);
+  void append (UserLabel *lbl);
+  void append (SourceFile *sf);
+  void append (Experiment *exp);
+  void append (Hwcentry *exp);
+  void set_need_refind ();
+
+  // Find user defined object by name
+  Expression *findObjDefByName (char *);
+  void get_filter_keywords (Vector<void*> *res);
+
+  // Get the Settings class object
+  Settings *
+  get_settings ()
+  {
+    return settings;
+  }
+
+  // static members, used to define or fetch the various IndexSpaces
+  Vector<void*> *getIndxObjDescriptions (void);
+  Vector<void*> *getCustomIndxObjects (void);
+  char *indxobj_define (const char *, char *, const char *, char *, char *);
+  char *getIndexSpaceName (int index);
+  char *getIndexSpaceDescr (int index);
+  Expression *getIndexSpaceExpr (int index);
+  char *getIndexSpaceExprStr (int index);
+  int findIndexSpaceByName (const char *mname);
+  void removeIndexSpaceByName (const char *mname);
+  IndexObjType_t *getIndexSpace (int index);
+  IndexObjType_t *findIndexSpace (const char *mname);
+  Expression *ql_parse (const char *expr_spec);
+  BaseMetric *find_metric (BaseMetric::Type type, const char *cmd, const char *expr_spec = NULL);
+  static void dump (char *msg, Vector<Metric*> *mlist);
+  static void dump (char *msg, Vector<BaseMetric*> *mlist);
+  static Platform_t platform;               // Sparc, Intel
+  Vector<ExpGroup *> *expGroups;
+  HashMap<char*, LoadObject *> *comp_lobjs; // list of comparable LoadObjects
+  HashMap<char*, DbeLine *> *comp_dbelines; // list of comparable DbeLines
+  HashMap<char*, SourceFile*>*comp_sources; // list of comparable SourceFiles
+  char *localized_SP_UNKNOWN_NAME;
+
+  void
+  set_lib_visibility_used ()
+  {
+    lib_visibility_used = true;
+  }
+
+  bool
+  is_lib_visibility_used ()
+  {
+    return lib_visibility_used;
+  }
+
+  void unlink_tmp_files ();
+  char *get_tmp_file_name (const char *nm, bool for_java);
+
+  Vector<char *> *tmp_files;
+  int status_ompavail;
+  int archive_mode;
+  bool ipc_mode;
+  bool rdt_mode;
+
+  // data and methods concerning the machine model
+  //    methods are in source file MachineModel.cc
+  Vector<char*> *list_mach_models (); // scan . and system lib directory for models
+  char *load_mach_model (char *);
+
+  char *
+  get_mach_model ()
+  {
+    return dbe_strdup (mach_model_loaded);
+  };
+  Vector<SourceFile *> *get_sources ();
+
+private:
+  void init ();
+  void check_tab_avail ();
+  bool add_path (char *path, Vector<char*> *pathes);
+  Experiment *createExperiment ();
+
+  // Divide the regular createExperiment into two parts -
+  // Part1 creates just the Experiment data structure
+  // Part2 updates related fields and vectors
+  Experiment *createExperimentPart1 ();
+  void createExperimentPart2 (Experiment *exp);
+
+  Histable *findIndexObject (int idxtype, uint64_t idx);
+  void append_mesgs (StringBuilder *sb, char *path, Experiment *exp);
+  static void insert_metric (BaseMetric *mtr, Vector<BaseMetric*> *mlist);
+  void update_metric_tree (BaseMetric *m);
+
+  char *find_mach_model (char *);   // fine machine model file by name
+  Vector<Experiment*> *exps;        // Master list of experiments
+  Vector<Histable*> *objs;          // Master list of Functions,Modules,Segments
+  Vector<DataObject*> *dobjs;       // Master list of DataObjects
+  Vector<LoadObject*> *lobjs;       // Auxiliary list of LoadObjects
+  Vector<Hwcentry*> *hwcentries;
+  Vector<HashMap<uint64_t, Histable*>*> *idxobjs; // Master list of IndexObjects
+  HashMap<char*, SourceFile*> *sourcesMap;  // list of Source which were not archived
+  Vector<SourceFile*> *sources;         // list of SourceFiles
+  Map<const char*, DbeJarFile*>*dbeJarFiles;
+  Vector<Countable*> *metrics;
+  Vector<BaseMetric*> *reg_metrics;     // Master list of BaseMetrics
+  BaseMetricTreeNode* reg_metrics_tree; // Hierarchy of BaseMetrics
+  Vector<char*> *search_path;
+  Vector<char*> *classpath;
+  Vector<DbeFile*> *classpath_df;
+  Map<const char*, DbeFile*>*dbeFiles;
+  Vector<DbeView*> *views;              // Master list of DbeViews
+  bool interactive;                     // interactive mode
+  bool lib_visibility_used;
+  LoadObject *lo_total;                 // Total LoadObject
+  Function *f_total;                    // Total function
+  LoadObject *lo_unknown;               // Unknown LoadObject
+  Function *f_unknown;                  // Unknown function
+  SourceFile *sf_unknown;               // Unknown source file
+  Function *f_jvm;                      // pseudo-function <JVM-System>
+  Vector<Function*> *f_special;         // pseudo-functions
+  Function *j_unknown;                  // pseudo-function <no Java callstack>
+  LoadObject *lo_omp;                   // OMP LoadObject (libmtsk)
+  Vector<Function*> *omp_functions;     // OMP-overhead, etc.
+  DataObject *d_unknown;                // Unknown dataobject
+  DataObject *d_scalars;                // Scalars dataobject
+  DataObject *d_total;                  // Total dataobject
+  List **dnameHTable;                   // DataObject name hash table
+  Settings *settings;                   // setting/defaults structure
+  Vector<IndexObjType_t*> *dyn_indxobj; // Index Object definitions
+  int dyn_indxobj_indx;
+  int dyn_indxobj_indx_fixed;
+
+  void propNames_name_store (int propId, const char *propName);
+  void propNames_name_store (int propId, const char *propName,
+                            const char *propUName, VType_type vType, int flags);
+  char* propNames_name_fetch (int propId);
+  Vector<PropDescr*> *propNames;
+  char *defExpName;
+  int user_exp_id_counter;
+  char *mach_model_loaded;
+  char *tmp_dir_name;
+};
+
+// For now, there's only one, so keep its pointer
+extern DbeSession *dbeSession;
+
+extern Vector<char *> *split_str (char *str, char delimiter);
+#endif  /* _DBESESSION_H */
diff --git a/gprofng/src/DbeSyncMap.h b/gprofng/src/DbeSyncMap.h
new file mode 100644 (file)
index 0000000..f13f7b4
--- /dev/null
@@ -0,0 +1,224 @@
+/* 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 _DbeSyncMap_h
+#define _DbeSyncMap_h
+
+#include "DbeLock.h"
+#include "DbeLinkList.h"
+#include "vec.h"
+
+typedef unsigned long hash_ty;
+
+template <class ITEM> class DbeSyncMap : public DbeLock
+{
+public:
+  DbeSyncMap (int _chunkSize = DefaultChunkSize);
+  virtual ~DbeSyncMap ();
+  void reset ();
+  ITEM *get (const char *nm, int64_t chksum);
+  ITEM *sync_create_item (const char *nm, int64_t chksum);
+  ITEM *get (const char *nm, const char *path, DbeFile *df);
+  ITEM *sync_create_item (const char *nm, const char *path, DbeFile *df);
+  virtual void dump ();
+
+  Vector<ITEM *> *
+  values ()
+  {
+    return items;
+  };
+
+private:
+  hash_ty hash (const char *key);
+
+  DbeLinkList<ITEM *> **chunk;
+  Vector<ITEM *> *items;
+  long chunkSize;
+
+  enum
+  {
+    DefaultChunkSize = 1024
+  };
+};
+
+template <class ITEM>
+DbeSyncMap<ITEM>::DbeSyncMap (int _chunkSize)
+{
+  chunkSize = _chunkSize;
+  chunk = new DbeLinkList<ITEM *> * [chunkSize];
+  for (long i = 0; i < chunkSize; i++)
+    chunk[i] = NULL;
+  items = new Vector<ITEM *>(512);
+}
+
+template <class ITEM>
+DbeSyncMap<ITEM>::~DbeSyncMap ()
+{
+  for (long i = 0; i < chunkSize; i++)
+    Destroy (chunk[i]);
+  delete[] chunk;
+  delete items;
+}
+
+template <class ITEM>
+void
+DbeSyncMap<ITEM>::reset ()
+{
+  for (long i = 0; i < chunkSize; i++)
+    {
+      Destroy (chunk[i]);
+      chunk[i] = NULL;
+    }
+  items->reset ();
+}
+
+template <class ITEM>
+ITEM *
+DbeSyncMap<ITEM>::get (const char *nm, int64_t chksum)
+{
+  hash_ty h = hash (nm);
+  for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
+    {
+      ITEM *item = dl->get_item ();
+      if (item->compare (nm, chksum))
+       return item;
+    }
+  return NULL;
+}
+
+template <class ITEM>
+hash_ty
+DbeSyncMap<ITEM>::hash (const char *key)
+{
+  return (hash_ty) (crc64 (key, strlen (key)) % chunkSize);
+}
+
+template <class ITEM>
+ITEM *
+DbeSyncMap<ITEM>::sync_create_item (const char *nm, int64_t chksum)
+{
+  hash_ty h = hash (nm);
+  for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
+    {
+      ITEM *item = dl->get_item ();
+      if (item->compare (nm, chksum))
+       return item;
+    }
+  aquireLock ();
+  for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
+    {
+      ITEM *item = dl->get_item ();
+      if (item->compare (nm, chksum))
+       {
+         releaseLock ();
+         return item;
+       }
+    }
+  ITEM *item = ITEM::create_item (nm, chksum);
+  DbeLinkList<ITEM *> *dl = new DbeLinkList<ITEM *>(item);
+  dl->set_next (chunk[h]);
+  chunk[h] = dl;
+  items->append (item);
+  releaseLock ();
+  return item;
+}
+
+template <class ITEM>
+ITEM *
+DbeSyncMap<ITEM>::get (const char *nm, const char *path, DbeFile *df)
+{
+  int mask = 1 + (path != NULL ? 2 : 0) + (df != NULL ? 4 : 0);
+  hash_ty h = hash (nm);
+  for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
+    {
+      ITEM *item = dl->get_item ();
+      if (mask == item->compare (nm, path, df))
+       return item;
+    }
+  return NULL;
+}
+
+template <class ITEM>
+ITEM *
+DbeSyncMap<ITEM>::sync_create_item (const char *nm, const char *path, DbeFile *df)
+{
+  int mask = CMP_PATH;
+  if (path != NULL)
+    mask += CMP_RUNTIMEPATH;
+  if (df != NULL)
+    mask += CMP_CHKSUM;
+  hash_ty h = hash (nm);
+  for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
+    {
+      ITEM *item = dl->get_item ();
+      if (mask == item->compare (nm, path, df))
+       return item;
+    }
+  aquireLock ();
+  for (DbeLinkList<ITEM *> *dl = chunk[h]; dl; dl = dl->get_next ())
+    {
+      ITEM *item = dl->get_item ();
+      if (mask == item->compare (nm, path, df))
+       {
+         releaseLock ();
+         return item;
+       }
+    }
+  ITEM *item = ITEM::create_item (nm, path, df);
+  DbeLinkList<ITEM *> *dl = new DbeLinkList<ITEM *>(item);
+  dl->set_next (chunk[h]);
+  chunk[h] = dl;
+  items->append (item);
+  releaseLock ();
+  return item;
+}
+
+template <class ITEM>
+void
+DbeSyncMap<ITEM>::dump ()
+{
+  Dprintf (1, NTXT ("\nDbeSyncMap::dump:  vals=%ld\n"), (long) VecSize (items));
+  int tot = 0;
+  int max_cnt = 0;
+  for (long i = 0; i < chunkSize; i++)
+    {
+      DbeLinkList<ITEM *> *lp = chunk[i];
+      if (lp)
+       {
+         int cnt = 0;
+         for (DbeLinkList<ITEM *> *lp1 = lp; lp1; lp1 = lp1->get_next ())
+           cnt++;
+         tot += cnt;
+         if (max_cnt < cnt)
+           max_cnt = cnt;
+         cnt = 1;
+         for (DbeLinkList<ITEM *> *lp1 = lp; lp1; lp1 = lp1->get_next ())
+           {
+             ITEM *p = lp1->get_item ();
+             Dprintf (1, NTXT ("      %2d %s\n"), cnt, p->get_name ());
+             cnt++;
+           }
+       }
+    }
+  Dprintf (1, NTXT ("\nDbeSyncMap::dump: vals=%ld max_cnt=%d tot=%d\n"),
+          (long) VecSize (items), max_cnt, tot);
+}
+
+#endif /* _DbeSyncMap_h */
diff --git a/gprofng/src/DbeThread.cc b/gprofng/src/DbeThread.cc
new file mode 100644 (file)
index 0000000..7eb3cb7
--- /dev/null
@@ -0,0 +1,224 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "DbeThread.h"
+#include "util.h"
+#include "vec.h"
+
+static void
+cleanup_free_mutex (void* arg) {
+  //  pthread_mutex_t *p_mutex = (pthread_mutex_t *) arg;
+  //  if (p_mutex)
+  //    pthread_mutex_unlock (p_mutex);
+}
+
+static void*
+thread_pool_loop (void* arg)
+{
+  DbeThreadPool *thrp = (DbeThreadPool*) arg;
+  Dprintf (DEBUG_THREADS, "thread_pool_loop:%d starting thread=%llu\n",
+          __LINE__, (unsigned long long) pthread_self ());
+
+  /* set my cancel state to 'enabled', and cancel type to 'defered'. */
+  pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL);
+  pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL);
+
+  /* set thread cleanup handler */
+  pthread_cleanup_push (cleanup_free_mutex, (void*) & (thrp->p_mutex));
+  for (;;)
+    {
+      DbeQueue *q = thrp->get_queue ();
+      if (q)
+       { /* a request is pending */
+         Dprintf (DEBUG_THREADS,
+                  "thread_pool_loop:%d thread=%llu queue=%d start\n",
+                  __LINE__, (unsigned long long) pthread_self (), q->id);
+         q->func (q->arg);
+         Dprintf (DEBUG_THREADS,
+                  "thread_pool_loop:%d thread=%llu queue=%d done\n",
+                  __LINE__, (unsigned long long) pthread_self (), q->id);
+         delete q;
+         continue;
+       }
+      if (thrp->no_new_queues)
+       {
+         Dprintf (DEBUG_THREADS, "thread_pool_loop:%d exit thread=%llu\n",
+                  __LINE__, (unsigned long long) pthread_self ());
+         pthread_exit (NULL);
+       }
+      Dprintf (DEBUG_THREADS,
+              "thread_pool_loop:%d before pthread_cond_wait thread=%llu\n",
+              __LINE__, (unsigned long long) pthread_self ());
+      pthread_mutex_lock (&thrp->p_mutex);
+      pthread_cond_wait (&thrp->p_cond_var, &thrp->p_mutex);
+      Dprintf (DEBUG_THREADS,
+              "thread_pool_loop:%d after pthread_cond_wait thread=%llu\n",
+              __LINE__, (unsigned long long) pthread_self ());
+      pthread_mutex_unlock (&thrp->p_mutex);
+    }
+
+  // never reached, but we must use it here. See `man pthread_cleanup_push`
+  pthread_cleanup_pop (0);
+}
+
+DbeThreadPool::DbeThreadPool (int _max_threads)
+{
+  static const int DBE_NTHREADS_DEFAULT = 4;
+  char *s = getenv ("GPROFNG_DBE_NTHREADS");
+  if (s)
+    {
+      max_threads = atoi (s);
+      if (max_threads < 0)
+       max_threads = 0;
+      if (_max_threads > 0 && max_threads < _max_threads)
+       max_threads = _max_threads;
+    }
+  else
+    {
+      max_threads = _max_threads;
+      if (max_threads < 0)
+       max_threads = DBE_NTHREADS_DEFAULT;
+    }
+  Dprintf (DEBUG_THREADS, "DbeThreadPool:%d  max_threads %d ---> %d\n",
+          __LINE__, _max_threads, max_threads);
+  pthread_mutex_init (&p_mutex, NULL);
+  pthread_cond_init (&p_cond_var, NULL);
+  threads = new Vector <pthread_t>(max_threads);
+  queue = NULL;
+  last_queue = NULL;
+  no_new_queues = false;
+  queues_cnt = 0;
+  total_queues = 0;
+}
+
+DbeThreadPool::~DbeThreadPool ()
+{
+  delete threads;
+}
+
+DbeQueue *
+DbeThreadPool::get_queue ()
+{
+  pthread_mutex_lock (&p_mutex);
+  DbeQueue *q = queue;
+  Dprintf (DEBUG_THREADS,
+   "get_queue:%d thr: %lld id=%d queues_cnt=%d threads_cnt=%d max_threads=%d\n",
+          __LINE__, (unsigned long long) pthread_self (),
+          q ? q->id : -1, queues_cnt, (int) threads->size (), max_threads);
+  if (q)
+    {
+      queue = q->next;
+      queues_cnt--;
+    }
+  pthread_mutex_unlock (&p_mutex);
+  return q;
+}
+
+void
+DbeThreadPool::put_queue (DbeQueue *q)
+{
+  if (max_threads == 0)
+    {
+      // nothing runs in parallel
+      q->id = ++total_queues;
+      Dprintf (DEBUG_THREADS, NTXT ("put_queue:%d thr=%lld max_threads=%d queue (%d) runs on the worked thread\n"),
+              __LINE__, (unsigned long long) pthread_self (), max_threads, q->id);
+      q->func (q->arg);
+      delete q;
+      return;
+    }
+
+  pthread_mutex_lock (&p_mutex);
+  // nothing runs in parallel
+  q->id = ++total_queues;
+  Dprintf (DEBUG_THREADS, "put_queue:%d thr=%lld max_threads=%d queue (%d)\n",
+          __LINE__, (unsigned long long) pthread_self (), max_threads, q->id);
+  if (queue)
+    {
+      last_queue->next = q;
+      last_queue = q;
+    }
+  else
+    {
+      queue = q;
+      last_queue = q;
+    }
+  queues_cnt++;
+  Dprintf (DEBUG_THREADS,
+          "put_queue:%d id=%d queues_cnt=%d threads_cnt=%d max_threads=%d\n",
+          __LINE__, q->id, queues_cnt, (int) threads->size (), max_threads);
+  if (queues_cnt > threads->size () && threads->size () < max_threads)
+    {
+      pthread_t thr;
+      int r = pthread_create (&thr, NULL, thread_pool_loop, (void *) this);
+      Dprintf (DEBUG_THREADS,
+              "put_queue:%d pthread_create returns %d thr=%llu\n",
+              __LINE__, r, (unsigned long long) thr);
+      if (r)
+       fprintf (stderr, GTXT ("pthread_create failed. errnum=%d (%s)\n"), r,
+                STR (strerror (r)));
+      else
+       threads->append (thr);
+    }
+  pthread_cond_signal (&p_cond_var);
+  pthread_mutex_unlock (&p_mutex);
+}
+
+void
+DbeThreadPool::wait_queues ()
+{
+  pthread_mutex_lock (&p_mutex);
+  no_new_queues = true;
+  pthread_mutex_unlock (&p_mutex);
+  pthread_cond_broadcast (&p_cond_var);
+  for (;;) // Run requests on the worked thread too
+    {
+      DbeQueue *q = get_queue ();
+      if (q == NULL)
+       break;
+      Dprintf (DEBUG_THREADS, "wait_queues:%d thread=%llu queue=%d start\n",
+              __LINE__, (unsigned long long) pthread_self (), q->id);
+      q->func (q->arg);
+      Dprintf (DEBUG_THREADS, "wait_queues:%d thread=%llu queue=%d done\n",
+              __LINE__, (unsigned long long) pthread_self (), q->id);
+      delete q;
+    }
+  for (int i = 0, sz = threads->size (); i < sz; i++)
+    {
+      void *retval;
+      pthread_join (threads->get (i), &retval);
+    }
+}
+
+DbeQueue::DbeQueue (int (*_func) (void *arg), void *_arg)
+{
+  func = _func;
+  arg = _arg;
+  next = NULL;
+}
+
+DbeQueue::~DbeQueue () { }
diff --git a/gprofng/src/DbeThread.h b/gprofng/src/DbeThread.h
new file mode 100644 (file)
index 0000000..8ee148b
--- /dev/null
@@ -0,0 +1,61 @@
+/* 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 _DBETHREAD_H
+#define _DBETHREAD_H
+#include <pthread.h>
+#include "DbeLinkList.h"
+
+template <class ITEM> class Vector;
+
+class DbeQueue
+{
+public:
+  DbeQueue (int (*_func)(void *arg), void *_arg);
+  ~DbeQueue ();
+
+  int (*func) (void *arg);
+  void *arg;
+  int id;
+  DbeQueue *next;
+};
+
+class DbeThreadPool
+{
+public:
+  DbeThreadPool (int _max_threads);
+  ~DbeThreadPool ();
+  DbeQueue *get_queue ();
+  void put_queue (DbeQueue *q);
+  void wait_queues ();
+
+  pthread_mutex_t p_mutex;
+  pthread_cond_t p_cond_var;
+  volatile bool no_new_queues;
+private:
+  Vector<pthread_t> *threads;
+  int max_threads;
+  DbeQueue *volatile queue;
+  DbeQueue *volatile last_queue;
+  volatile int queues_cnt;
+  volatile int total_queues;
+};
+
+#endif
diff --git a/gprofng/src/DbeView.cc b/gprofng/src/DbeView.cc
new file mode 100644 (file)
index 0000000..68613a5
--- /dev/null
@@ -0,0 +1,3126 @@
+/* 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 "util.h"
+#include "Application.h"
+#include "DbeSession.h"
+#include "CallStack.h"
+#include "Command.h"
+#include "DataObject.h"
+#include "Experiment.h"
+#include "ExpGroup.h"
+#include "FilterExp.h"
+#include "FilterSet.h"
+#include "Function.h"
+#include "DbeView.h"
+#include "PathTree.h"
+#include "DataSpace.h"
+#include "MemorySpace.h"
+#include "IOActivity.h"
+#include "HeapActivity.h"
+#include "Print.h"
+#include "MetricList.h"
+#include "Module.h"
+#include "Filter.h"
+#include "LoadObject.h"
+#include "dbe_types.h"
+#include "StringBuilder.h"
+
+DbeView::DbeView (Application *_app, Settings *_settings, int _vindex)
+{
+  init ();
+  phaseIdx = 0;
+  settings = new Settings (_settings);
+  ptree = new PathTree (this);
+  dspace = new DataSpace (this);
+  memspaces = new Vector<MemorySpace*>;
+  iospace = new IOActivity (this);
+  heapspace = new HeapActivity (this);
+  filters = new Vector<FilterSet*>;
+  lo_expands = new Vector<enum LibExpand>;
+  cur_filter_str = NULL;
+  prev_filter_str = NULL;
+  cur_filter_expr = NULL;
+  filter_active = false;
+  noParFilter = false;
+  dataViews = new Vector<Vector<DataView*>*>;
+  names_src[0] = NULL;
+  names_src[1] = NULL;
+  names_src[2] = NULL;
+  names_dis[0] = NULL;
+  names_dis[1] = NULL;
+  names_dis[2] = NULL;
+  marks = new Vector<int>;
+  marks2dsrc = new Vector<int_pair_t>;
+  marks2dsrc_inc = new Vector<int_pair_t>;
+  marks2ddis = new Vector<int_pair_t>;
+  marks2ddis_inc = new Vector<int_pair_t>;
+  app = _app;
+
+  // set the view's index
+  vindex = _vindex;
+
+  // clear the precomputed data
+  func_data = NULL;
+  line_data = NULL;
+  pc_data = NULL;
+  src_data = NULL;
+  dis_data = NULL;
+  fitem_data = NULL;
+  callers = NULL;
+  callees = NULL;
+  dobj_data = NULL;
+  dlay_data = NULL;
+  iofile_data = NULL;
+  iovfd_data = NULL;
+  iocs_data = NULL;
+  heapcs_data = NULL;
+
+  // and clear the selections
+  sel_obj = NULL;
+  sel_dobj = NULL;
+  sel_binctx = NULL;
+  func_scope = false;
+  lastSelInstr = NULL;
+  lastSelFunc = NULL;
+
+  // Initialize index spaces
+  int sz = settings->get_IndxTabState ()->size ();
+  indxspaces = new Vector<PathTree*>(sz);
+  indx_data = new Vector<Hist_data*>(sz);
+  sel_idxobj = new Vector<Histable*>(sz);
+  for (int i = 0; i < sz; i++)
+    {
+      PathTree *is = new PathTree (this, i);
+      indxspaces->store (i, is);
+      indx_data->store (i, NULL);
+      sel_idxobj->store (i, NULL);
+    }
+  reset ();
+
+  lobjectsNoJava = NULL;
+
+  // set lo_expands for already existing LoadObjects
+  int idx;
+  LoadObject *lo;
+  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+  Vec_loop (LoadObject*, lobjs, idx, lo)
+  {
+    lo_expands->store (lo->seg_idx, LIBEX_SHOW);
+    set_lo_expand (lo->seg_idx, LIBEX_SHOW);
+  }
+  delete lobjs;
+}
+
+DbeView::DbeView (DbeView *dbev, int _vindex)
+{
+  init ();
+  phaseIdx = 0;
+  settings = new Settings (dbev->settings);
+  ptree = new PathTree (this);
+  dspace = new DataSpace (this);
+  iospace = new IOActivity (this);
+  heapspace = new HeapActivity (this);
+  memspaces = new Vector<MemorySpace*>;
+  filters = new Vector<FilterSet*>;
+  lo_expands = new Vector<enum LibExpand>;
+  cur_filter_str = NULL;
+  prev_filter_str = NULL;
+  cur_filter_expr = NULL;
+  noParFilter = false;
+  dataViews = new Vector<Vector<DataView*>*>;
+  names_src[0] = NULL;
+  names_src[1] = NULL;
+  names_src[2] = NULL;
+  names_dis[0] = NULL;
+  names_dis[1] = NULL;
+  names_dis[2] = NULL;
+  marks = new Vector<int>;
+  marks2dsrc = new Vector<int_pair_t>;
+  marks2dsrc_inc = new Vector<int_pair_t>;
+  marks2ddis = new Vector<int_pair_t>;
+  marks2ddis_inc = new Vector<int_pair_t>;
+  app = dbev->app;
+
+  // set the view's index
+  vindex = _vindex;
+
+  // clear the precomputed data
+  func_data = NULL;
+  line_data = NULL;
+  pc_data = NULL;
+  src_data = NULL;
+  dis_data = NULL;
+  fitem_data = NULL;
+  callers = NULL;
+  callees = NULL;
+  dobj_data = NULL;
+  dlay_data = NULL;
+  iofile_data = NULL;
+  iovfd_data = NULL;
+  iocs_data = NULL;
+  heapcs_data = NULL;
+
+  // and clear the selections
+  sel_obj = NULL;
+  sel_dobj = NULL;
+  sel_binctx = NULL;
+  func_scope = false;
+  lastSelInstr = NULL;
+  lastSelFunc = NULL;
+
+  // create the vector of IndexSpaces
+  int sz = dbev->indxspaces->size ();
+  indxspaces = new Vector<PathTree*>(sz);
+  indx_data = new Vector<Hist_data*>(sz);
+  sel_idxobj = new Vector<Histable*>(sz);
+  for (int i = 0; i < sz; i++)
+    {
+      PathTree *is = new PathTree (this, i);
+      indxspaces->store (i, is);
+      indx_data->store (i, NULL);
+      sel_idxobj->store (i, NULL);
+    }
+  reset ();
+
+  // now copy the relevant information from the original view
+  for (int i = 0; i < dbeSession->nexps (); i++)
+    add_experiment (i, dbev->get_exp_enable (i));
+  update_advanced_filter ();
+  delete lo_expands;
+  lo_expands = dbev->lo_expands->copy ();
+  lobjectsNoJava = NULL;
+}
+
+DbeView::~DbeView ()
+{
+  delete settings;
+  delete ptree;
+  delete dspace;
+  delete iospace;
+  delete heapspace;
+  Destroy (memspaces);
+  Destroy (filters);
+  delete lo_expands;
+  free (cur_filter_str);
+  free (prev_filter_str);
+  delete cur_filter_expr;
+  for (int exp_id = 0; exp_id < dataViews->size (); ++exp_id)
+    {
+      Vector<DataView*> *expDataViewList = dataViews->fetch (exp_id);
+      Destroy (expDataViewList);
+    }
+  delete dataViews;
+  delete reg_metrics;
+  metrics_lists->destroy ();
+  delete metrics_lists;
+  metrics_ref_lists->destroy ();
+  delete metrics_ref_lists;
+  delete derived_metrics;
+  delete marks;
+  delete marks2dsrc;
+  delete marks2dsrc_inc;
+  delete marks2ddis;
+  delete marks2ddis_inc;
+
+  // Index spaces
+  indxspaces->destroy ();
+  delete indxspaces;
+
+  indx_data->destroy ();
+  delete indx_data;
+  delete sel_idxobj;
+  delete lobjectsNoJava;
+}
+
+void
+DbeView::init ()
+{
+  phaseIdx = 0;
+  reg_metrics = new Vector<BaseMetric*>;
+  metrics_lists = new Vector<MetricList*>;
+  metrics_ref_lists = new Vector<MetricList*>;
+  for (int i = 0; i <= MET_HEAP; i++)
+    {
+      metrics_lists->append (NULL);
+      metrics_ref_lists->append (NULL);
+    }
+  derived_metrics = new DerivedMetrics;
+  derived_metrics->add_definition (GTXT ("CPI"), GTXT ("Cycles Per Instruction"), GTXT ("cycles/insts"));
+  derived_metrics->add_definition (GTXT ("IPC"), GTXT ("Instructions Per Cycle"), GTXT ("insts/cycles"));
+  derived_metrics->add_definition (GTXT ("K_CPI"), GTXT ("Kernel Cycles Per Instruction"), GTXT ("K_cycles/K_insts"));
+  derived_metrics->add_definition (GTXT ("K_IPC"), GTXT ("Kernel Instructions Per Cycle"), GTXT ("K_insts/K_cycles"));
+}
+
+bool
+DbeView::set_libexpand (char *liblist, enum LibExpand flag)
+{
+  bool changed = settings->set_libexpand (liblist, flag, false);
+  // Show/hide performance optimization:
+  // No need to call update_lo_expand for every library because dbev->set_libexpand()
+  // is called from a loop in Dbe.cc SetLoadObjectState for every load object.
+  // It is sufficient to call update_lo_expand() just once at the end of the loop.
+  //  At all other places such as er_print.cc which calls specific set_libexpand()
+  //  explicitly call update_lo_expands();
+  return changed;
+}
+
+bool
+DbeView::set_libdefaults ()
+{
+  bool changed = settings->set_libdefaults ();
+  if (changed == true)
+    update_lo_expands ();
+  return changed;
+}
+
+void
+DbeView::update_lo_expands ()
+{
+  int index;
+  LoadObject *lo;
+
+  // search all load objects
+  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+  Vec_loop (LoadObject*, lobjs, index, lo)
+  {
+    // now search the settings list for this one
+    enum LibExpand flag = settings->get_lo_setting (lo->get_pathname ());
+    set_lo_expand (lo->seg_idx, flag);
+  }
+  delete lobjs;
+}
+
+enum LibExpand
+DbeView::get_lo_expand (int idx)
+{
+  if (idx < lo_expands->size ())
+    return lo_expands->get (idx);
+  return LIBEX_SHOW;
+}
+
+bool
+DbeView::set_lo_expand (int idx, enum LibExpand flag)
+{
+  // LIBRARY_VISIBILITY
+  if (flag == LIBEX_HIDE)
+    {
+      resetShowAll ();
+      dbeSession->set_lib_visibility_used ();
+    }
+  // if no change
+  if (idx < lo_expands->size () && flag == get_lo_expand (idx))
+    return false;
+  setShowHideChanged (); // this is necessary if called from er_print
+
+  // change the flag
+  lo_expands->store (idx, flag);
+
+  // and reset the data
+  fflush (stderr);
+  purge_events ();
+  reset_data (true);
+  return true;
+}
+
+void
+DbeView::reset ()
+{
+  phaseIdx++;
+
+  // reset all the per-experiment arrays
+  filters->destroy ();
+  lo_expands->reset ();
+  free (cur_filter_str);
+  cur_filter_str = NULL;
+  free (prev_filter_str);
+  prev_filter_str = NULL;
+  delete cur_filter_expr;
+  cur_filter_expr = NULL;
+  noParFilter = false;
+  for (int exp_id = 0; exp_id < dataViews->size (); ++exp_id)
+    {
+      Vector<DataView*> *expDataViewList = dataViews->fetch (exp_id);
+      if (expDataViewList)
+       expDataViewList->destroy ();
+    }
+  dataViews->destroy ();
+  reset_metrics ();
+
+  // now reset any cached data
+  reset_data (true);
+  ompDisMode = false;
+  showAll = true;
+  showHideChanged = false;
+  newViewMode = false;
+}
+
+void
+DbeView::reset_data (bool all)
+{
+  // clear the precomputed data
+  if (func_data != NULL)
+    {
+      delete func_data;
+      func_data = NULL;
+    }
+  if (line_data != NULL)
+    {
+      delete line_data;
+      line_data = NULL;
+    }
+  if (pc_data != NULL)
+    {
+      delete pc_data;
+      pc_data = NULL;
+    }
+  if (src_data != NULL)
+    {
+      delete src_data;
+      src_data = NULL;
+    }
+  if (dis_data != NULL)
+    {
+      delete dis_data;
+      dis_data = NULL;
+    }
+  if (fitem_data != NULL)
+    {
+      delete fitem_data;
+      fitem_data = NULL;
+    }
+  if (callers != NULL)
+    {
+      delete callers;
+      callers = NULL;
+    }
+  if (callees != NULL)
+    {
+      delete callees;
+      callees = NULL;
+    }
+  if (dobj_data != NULL)
+    {
+      delete dobj_data;
+      dobj_data = NULL;
+    }
+  if (dlay_data != NULL)
+    {
+      delete dlay_data;
+      dlay_data = NULL;
+    }
+  if (iofile_data != NULL)
+    {
+      delete iofile_data;
+      iofile_data = NULL;
+    }
+  if (iovfd_data != NULL)
+    {
+      delete iovfd_data;
+      iovfd_data = NULL;
+    }
+  if (iocs_data != NULL)
+    {
+      delete iocs_data;
+      iocs_data = NULL;
+    }
+  if (heapcs_data != NULL)
+    {
+      delete heapcs_data;
+      heapcs_data = NULL;
+    }
+
+  // and reset the selections
+  if (all)
+    {
+      sel_obj = NULL;
+      sel_dobj = NULL;
+      lastSelInstr = NULL;
+      lastSelFunc = NULL;
+      // Set selected object <Total> if possible
+      Function * ft = dbeSession->get_Total_Function ();
+      set_sel_obj (ft);
+    }
+  sel_binctx = NULL;
+
+  dspace->reset ();
+  iospace->reset ();
+  heapspace->reset ();
+
+  // loop over MemorySpaces, resetting each one
+  for (long i = 0, sz = VecSize (memspaces); i < sz; i++)
+    {
+      MemorySpace *ms = memspaces->get (i);
+      ms->reset ();
+    }
+
+  // loop over IndexSpaces, resetting cached data
+  indx_data->destroy ();
+  for (long i = 0, sz = VecSize (indxspaces); i < sz; i++)
+    {
+      indx_data->store (i, NULL);
+      sel_idxobj->store (i, NULL);
+    }
+}
+
+Vector<BaseMetric*> *
+DbeView::get_all_reg_metrics ()
+{
+  Vector<BaseMetric*> *mlist = dbeSession->get_all_reg_metrics ();
+  return mlist;
+}
+
+BaseMetric *
+DbeView::register_metric_expr (BaseMetric::Type type, char *cmd, char *expr_spec)
+{
+  BaseMetric *bm = dbeSession->register_metric_expr (type, cmd, expr_spec);
+  return bm;
+}
+
+Metric *
+DbeView::get_compare_metric (Metric *mtr, int groupNum)
+{
+  if (groupNum == 0 || !mtr->comparable ())
+    return new Metric (*mtr);
+  ExpGroup *gr = dbeSession->expGroups->get (groupNum - 1);
+  char buf[128];
+  snprintf (buf, sizeof (buf), NTXT ("EXPGRID==%d"), gr->groupId);
+  BaseMetric *bm = register_metric_expr (mtr->get_type (), mtr->get_cmd (), buf);
+  Metric *m = new Metric (bm, mtr->get_subtype ());
+  m->set_raw_visbits (mtr->get_visbits ());
+  if (m->legend == NULL)
+    m->legend = dbe_strdup (get_basename (gr->name));
+  return m;
+}
+
+MetricList *
+DbeView::get_metric_ref (MetricType mtype)
+{
+  if (metrics_ref_lists->fetch (MET_COMMON) == NULL)
+    {
+      Vector<BaseMetric*> *base_metrics = dbeSession->get_base_reg_metrics ();
+      metrics_ref_lists->store (MET_SRCDIS, new MetricList (base_metrics, MET_SRCDIS));
+      metrics_ref_lists->store (MET_COMMON, new MetricList (base_metrics, MET_COMMON));
+      metrics_ref_lists->store (MET_NORMAL, new MetricList (base_metrics, MET_NORMAL));
+      metrics_ref_lists->store (MET_CALL, new MetricList (base_metrics, MET_CALL));
+      metrics_ref_lists->store (MET_CALL_AGR, new MetricList (base_metrics, MET_CALL_AGR));
+      metrics_ref_lists->store (MET_DATA, new MetricList (base_metrics, MET_DATA));
+      metrics_ref_lists->store (MET_INDX, new MetricList (base_metrics, MET_INDX));
+      metrics_ref_lists->store (MET_IO, new MetricList (base_metrics, MET_IO));
+      metrics_ref_lists->store (MET_HEAP, new MetricList (base_metrics, MET_HEAP));
+      delete base_metrics;
+    }
+  return metrics_ref_lists->fetch (mtype);
+}
+
+// logically, the function list must be created first, and it
+//     will create the other two;
+MetricList *
+DbeView::get_metric_list (MetricType mtype)
+{
+  if (metrics_lists->fetch (MET_COMMON) == NULL)
+    {
+      Vector<BaseMetric*> *base_metrics = dbeSession->get_base_reg_metrics ();
+      metrics_lists->store (MET_SRCDIS, new MetricList (base_metrics, MET_SRCDIS));
+      metrics_lists->store (MET_COMMON, new MetricList (base_metrics, MET_COMMON));
+      metrics_lists->store (MET_NORMAL, new MetricList (base_metrics, MET_NORMAL));
+      metrics_lists->store (MET_CALL, new MetricList (base_metrics, MET_CALL));
+      metrics_lists->store (MET_CALL_AGR, new MetricList (base_metrics, MET_CALL_AGR));
+      metrics_lists->store (MET_DATA, new MetricList (base_metrics, MET_DATA));
+      metrics_lists->store (MET_INDX, new MetricList (base_metrics, MET_INDX));
+      metrics_lists->store (MET_IO, new MetricList (base_metrics, MET_IO));
+      metrics_lists->store (MET_HEAP, new MetricList (base_metrics, MET_HEAP));
+      delete base_metrics;
+
+      // set the defaults
+      if (settings->str_dmetrics == NULL)
+       settings->str_dmetrics = strdup (Command::DEFAULT_METRICS);
+      char *status = setMetrics (settings->str_dmetrics, true);
+      if (status != NULL)
+       {
+         fprintf (stderr, "XXX setMetrics(\"%s\") failed: %s\n", settings->str_dmetrics, status);
+         abort ();
+       }
+
+      // set the default sort
+      setSort (settings->str_dsort, MET_NORMAL, true);
+    }
+  return metrics_lists->fetch (mtype);
+}
+
+MetricList *
+DbeView::get_metric_list (int dsptype, int subtype)
+{
+  MetricList *mlist;
+  switch (dsptype)
+    {
+    case DSP_DISASM:
+    case DSP_SOURCE:
+    case DSP_SOURCE_DISASM:
+      mlist = get_metric_list (MET_COMMON);
+      mlist = new MetricList (mlist);
+      if (subtype != 0)
+       {
+         for (long i = 0, sz = mlist->size (); i < sz; i++)
+           {
+             Metric *m = mlist->get (i);
+             if (m->comparable ())
+               {
+                 Metric *m1 = get_compare_metric (m, subtype);
+                 mlist->put (i, m1);
+                 delete m;
+               }
+           }
+       }
+      break;
+    default:
+      mlist = get_metric_list (MET_NORMAL);
+      mlist = new MetricList (mlist);
+      break;
+    }
+  return mlist;
+}
+
+void
+DbeView::reset_metrics ()
+{
+  for (int i = 0, sz = metrics_lists->size (); i < sz; i++)
+    {
+      delete metrics_lists->fetch (i);
+      metrics_lists->store (i, NULL);
+    }
+  for (int i = 0, sz = metrics_ref_lists->size (); i < sz; i++)
+    {
+      delete metrics_ref_lists->fetch (i);
+      metrics_ref_lists->store (i, NULL);
+    }
+}
+
+bool
+DbeView::comparingExperiments ()
+{
+  if (dbeSession->expGroups->size () <= 1)
+    return false;
+  return 0 != (settings->get_compare_mode () & (CMP_DELTA | CMP_ENABLE | CMP_RATIO));
+}
+
+void
+DbeView::set_compare_mode (int mode)
+{
+  if (mode == get_compare_mode ())
+    return;
+  settings->set_compare_mode (mode);
+  if (comparingExperiments ())
+    {
+      Vector<BaseMetric*> *bm_list = dbeSession->get_base_reg_metrics ();
+      for (int i = 0, sz = bm_list->size (); i < sz; i++)
+       {
+         BaseMetric *m = bm_list->fetch (i);
+         if (m->get_expr_spec () || !m->comparable ())
+           continue;
+         for (int i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++)
+           {
+             ExpGroup *gr = dbeSession->expGroups->fetch (i1);
+             char buf[128];
+             snprintf (buf, sizeof (buf), NTXT ("EXPGRID==%d"), gr->groupId);
+             register_metric_expr (m->get_type (), m->get_cmd (), buf);
+           }
+       }
+    }
+  MetricList *mlist = get_metric_list (MET_NORMAL);
+  MetricList *gmlist = get_metric_list (MET_CALL);
+  MetricList *dmlist = get_metric_list (MET_DATA);
+  MetricList *imlist = get_metric_list (MET_INDX);
+  if (comparingExperiments ())
+    {
+      add_compare_metrics (mlist);
+      add_compare_metrics (gmlist);
+      add_compare_metrics (dmlist);
+      add_compare_metrics (imlist);
+    }
+  else
+    {
+      remove_compare_metrics (mlist);
+      remove_compare_metrics (gmlist);
+      remove_compare_metrics (dmlist);
+      remove_compare_metrics (imlist);
+    }
+}
+
+void
+DbeView::ifreq (FILE *outfile)
+{
+  if (!dbeSession->is_ifreq_available ())
+    {
+      fprintf (outfile, GTXT ("No instruction frequency data available\n"));
+      return;
+    }
+  for (int index = 0; index < filters->size (); index++)
+    {
+      Experiment *exp = dbeSession->get_exp (index);
+      if (exp->broken || !get_exp_enable (index) || !exp->ifreqavail)
+       continue;
+
+      // this experiment has the data; print it
+      fprintf (outfile,
+              GTXT ("Instruction frequency data from experiment %s\n\n"),
+              exp->get_expt_name ());
+      fprintf (outfile, NTXT ("%s"), pr_mesgs (exp->fetch_ifreq (), "", ""));
+    }
+}
+
+// When adding multiple sub-experiments of an experiment, it is
+// not necessary to do the following every-time. It is sufficient to call reset_metrics()
+// and call get_metric_ref() and get_metric_list() in the end after all the sub-experiments
+// have been added
+void
+DbeView::add_experiment_epilogue ()
+{
+  bool flag_LIBEX_HIDE = false;
+  bool flag_ShowHideChanged = false;
+  Vector<LoadObject*> *lobjs = dbeSession->get_LoadObjects ();
+  for (long i = lo_expands->size (), sz = lobjs ? lobjs->size () : 0; i < sz; i++)
+    {
+      flag_ShowHideChanged = true;
+      LoadObject *lo = lobjs->get (i);
+      enum LibExpand flag = settings->get_lo_setting (lo->get_pathname ());
+      if (flag == LIBEX_HIDE)
+       flag_LIBEX_HIDE = true;
+      lo_expands->store (lo->seg_idx, flag);
+    }
+  if (flag_LIBEX_HIDE)
+    {
+      resetShowAll ();
+      dbeSession->set_lib_visibility_used ();
+    }
+  if (flag_ShowHideChanged)
+    {
+      setShowHideChanged (); // this is necessary if called from er_print
+      purge_events ();
+      reset_data (true);
+    }
+  reset_metrics ();
+  (void) get_metric_ref (MET_NORMAL);
+  (void) get_metric_ref (MET_CALL);
+  (void) get_metric_ref (MET_CALL_AGR);
+  (void) get_metric_ref (MET_DATA);
+  (void) get_metric_ref (MET_INDX);
+  (void) get_metric_ref (MET_IO);
+  (void) get_metric_ref (MET_HEAP);
+  (void) get_metric_list (MET_NORMAL);
+  (void) get_metric_list (MET_CALL);
+  (void) get_metric_list (MET_CALL_AGR);
+  (void) get_metric_list (MET_DATA);
+  (void) get_metric_list (MET_INDX);
+  (void) get_metric_list (MET_IO);
+  (void) get_metric_list (MET_HEAP);
+}
+
+// When adding multiple sub-experiments of an experiment, avoid invoking the steps in
+// add_experiment_epilogue() every time and instead call it separately in the end
+// after all sub-experiments have been added
+void
+DbeView::add_subexperiment (int index, bool enabled)
+{
+  // phaseIdx doesn't change, PathTree can handle adding
+  // new experiments without reset
+
+  // Set up the FilterSet for the experiments
+  Experiment *exp = dbeSession->get_exp (index);
+  FilterSet *filterset = new FilterSet (this, exp);
+  filterset->set_enabled (enabled);
+  filters->store (index, filterset);
+
+  assert (index == dataViews->size ());
+  Vector<DataView*> *expDataViewList = new Vector<DataView*>;
+  for (int data_id = 0; data_id < DATA_LAST; ++data_id)
+    expDataViewList->append (NULL); //experiment data_id's are not known yet
+  dataViews->store (index, expDataViewList);
+}
+
+void
+DbeView::add_experiment (int index, bool enabled)
+{
+  // phaseIdx doesn't change, PathTree can handle adding
+  // new experiments without reset
+
+  // delete any cached data
+  reset_data (true);
+
+  // Set up the FilterSet for the experiments
+  Experiment *exp = dbeSession->get_exp (index);
+  FilterSet *filterset = new FilterSet (this, exp);
+  filterset->set_enabled (enabled);
+  filters->store (index, filterset);
+
+  assert (index == dataViews->size ());
+  Vector<DataView*> *expDataViewList = new Vector<DataView*>;
+  for (int data_id = 0; data_id < DATA_LAST; ++data_id)
+    expDataViewList->append (NULL); //experiment data_id's are not known yet
+  dataViews->store (index, expDataViewList);
+
+  reset_metrics ();
+  (void) get_metric_ref (MET_NORMAL);
+  (void) get_metric_ref (MET_CALL);
+  (void) get_metric_ref (MET_CALL_AGR);
+  (void) get_metric_ref (MET_DATA);
+  (void) get_metric_ref (MET_INDX);
+  (void) get_metric_ref (MET_IO);
+  (void) get_metric_ref (MET_HEAP);
+  (void) get_metric_list (MET_NORMAL);
+  (void) get_metric_list (MET_CALL);
+  (void) get_metric_list (MET_CALL_AGR);
+  (void) get_metric_list (MET_DATA);
+  (void) get_metric_list (MET_INDX);
+  (void) get_metric_list (MET_IO);
+  (void) get_metric_list (MET_HEAP);
+}
+
+void
+DbeView::drop_experiment (int index)
+{
+  phaseIdx++;
+  filters->remove (index);
+
+  // reset any cached data
+  reset_data (true);
+
+  Vector<DataView*> *expDataViewList = dataViews->remove (index);
+  if (expDataViewList)
+    {
+      expDataViewList->destroy ();
+      delete expDataViewList;
+    }
+}
+
+bool
+DbeView::get_exp_enable (int n)
+{
+  return filters ? filters->fetch (n)->get_enabled () : true;
+}
+
+void
+DbeView::set_exp_enable (int n, bool e)
+{
+  FilterSet *fs = filters->fetch (n);
+  if (fs->get_enabled () != e)
+    {
+      fs->set_enabled (e);
+      purge_events (n);
+      phaseIdx++;
+    }
+}
+
+void
+DbeView::reset_metric_list (MetricList *mlist, int cmp_mode)
+{
+  MetricType mtype = mlist->get_type ();
+  switch (mtype)
+    {
+    case MET_NORMAL:
+    case MET_COMMON:
+      delete metrics_lists->fetch (MET_COMMON);
+      metrics_lists->store (MET_COMMON, new MetricList (mlist));
+      remove_compare_metrics (metrics_lists->fetch (MET_COMMON));
+      break;
+      // ignoring the following cases (why?)
+    case MET_SRCDIS:
+    case MET_CALL:
+    case MET_DATA:
+    case MET_INDX:
+    case MET_CALL_AGR:
+    case MET_IO:
+    case MET_HEAP:
+      break;
+    }
+
+  if (cmp_mode != -1)
+    {
+      settings->set_compare_mode (cmp_mode);
+      if (comparingExperiments ())
+       add_compare_metrics (mlist);
+    }
+
+  switch (mtype)
+    {
+    case MET_NORMAL:
+      delete metrics_lists->fetch (mtype);
+      metrics_lists->store (mtype, mlist);
+      // fall through to next case
+    case MET_COMMON:
+      metrics_lists->fetch (MET_SRCDIS)->set_metrics (mlist);
+      metrics_lists->fetch (MET_CALL)->set_metrics (mlist);
+      metrics_lists->fetch (MET_CALL_AGR)->set_metrics (mlist);
+      remove_compare_metrics (metrics_lists->fetch (MET_CALL_AGR));
+      metrics_lists->fetch (MET_DATA)->set_metrics (mlist);
+      metrics_lists->fetch (MET_INDX)->set_metrics (mlist);
+      metrics_lists->fetch (MET_IO)->set_metrics (mlist);
+      metrics_lists->fetch (MET_HEAP)->set_metrics (mlist);
+      break;
+    case MET_CALL_AGR:
+      delete metrics_lists->fetch (MET_CALL_AGR);
+      metrics_lists->store (MET_CALL_AGR, mlist);
+      remove_compare_metrics (mlist);
+      break;
+    case MET_SRCDIS:
+    case MET_CALL:
+    case MET_DATA:
+    case MET_INDX:
+    case MET_IO:
+    case MET_HEAP:
+      delete metrics_lists->fetch (mtype);
+      metrics_lists->store (mtype, mlist);
+      break;
+    default:
+      abort ();
+    }
+  reset_data (false);
+}
+
+void
+DbeView::add_compare_metrics (MetricList *mlist)
+{
+  if (mlist == NULL || !comparingExperiments ())
+    return;
+  int sort_ref_index = mlist->get_sort_ref_index ();
+  Vector<Metric*> *items = mlist->get_items ();
+  Vector<Metric*> *newItems = new Vector<Metric*>();
+  int mode = get_compare_mode ();
+  int cmp_vbits = 0;
+  if ((mode & CMP_DELTA) != 0)
+    cmp_vbits = VAL_DELTA;
+  else if ((mode & CMP_RATIO) != 0)
+    cmp_vbits = VAL_RATIO;
+  for (long i = 0, sz = items->size (); i < sz; i++)
+    {
+      Metric *mtr = items->get (i);
+      if (sort_ref_index == i)
+       mlist->set_sort_ref_index (newItems->size ());
+      int vbits = mtr->get_visbits () & ~(VAL_DELTA | VAL_RATIO);
+      mtr->set_raw_visbits (vbits);
+      if (!mtr->comparable ())
+       {
+         newItems->append (mtr);
+         continue;
+       }
+      if (mtr->get_expr_spec ())
+       {
+         if (strcmp (mtr->get_expr_spec (), NTXT ("EXPGRID==1")) != 0)
+           {
+             if ((cmp_vbits & VAL_RATIO) != 0)
+               // for ratios, make sure VAL_TIMEVAL is off and VAL_VALUE is on
+               mtr->set_raw_visbits ((vbits | VAL_VALUE | cmp_vbits) & ~VAL_TIMEVAL);
+             else
+               {
+                 int ind = mlist->get_listorder (mtr->get_cmd (), mtr->get_subtype (), NTXT ("EXPGRID==1"));
+                 if (ind >= 0)
+                   // take VAL_VALUE and VAL_TIMEVAL from base experiment
+                   mtr->set_raw_visbits (cmp_vbits
+                                         | (vbits & ~(VAL_VALUE | VAL_TIMEVAL))
+                                         | (mlist->get (ind)->get_visbits ()
+                                            & (VAL_VALUE | VAL_TIMEVAL)));
+                 else
+                   mtr->set_raw_visbits (cmp_vbits | vbits);
+               }
+           }
+         newItems->append (mtr);
+         continue;
+       }
+      for (long i1 = 0, sz1 = dbeSession->expGroups->size (); i1 < sz1; i1++)
+       {
+         Metric *m = get_compare_metric (mtr, i1 + 1);
+         switch (m->get_vtype ())
+           {
+           case VT_LABEL:
+           case VT_ADDRESS:
+           case VT_OFFSET:
+             m->set_raw_visbits (vbits);
+             break;
+           default:
+             if (i1 == 0)
+               m->set_raw_visbits (vbits);
+             else if (cmp_vbits == VAL_RATIO
+                      && ((vbits & (VAL_VALUE | VAL_TIMEVAL))
+                          == (VAL_VALUE | VAL_TIMEVAL)))
+               // make ratios for VAL_VALUE only
+               m->set_raw_visbits ((vbits | VAL_VALUE | cmp_vbits) & ~VAL_TIMEVAL);
+             else
+               m->set_raw_visbits (vbits | cmp_vbits);
+             break;
+           }
+         newItems->append (m);
+       }
+    }
+  items->reset ();
+  items->addAll (newItems);
+  delete newItems;
+  phaseIdx++;
+  reset_data (false);
+}
+
+MetricList *
+DbeView::get_compare_mlist (MetricList *met_list, int grInd)
+{
+  MetricList *mlist = new MetricList (met_list->get_type ());
+  mlist->set_sort_ref_index (met_list->get_sort_ref_index ());
+  mlist->set_sort_rev (met_list->get_sort_rev ());
+
+  Vector<Metric*> *items_old = met_list->get_items ();
+  for (int i = 0, sz = items_old->size (); i < sz; i++)
+    {
+      Metric *m = get_compare_metric (items_old->get (i), grInd + 1);
+      mlist->append (m);
+    }
+  return mlist;
+}
+
+void
+DbeView::remove_compare_metrics (MetricList *mlist)
+{
+  Vector<Metric*> *items = mlist->get_items ();
+  Vector<Metric*> *items_old = items->copy ();
+  items->reset ();
+  int sort_index = mlist->get_sort_ref_index ();
+  mlist->set_sort_ref_index (0);
+  for (int i = 0, sz = items_old->size (); i < sz; i++)
+    {
+      Metric *m = items_old->fetch (i);
+      if (m->get_expr_spec () == NULL)
+       {
+         // this is a 'non-compare' metric; add it
+         items->append (m);
+         if (sort_index == i)
+           mlist->set_sort_ref_index (items->size () - 1);
+         continue;
+       }
+      // is the 'non-compare' version of the metric already in the list?
+      int ind = mlist->get_listorder (m->get_cmd (), m->get_subtype ());
+      if (ind == -1)
+       {
+         // not in the list; add it
+         BaseMetric *bm = dbeSession->find_metric (m->get_type (), m->get_cmd (), NULL);
+         Metric *new_met = new Metric (bm, m->get_subtype ());
+         new_met->set_raw_visbits (m->get_visbits () & ~(CMP_DELTA | CMP_RATIO));
+         items->append (new_met);
+         if (sort_index == i)
+           mlist->set_sort_ref_index (items->size () - 1);
+       }
+      delete m;
+    }
+  delete items_old;
+  reset_data (false);
+}
+
+// setMetrics -- set the metric list according to specification
+//     The previous sort is preserved, if possible
+//     Otherwise, the default sort setting is used
+//     Returns NULL if OK, or an error string if not
+//YXXX only MET_NORMAL appears to be used... code could be simplified
+char *
+DbeView::setMetrics (char *mspec, bool fromRcFile)
+{
+  char *ret;
+  MetricType mtype = MET_NORMAL;
+  // note that setting the default is done here, while all else is in MetricList
+  if (mspec == NULL) abort ();
+  if (strcasecmp (mspec, Command::DEFAULT_CMD) == 0)
+    {
+      mspec = settings->get_default_metrics ();
+      fromRcFile = true;
+    }
+  MetricList *mlist = get_metric_list (mtype);
+  mlist = new MetricList (mlist);
+  ret = mlist->set_metrics (mspec, fromRcFile, derived_metrics);
+  if (ret == NULL)
+    {
+      switch (mtype)
+       {
+       case MET_NORMAL:
+       case MET_COMMON:
+         delete metrics_lists->fetch (MET_COMMON);
+         metrics_lists->store (MET_COMMON, new MetricList (mlist));
+         break;
+         // ignoring the following cases (why?)
+       case MET_SRCDIS:
+       case MET_CALL:
+       case MET_DATA:
+       case MET_INDX:
+       case MET_CALL_AGR:
+       case MET_IO:
+       case MET_HEAP:
+         break;
+       }
+      add_compare_metrics (mlist);
+
+      //YXXX looks like cut/paste code here, see reset_metric_list()
+      switch (mtype)
+       {
+       case MET_NORMAL:
+         delete metrics_lists->fetch (mtype);
+         metrics_lists->store (mtype, mlist);
+         //YXXX is lack of break intentional?  If so, add comment...
+       case MET_COMMON:
+         metrics_lists->fetch (MET_SRCDIS)->set_metrics (mlist);
+         metrics_lists->fetch (MET_CALL)->set_metrics (mlist);
+         metrics_lists->fetch (MET_CALL_AGR)->set_metrics (mlist);
+         remove_compare_metrics (metrics_lists->fetch (MET_CALL_AGR));
+         metrics_lists->fetch (MET_DATA)->set_metrics (mlist);
+         metrics_lists->fetch (MET_INDX)->set_metrics (mlist);
+         metrics_lists->fetch (MET_IO)->set_metrics (mlist);
+         metrics_lists->fetch (MET_HEAP)->set_metrics (mlist);
+         break;
+       case MET_CALL_AGR:
+         delete metrics_lists->fetch (MET_CALL_AGR);
+         metrics_lists->store (MET_CALL_AGR, mlist);
+         remove_compare_metrics (mlist);
+         break;
+       case MET_SRCDIS:
+       case MET_CALL:
+       case MET_DATA:
+       case MET_INDX:
+       case MET_IO:
+       case MET_HEAP:
+         delete metrics_lists->fetch (mtype);
+         metrics_lists->store (mtype, mlist);
+         break;
+       default:
+         abort ();
+       }
+      reset_data (false);
+    }
+  else
+    delete mlist;
+  return ret;
+}
+
+
+// Set Sort by name (er_print)
+char *
+DbeView::setSort (char * sort_list, MetricType mtype, bool fromRcFile)
+{
+  MetricList *mlist = NULL;
+
+  // note that setting the default is done here, while all else is in MetricList
+  if ((sort_list == NULL) || (strcmp (sort_list, Command::DEFAULT_CMD) == 0))
+    {
+      if (settings->str_dsort == NULL)
+       settings->str_dsort = strdup (Command::DEFAULT_METRICS);
+      sort_list = settings->get_default_sort ();
+    }
+  mlist = get_metric_list (mtype);
+
+  if (mlist == NULL)
+    abort ();
+
+  // set the new sort
+  char *ret = mlist->set_sort (sort_list, fromRcFile);
+  if (ret != NULL)
+    return ret;
+
+  // now resort all cached data
+  resortData (mtype);
+  return NULL;
+}
+
+// Set sort from the visible index (Analyzer)
+void
+DbeView::setSort (int visindex, MetricType mtype, bool reverse)
+{
+  MetricList *mlist = get_metric_list (mtype);
+  Vector<Metric*> *items = mlist->get_items ();
+  if (visindex >= items->size ())
+    return;
+  mlist->set_sort (visindex, reverse);
+  resortData (mtype);
+  if (mtype == MET_NORMAL)
+    {
+      int idx_cc = -1;
+      MetricList *mlist_cc = get_metric_list (MET_CALL);
+      Vector<Metric*> *items_cc = mlist_cc->get_items ();
+      for (int i = 0; i < items_cc->size (); i++)
+       {
+         char * name_cc = items_cc->fetch (i)->get_username ();
+         char * name_normal = items->fetch (visindex)->get_username ();
+         if (0 == strncmp (name_cc, name_normal, strlen (name_cc)))
+           {
+             idx_cc = i;
+             break;
+           }
+       }
+      if (idx_cc != -1)
+       {
+         mlist_cc->set_sort (idx_cc, reverse);
+         resortData (MET_CALL);
+         // Change a sort metric for MET_CALL_AGR
+         Metric *m = items_cc->fetch (idx_cc);
+         MetricList *cList = get_metric_list (MET_CALL_AGR);
+         Metric *m1 = cList->find_metric (m->get_cmd (), m->get_subtype ());
+         if (m1)
+           cList->set_sort_metric (m1->get_cmd (), m1->get_subtype (), reverse);
+       }
+    }
+  if (mtype == MET_CALL)
+    {
+      int idx_norm = -1;
+      MetricList *mlist_norm = get_metric_list (MET_NORMAL);
+      Vector<Metric*> *items_norm = mlist_norm->get_items ();
+      for (int i = 0; i < items_norm->size (); i++)
+       {
+         char * name_norm = items_norm->fetch (i)->get_username ();
+         char * name_cc = items->fetch (visindex)->get_username ();
+         if (mlist_norm->get_sort_ref_index () == i
+             && 0 == strncmp (name_norm, name_cc, strlen (name_norm)))
+           {
+             idx_norm = i;
+             break;
+           }
+       }
+      if (idx_norm == -1)
+       {
+         for (int i = 0; i < items_norm->size (); i++)
+           {
+             char * name_norm = items_norm->fetch (i)->get_username ();
+             char * name_cc = items->fetch (visindex)->get_username ();
+             if (0 == strncmp (name_norm, name_cc, strlen (name_norm)))
+               {
+                 idx_norm = i;
+                 break;
+               }
+           }
+       }
+      if (idx_norm != -1)
+       {
+         mlist_norm->set_sort (idx_norm, reverse);
+         resortData (MET_NORMAL);
+       }
+      // Change a sort metric for MET_CALL_AGR
+      Metric *m = items->fetch (visindex);
+      MetricList *cList = get_metric_list (MET_CALL_AGR);
+      Metric *m1 = cList->find_metric (m->get_cmd (), m->get_subtype ());
+      if (m1)
+       cList->set_sort_metric (m1->get_cmd (), m1->get_subtype (), reverse);
+    }
+}
+
+void
+DbeView::resortData (MetricType mtype)
+{
+  int idx;
+  Hist_data *data;
+
+  MetricList *mlist = get_metric_list (mtype);
+  switch (mtype)
+    {
+    case MET_NORMAL:
+      if (func_data != NULL)
+       func_data->resort (mlist);
+      if (line_data != NULL)
+       line_data->resort (mlist);
+      if (pc_data != NULL)
+       pc_data->resort (mlist);
+      break;
+    case MET_CALL:
+    case MET_CALL_AGR:
+      if (fitem_data != NULL)
+       fitem_data->resort (mlist);
+      if (callers != NULL)
+         callers->resort (mlist);
+      if (callees != NULL)
+       callees->resort (mlist);
+      break;
+    case MET_DATA:
+      if (dobj_data != NULL)
+       dobj_data->resort (mlist);
+      if (dlay_data != NULL)
+       {
+         delete dlay_data;
+         dlay_data = NULL;
+       }
+      break;
+    case MET_INDX:
+      Vec_loop (Hist_data*, indx_data, idx, data)
+      {
+       if (data)
+         data->resort (mlist);
+      }
+      break;
+    case MET_IO:
+      if (iofile_data != NULL)
+       iofile_data->resort (mlist);
+      if (iovfd_data != NULL)
+       iovfd_data->resort (mlist);
+      if (iocs_data != NULL)
+         iocs_data->resort (mlist);
+      break;
+    case MET_HEAP:
+      if (heapcs_data != NULL)
+       heapcs_data->resort (mlist);
+      break;
+    case MET_COMMON:
+    case MET_SRCDIS:
+      break;
+    }
+}
+
+// Get the sort metric name
+char *
+DbeView::getSort (MetricType mtype)
+{
+  MetricList *mlist = get_metric_list (mtype);
+  return mlist->get_sort_name ();
+}
+
+// Get the sort command (to use for resetting)
+char *
+DbeView::getSortCmd (MetricType mtype)
+{
+  MetricList *mlist = get_metric_list (mtype);
+  return mlist->get_sort_cmd ();
+}
+
+int
+DbeView::get_sel_ind (Histable *selObj, int type, int subtype)
+{
+  Hist_data *data;
+  switch (type)
+    {
+    case DSP_FUNCTION:
+      data = func_data;
+      break;
+    case DSP_LINE:
+      data = line_data;
+      break;
+    case DSP_PC:
+      data = pc_data;
+      break;
+    case DSP_SOURCE:
+    case DSP_SOURCE_V2:
+      data = src_data;
+      break;
+    case DSP_DISASM:
+    case DSP_DISASM_V2:
+      data = dis_data;
+      break;
+    case DSP_DLAYOUT:
+      data = dlay_data;
+      break;
+    case DSP_DATAOBJ:
+      data = dobj_data;
+      break;
+    case DSP_IOACTIVITY:
+      data = iofile_data;
+      break;
+    case DSP_IOVFD:
+      data = iovfd_data;
+      break;
+    case DSP_IOCALLSTACK:
+      data = iocs_data;
+      break;
+    case DSP_HEAPCALLSTACK:
+      data = heapcs_data;
+      break;
+    case DSP_MEMOBJ:
+    case DSP_INDXOBJ:
+      data = get_indxobj_data (subtype);
+      break;
+    default:
+      data = NULL;
+      break;
+    }
+  if (data == NULL || data->get_status () != Hist_data::SUCCESS)
+    return -1;
+  Vector<Hist_data::HistItem*> *hi_data = data->get_hist_items ();
+  for (int i = 0, sz = hi_data->size (); i < sz; i++)
+    {
+      Hist_data::HistItem *hi = hi_data->fetch (i);
+      if (hi->obj == selObj)
+       return i;
+    }
+  return -1;
+}
+
+MetricList *
+DbeView::get_metric_list (MetricType mtype, bool compare, int gr_num)
+{
+  MetricList *mlist;
+  switch (mtype)
+    {
+    case MET_COMMON:// comparison mode, src & disasm views
+      if (gr_num == 0)
+       {// signifies same src file (or load obj) used by all groups
+         // show compare metrics in columns (not in separate source panels)
+         mlist = get_metric_list (MET_NORMAL);
+         break;
+       }
+      // once source panel per group; get metrics for this group
+      mlist = get_metric_list (mtype);
+      if (compare)
+       {
+         mlist = get_compare_mlist (mlist, gr_num - 1);
+         int mode = get_compare_mode ();
+         if ((mode & (CMP_DELTA | CMP_RATIO)) != 0)
+           {
+             for (long i = 0, sz = mlist->size (); i < sz; i++)
+               {
+                 Metric *m = mlist->get (i);
+                 char *expr_spec = m->get_expr_spec ();
+                 if (expr_spec && (strcmp (expr_spec, NTXT ("EXPGRID==1")) != 0))
+                   {
+                     int vbits = m->get_visbits () & ~(VAL_DELTA | VAL_RATIO);
+                     if ((mode & CMP_RATIO) != 0)
+                       vbits |= VAL_RATIO;
+                     else if ((mode & CMP_DELTA) != 0)
+                       vbits |= VAL_DELTA;
+                     m->set_raw_visbits (vbits);
+                   }
+               }
+           }
+       }
+      break;
+    default:
+      mlist = get_metric_list (mtype);
+      break;
+    }
+  return mlist;
+}
+
+Hist_data *
+DbeView::get_data (MetricList *mlist, Histable *selObj, int type, int subtype)
+{
+  Hist_data *data;
+  switch (type)
+    {
+    case DSP_FUNCTION:
+      delete func_data;
+      mlist = new MetricList (mlist);
+      func_data = get_hist_data (mlist, Histable::FUNCTION, subtype, Hist_data::ALL);
+      return func_data;
+    case DSP_LINE:
+      delete line_data;
+      mlist = new MetricList (mlist);
+      line_data = get_hist_data (mlist, Histable::LINE, subtype, Hist_data::ALL);
+      return line_data;
+    case DSP_PC:
+      delete pc_data;
+      mlist = new MetricList (mlist);
+      pc_data = get_hist_data (mlist, Histable::INSTR, subtype, Hist_data::ALL);
+      return pc_data;
+    case DSP_DATAOBJ:
+      delete dobj_data;
+      dobj_data = get_hist_data (mlist, Histable::DOBJECT, subtype,
+                                Hist_data::ALL);
+      break;
+    case DSP_MEMOBJ:
+      return get_hist_data (mlist, Histable::MEMOBJ, subtype, Hist_data::ALL);
+    case DSP_INDXOBJ:
+      data = get_hist_data (mlist, Histable::INDEXOBJ, subtype, Hist_data::ALL);
+      indx_data->store (subtype, data);
+      return data;
+    case DSP_DLAYOUT:
+      delete dlay_data;
+      marks->reset ();
+      data = get_hist_data (mlist, Histable::DOBJECT, subtype,
+                           Hist_data::LAYOUT);
+      // .. provides metric data for layout
+      dlay_data = get_data_space ()->get_layout_data (data, marks,
+                                                     get_thresh_dis ());
+      return dlay_data;
+    case DSP_CALLER:
+      delete callers;
+      callers = get_hist_data (mlist, Histable::FUNCTION, subtype,
+                              Hist_data::CALLERS, selObj);
+      return callers;
+    case DSP_CALLEE:
+      delete callees;
+      callees = get_hist_data (mlist, Histable::FUNCTION, subtype,
+                              Hist_data::CALLEES, selObj);
+      return callees;
+    case DSP_SELF:
+      // Center Function item
+      delete fitem_data;
+      fitem_data = get_hist_data (mlist, Histable::FUNCTION, subtype,
+                                 Hist_data::SELF, selObj);
+      return fitem_data;
+    case DSP_SOURCE_V2:
+    case DSP_DISASM_V2:
+    case DSP_SOURCE:
+    case DSP_DISASM:
+      {
+       // Source or disassembly
+       if (selObj == NULL)
+         {
+           error_msg = status_str (DBEVIEW_NO_SEL_OBJ);
+           return NULL;
+         }
+       Function *func = (Function *) selObj->convertto (Histable::FUNCTION);
+       if (func == NULL)
+         {
+           error_msg = dbe_strdup (GTXT ("Not a real function; no source or disassembly available."));
+           return NULL;
+         }
+       if (func->flags & FUNC_FLAG_SIMULATED)
+         {
+           error_msg = dbe_strdup (GTXT ("Not a real function; no source or disassembly available."));
+           return NULL;
+         }
+       if (func->get_name () == NULL)
+         {
+           error_msg = dbe_strdup (GTXT ("Source location not recorded in experiment"));
+           return NULL;
+         }
+       Module *module = func->module;
+       if (module == NULL || module->get_name () == NULL)
+         {
+           error_msg = dbe_strdup (GTXT ("Object name not recorded in experiment"));
+           return NULL;
+         }
+       marks->reset ();
+       SourceFile *srcContext = (SourceFile *) selObj->convertto (Histable::SOURCEFILE);
+       sel_binctx = func;
+
+       if (func_data == NULL)
+         func_data = get_hist_data (mlist, Histable::FUNCTION, subtype, Hist_data::ALL);
+
+       // for source and disassembly the name needs to be invisible,
+       //      but that's handled in the module code
+       if (type == DSP_SOURCE || type == DSP_SOURCE_V2)
+         {
+           marks2dsrc->reset ();
+           marks2dsrc_inc->reset ();
+           delete src_data;
+           data = src_data = module->get_data (this, mlist, Histable::LINE,
+                             func_data->get_totals ()->value, srcContext, func,
+                             marks, get_thresh_src (), get_src_compcom (),
+                             get_src_visible (), get_hex_visible (),
+                             false, false, marks2dsrc, marks2dsrc_inc);
+         }
+       else
+         { /* type == DSP_DISASM */
+           marks2ddis->reset ();
+           marks2ddis_inc->reset ();
+           delete dis_data;
+           data = dis_data = module->get_data (this, mlist, Histable::INSTR,
+                             func_data->get_totals ()->value, srcContext, func,
+                             marks, get_thresh_dis (), get_dis_compcom (),
+                             get_src_visible (), get_hex_visible (),
+                             get_func_scope (), false, marks2ddis,
+                             marks2ddis_inc);
+         }
+       return data;
+      }
+    default:
+      abort ();
+    }
+  return NULL;
+}
+
+Histable *
+DbeView::get_compare_obj (Histable *obj)
+{
+  char *nm;
+  switch (obj->get_type ())
+    {
+    case Histable::LINE:
+      nm = obj->get_name ();
+      if (nm == NULL)
+       break;
+      if (dbeSession->comp_dbelines == NULL)
+       dbeSession->comp_dbelines = new HashMap<char*, DbeLine*>;
+      return dbeSession->comp_dbelines->get (nm, (DbeLine*) obj);
+    case Histable::SOURCEFILE:
+      nm = obj->get_name ();
+      if (nm == NULL)
+       break;
+      nm = get_basename (nm);
+      if (dbeSession->comp_sources == NULL)
+       dbeSession->comp_sources = new HashMap<char*, SourceFile*>;
+      return dbeSession->comp_sources->get (nm, (SourceFile*) obj);
+    default:
+      return obj->get_compare_obj ();
+    }
+  return obj;
+}
+
+//
+//   get_hist_data() creates a new Hist_data object;
+//   it's caller's responsibility to delete it.
+Hist_data *
+DbeView::get_hist_data (MetricList *mlist_orig, Histable::Type type,
+                       int subtype, Hist_data::Mode mode, Histable *obj,
+                       Histable *context, Vector<Histable*> *sel_objs,
+                       PathTree::PtreeComputeOption flag)
+{
+  Vector<Histable*> *objs = NULL;
+  if (obj != NULL)
+    {
+      objs = new Vector<Histable*>();
+      objs->append (obj);
+    }
+  Hist_data *res = get_hist_data (mlist_orig, type, subtype, mode, objs, context, sel_objs, flag);
+  delete objs;
+  return res;
+}
+
+Hist_data *
+DbeView::get_hist_data (MetricList *mlist_orig, Histable::Type type,
+                       int subtype, Hist_data::Mode mode,
+                       Vector<Histable*> *objs,
+                       Histable *context, Vector<Histable*> *sel_objs,
+                       PathTree::PtreeComputeOption flag)
+{
+  MetricList *mlist = new MetricList (mlist_orig);
+  /*
+   * mlist differs from mlist_orig in two ways:
+   * - extra metrics have been added as needed to compute derived metrics
+   * - extra metrics have been added as needed to compute time for HWC (time converted) metrics
+   *     (We don't drop those extra metrics but we don't display they to user.)
+   * - visibility bits have been added for compare mode (e.g., VAL_DELTA or VAL_RATIO)
+   *     (We want to preserve those visbits.)
+   */
+  // loop over mlist to add missing dependencies for derived metrics
+  for (long i = 0, sz = mlist->get_items ()->size (); i < sz; i++)
+    {
+      Metric *m = mlist->get_items ()->fetch (i);
+      char *expr_spec = m->get_expr_spec ();
+      if (expr_spec && (strcmp (expr_spec, NTXT ("EXPGRID==1")) != 0))
+       {
+         int ind = mlist->get_listorder (m->get_cmd (), m->get_subtype (), NTXT ("EXPGRID==1"));
+         if (ind < 0)
+           {
+             BaseMetric *bm1 = dbeSession->find_metric (m->get_type (), m->get_cmd (), NTXT ("EXPGRID==1"));
+             Metric *m1 = new Metric (bm1, m->get_subtype ());
+             m1->set_dmetrics_visbits (VAL_VALUE);
+             mlist->append (m1);
+           }
+       }
+    }
+
+  for (long i = 0, sz = mlist->get_items ()->size (); i < sz; i++)
+    {
+      Metric *m = mlist->get_items ()->fetch (i);
+      if (m->get_type () == BaseMetric::DERIVED)
+       {
+         Definition *def = m->get_definition ();
+         Vector<BaseMetric*> *dependencies = def->get_dependencies ();
+         long *map = def->get_map ();
+         for (long i1 = 0, sz1 = dependencies ? dependencies->size () : 0; i1 < sz1; i1++)
+           {
+             BaseMetric *bm = dependencies->fetch (i1);
+             int ind = mlist->get_listorder (bm->get_cmd (), m->get_subtype (), m->get_expr_spec ());
+             if (ind < 0)
+               {
+                 BaseMetric *bm1 = dbeSession->find_metric (bm->get_type (), bm->get_cmd (), m->get_expr_spec ());
+                 assert (bm1 != NULL);
+                 Metric *m1 = new Metric (bm1, m->get_subtype ());
+                 m1->set_dmetrics_visbits (VAL_VALUE);
+                 ind = mlist->size ();
+                 mlist->append (m1);
+               }
+             map[i1] = ind;
+           }
+       }
+      else if (m->get_type () == BaseMetric::HWCNTR)
+       {
+         if (m->is_tvisible () && m->get_dependent_bm ())
+           {
+             int ii = mlist->get_listorder (m->get_dependent_bm ()->get_cmd (),
+                                       m->get_subtype (), m->get_expr_spec ());
+             if (ii < 0)
+               {
+                 BaseMetric *bm1 = dbeSession->find_metric (m->get_type (),
+                                            m->get_dependent_bm ()->get_cmd (),
+                                            m->get_expr_spec ());
+                 assert (bm1 != NULL);
+                 Metric *m1 = new Metric (bm1, m->get_subtype ());
+                 m1->set_dmetrics_visbits ((m->get_visbits ()
+                                            & ~VAL_VALUE) | VAL_TIMEVAL);
+                 mlist->append (m1);
+               }
+           }
+       }
+    }
+
+  // compute Hist_data
+  Hist_data *data;
+  switch (type)
+    {
+    case Histable::INSTR:
+    case Histable::LINE:
+      data = ptree->compute_metrics (mlist, type, mode, objs, context, sel_objs);
+      break;
+    case Histable::FUNCTION:
+    case Histable::MODULE:
+    case Histable::LOADOBJECT:
+      data = ptree->compute_metrics (mlist, type, mode, objs, NULL,
+                                    sel_objs, flag);
+      break;
+    case Histable::DOBJECT:
+      data = dspace->compute_metrics (mlist, type, mode,
+                                     objs ? objs->fetch (0) : NULL);
+      break;
+    case Histable::MEMOBJ:
+    case Histable::INDEXOBJ:
+      data = indxspaces->get (subtype)->compute_metrics (mlist, type, mode,
+                                                        objs, NULL);
+      break;
+    case Histable::IOACTFILE:
+      if (objs == NULL)
+       {
+         data = iofile_data = iospace->compute_metrics (mlist, type, mode,
+                                                        NULL);
+         break;
+       }
+      else
+       {
+         data = iospace->compute_metrics (mlist, type, mode, objs->fetch (0));
+         break;
+       }
+    case Histable::IOACTVFD:
+      if (objs == NULL)
+       data = iovfd_data = iospace->compute_metrics (mlist, type, mode, NULL);
+      else
+       data = iospace->compute_metrics (mlist, type, mode, objs->fetch (0));
+      break;
+    case Histable::IOCALLSTACK:
+      if (objs == NULL)
+       data = iocs_data = iospace->compute_metrics (mlist, type, mode, NULL);
+      else
+       data = iospace->compute_metrics (mlist, type, mode, objs->fetch (0));
+      break;
+    case Histable::HEAPCALLSTACK:
+      if (objs == NULL)
+       data = heapcs_data = heapspace->compute_metrics (mlist, type, mode, NULL);
+      else
+       data = heapspace->compute_metrics (mlist, type, mode, objs->fetch (0));
+      break;
+    default:
+      data = NULL;
+      break;
+    }
+  for (long i = mlist_orig->get_items ()->size (),
+         sz = mlist->get_items ()->size (); i < sz; i++)
+    {
+      Metric *m = mlist->get_items ()->get (i);
+      m->set_dmetrics_visbits (VAL_HIDE_ALL | m->get_visbits ());
+    }
+  if (data)
+    data->nmetrics = mlist_orig->size ();
+  return data;
+}
+
+char *
+DbeView::get_mobj_name (int subtype)
+{
+  MemorySpace *ms = getMemorySpace (subtype);
+  if (ms == NULL)
+    ms = addMemorySpace (subtype);
+  return ms->getMemObjTypeName ();
+}
+
+MemorySpace *
+DbeView::getMemorySpace (int subtype)
+{
+  for (long i = 0, sz = VecSize (memspaces); i < sz; i++)
+    {
+      MemorySpace *ms = memspaces->get (i);
+      if (subtype == ms->getMemObjType ())
+       return ms;
+    }
+  return NULL;
+}
+
+MemorySpace *
+DbeView::addMemorySpace (int subtype)
+{
+  MemorySpace *ms = new MemorySpace (this, subtype);
+  memspaces->append (ms);
+  return ms;
+}
+
+Hist_data *
+DbeView::get_indxobj_data (int subtype)
+{
+  if (subtype < 0 || subtype >= indx_data->size ())
+    return NULL;
+  return indx_data->fetch (subtype);
+}
+
+void
+DbeView::set_indxobj_sel (int subtype, int sel_ind)
+{
+  Hist_data *data = get_indxobj_data (subtype);
+  if (data == NULL)
+    return;
+  if (sel_ind >= 0 && sel_ind < data->size ())
+    {
+      Histable *obj = data->fetch (sel_ind)->obj;
+      sel_idxobj->store (subtype, obj);
+    }
+}
+
+Histable *
+DbeView::get_indxobj_sel (int subtype)
+{
+  return sel_idxobj->fetch (subtype);
+}
+
+void
+DbeView::addIndexSpace (int subtype)
+{
+  PathTree *is = new PathTree (this, subtype);
+  indxspaces->store (subtype, is);
+  indx_data->store (subtype, NULL);
+  sel_idxobj->store (subtype, NULL);
+  settings->indxobj_define (subtype, false);
+}
+
+Histable *
+DbeView::get_sel_obj_io (uint64_t id, Histable::Type type)
+{
+  if (iospace == NULL)
+    return NULL;
+  Histable *obj = NULL;
+  Hist_data *data = NULL;
+  switch (type)
+    {
+    case Histable::IOACTFILE:
+      data = iofile_data;
+      break;
+    case Histable::IOACTVFD:
+      data = iovfd_data;
+      break;
+    case Histable::IOCALLSTACK:
+      data = iocs_data;
+      break;
+    default:
+      break;
+    }
+  if (data == NULL)
+    return NULL;
+
+  Vector<Hist_data::HistItem*> *hi_data = data->get_hist_items ();
+  int size = hi_data->size ();
+  for (int i = 0; i < size; i++)
+    {
+      Hist_data::HistItem *hi = hi_data->fetch (i);
+      if (hi->obj != NULL && (uint64_t) hi->obj->id == id)
+       {
+         obj = hi->obj;
+         break;
+       }
+    }
+  return obj;
+}
+
+Histable *
+DbeView::get_sel_obj_heap (uint64_t id)
+{
+  if (heapspace == NULL || heapcs_data == NULL)
+    return NULL;
+  Histable *obj = NULL;
+  Hist_data *data = heapcs_data;
+  Vector<Hist_data::HistItem*> *hi_data = data->get_hist_items ();
+  int size = hi_data->size ();
+  for (int i = 0; i < size; i++)
+    {
+      Hist_data::HistItem *hi = hi_data->fetch (i);
+      if ((hi->obj != NULL) && ((uint64_t) hi->obj->id) == id)
+       {
+         obj = hi->obj;
+         break;
+       }
+    }
+  return obj;
+}
+
+CStack_data *
+DbeView::get_cstack_data (MetricList *mlist)
+{
+  return ptree->get_cstack_data (mlist);
+}
+
+Stats_data *
+DbeView::get_stats_data (int index)
+{
+  DataView *packets = get_filtered_events (index, DATA_SAMPLE);
+  if (packets == NULL)
+    return NULL;
+  return new Stats_data (packets);
+}
+
+Ovw_data *
+DbeView::get_ovw_data (int index)
+{
+  DataView *packets = get_filtered_events (index, DATA_SAMPLE);
+  Experiment* exp = dbeSession->get_exp (index);
+  hrtime_t starttime = 0;
+  if (exp != NULL)
+    starttime = exp->getStartTime ();
+  if (packets == NULL)
+    return NULL;
+  return new Ovw_data (packets, starttime);
+}
+
+char *
+DbeView::set_filter (const char *filter_spec)
+{
+  if (dbe_strcmp (filter_spec, cur_filter_str) == 0)  // Nothing was changed
+    return NULL;
+
+  // if string is NULL, delete the filter
+  if (filter_spec == NULL)
+    {
+      if (cur_filter_str)
+       {
+         free (cur_filter_str);
+         cur_filter_str = NULL;
+       }
+      if (cur_filter_expr)
+       {
+         delete cur_filter_expr;
+         cur_filter_expr = NULL;
+       }
+      noParFilter = false;
+      purge_events ();
+      reset_data (false);
+      return NULL;
+    }
+
+  // process the filter
+  Expression *expr = dbeSession->ql_parse (filter_spec);
+  if (expr == NULL)
+    return dbe_sprintf (GTXT ("Invalid filter specification `%s'\n"), filter_spec);
+
+  if (dbe_strcmp (filter_spec, "1") == 0)
+    noParFilter = false;
+  else if (sel_obj != NULL)
+    if (sel_obj->get_type () == Histable::LINE)
+      if (expr->verifyObjectInExpr (sel_obj))
+       noParFilter = true;
+
+  // valid new filter
+  if (cur_filter_str != NULL)
+    {
+      free (prev_filter_str);
+      prev_filter_str = dbe_strdup (cur_filter_str);
+    }
+  free (cur_filter_str);
+  cur_filter_str = dbe_strdup (filter_spec);
+  delete cur_filter_expr;
+  cur_filter_expr = expr;
+  purge_events ();
+  reset_data (false);
+  return NULL;
+}
+
+FilterExp *
+DbeView::get_FilterExp (Experiment *exp)
+{
+  if (cur_filter_expr == NULL)
+    return NULL;
+  Expression::Context *ctx = new Expression::Context (this, exp);
+  return new FilterExp (cur_filter_expr, ctx, noParFilter);
+}
+
+char *
+DbeView::get_filter ()
+{
+  return dbe_strdup (cur_filter_str);
+}
+
+FilterSet *
+DbeView::get_filter_set (int n)
+{
+  fflush (stderr);
+  if (n >= filters->size ())
+    return NULL;
+  return ( filters->fetch (n));
+}
+
+Vector<FilterNumeric*> *
+DbeView::get_all_filters (int nexp)
+{
+  FilterSet *fs = get_filter_set (nexp);
+  return fs ? fs->get_all_filters () : NULL;
+}
+
+FilterNumeric *
+DbeView::get_FilterNumeric (int nexp, int idx)
+{
+  FilterSet *fs = get_filter_set (nexp);
+  return fs ? fs->get_filter (idx) : NULL;
+}
+
+void
+DbeView::backtrack_filter()
+{
+    if (prev_filter_str != NULL)
+       set_filter(prev_filter_str);
+    else set_filter("1"); // reset
+
+}
+
+void
+DbeView::update_advanced_filter ()
+{
+  char *s = get_advanced_filter ();
+  if (dbe_strcmp (s, cur_filter_str))
+    {
+      phaseIdx++;
+      char *err_msg = set_filter (s);
+      if (err_msg)
+       {
+#ifdef DEBUG
+         fprintf (stderr, NTXT ("ERROR: Advanced Filter: '%s'\n"), err_msg);
+#endif
+       }
+    }
+  free (s);
+}
+
+bool
+DbeView::set_pattern (int n, Vector<char *> *pattern_str, bool *error)
+{
+  Vector<FilterNumeric*> *filts = get_all_filters (n);
+
+  bool ret = false;
+  *error = false;
+  int imax = pattern_str->size ();
+  if (imax > filts->size ())
+    imax = filts->size ();
+  for (int i = 0; i < imax; i++)
+    {
+      FilterNumeric *f = filts->fetch (i);
+      char *s = pattern_str->fetch (i);
+      if (s == NULL)
+       continue;
+      if (f->set_pattern (s, error))
+       ret = true;
+    }
+
+  if (ret || cur_filter_expr)
+    {
+      update_advanced_filter ();
+      filter_active = true;
+    }
+  return ret;
+}
+
+static void
+append_experiments (StringBuilder *sb, int first, int last)
+{
+  if (first == -1)
+    return;
+  if (sb->length () != 0)
+    sb->append (NTXT (" || "));
+  sb->append ('(');
+  if (first == last)
+    {
+      sb->append (NTXT ("EXPID=="));
+      sb->append (first);
+    }
+  else
+    {
+      sb->append (NTXT ("EXPID>="));
+      sb->append (first);
+      sb->append (NTXT (" && EXPID<="));
+      sb->append (last);
+    }
+  sb->append (')');
+}
+
+char *
+DbeView::get_advanced_filter ()
+{
+  StringBuilder sb;
+  bool wasFalse = false;
+  int first = -1, last = -1;
+  for (int n = 0, nexps = dbeSession->nexps (); n < nexps; n++)
+    {
+      FilterSet *fs = get_filter_set (n);
+      char *s = fs->get_advanced_filter ();
+      if (s)
+       {
+         if (streq (s, NTXT ("1")))
+           {
+             last = n + 1;
+             if (first == -1)
+               first = last;
+             continue;
+           }
+         append_experiments (&sb, first, last);
+         first = -1;
+         if (streq (s, NTXT ("0")))
+           {
+             wasFalse = true;
+             continue;
+           }
+         if (sb.length () != 0)
+           sb.append (NTXT (" || "));
+         sb.append (NTXT ("(EXPID=="));
+         sb.append (n + 1);
+         sb.append (NTXT (" && ("));
+         sb.append (s);
+         free (s);
+         sb.append (NTXT ("))"));
+       }
+      else
+       {
+         last = n + 1;
+         if (first == -1)
+           first = last;
+       }
+    }
+  if (first != 1)
+    {
+      append_experiments (&sb, first, last);
+      first = -1;
+    }
+  if (sb.length () == 0)
+    sb.append (wasFalse ? '0' : '1');
+  else
+    append_experiments (&sb, first, last);
+  return sb.toString ();
+}
+
+bool
+DbeView::set_pattern (int m, char *pattern)
+{
+  bool error = false;
+
+  // Store original setting in case of error
+  int nexps = dbeSession->nexps ();
+  int orig_phaseIdx = phaseIdx;
+  bool *orig_enable = new bool[nexps];
+  char **orig_pattern = new char*[nexps];
+  for (int i = 0; i < nexps; i++)
+    {
+      orig_pattern[i] = get_FilterNumeric (i, m)->get_pattern ();
+      orig_enable[i] = get_exp_enable (i);
+      set_exp_enable (i, false);
+    }
+
+  // Copy the pattern so that we could safely modify it
+  char *buf = dbe_strdup (pattern);
+  FilterNumeric *fexp = NULL;
+  char *pb, *pe;
+  pb = pe = buf;
+  for (bool done = false; !done; pe++)
+    {
+      if (*pe == ':')
+       {
+         // experiment filter;
+         *pe = '\0';
+         fexp = new FilterNumeric (NULL, NULL, NULL);
+         fexp->set_range (1, nexps, nexps);
+         fexp->set_pattern (pb, &error);
+         if (error)
+           break;
+         pb = pe + 1;
+       }
+      else if (*pe == '+' || *pe == '\0')
+       {
+         // entity filter
+         if (*pe == '\0')
+           done = true;
+         else
+           *pe = '\0';
+         for (int i = 0; i < nexps; i++)
+           {
+             if (!fexp || fexp->is_selected (i + 1))
+               {
+                 FilterNumeric *f = get_FilterNumeric (i, m);
+                 f->set_pattern (pb, &error);
+                 if (error)
+                   break;
+                 set_exp_enable (i, true);
+               }
+           }
+         if (error)
+           break;
+         delete fexp;
+         fexp = NULL;
+         pb = pe + 1;
+       }
+    }
+
+  if (error)
+    {
+      for (int i = 0; i < nexps; i++)
+       {
+         bool err;
+         set_exp_enable (i, orig_enable[i]);
+         FilterNumeric *f = get_FilterNumeric (i, m);
+         f->set_pattern (orig_pattern[i], &err);
+         free (orig_pattern[i]);
+       }
+      phaseIdx = orig_phaseIdx;
+    }
+  else
+    {
+      update_advanced_filter ();
+      filter_active = true;
+    }
+  delete[] orig_enable;
+  delete[] orig_pattern;
+  delete fexp;
+  free (buf);
+  return !error;
+}
+
+void
+DbeView::set_view_mode (VMode newmode)
+{
+  if (newmode != settings->get_view_mode ())
+    {
+
+      // For OpenMP, the expert mode path-tree is already present with the user mode
+      // No need to increase the phaseIdx to trigger recomputation of path-tree
+      // if we toggle between user and expert modes
+      if (!(dbeSession->is_omp_available ()
+           && ((newmode == VMODE_EXPERT
+                && settings->get_view_mode () == VMODE_USER)
+               || (newmode == VMODE_USER
+                   && settings->get_view_mode () == VMODE_EXPERT))))
+       phaseIdx++; // For all other cases
+      setNewViewMode ();
+      settings->set_view_mode (newmode);
+    }
+}
+
+Cmd_status
+DbeView::set_view_mode (char *str, bool fromRC)
+{
+  VMode old = settings->get_view_mode ();
+  Cmd_status ret = settings->set_view_mode (str, fromRC);
+  if (old != settings->get_view_mode ())
+    phaseIdx++;
+  return ret;
+}
+
+Cmd_status
+DbeView::set_en_desc (char *str, bool fromRC)
+{
+  // Tell the session
+  Settings *s = dbeSession->get_settings ();
+  s->set_en_desc (str, fromRC);
+
+  // and tell our settings
+  return settings->set_en_desc (str, fromRC);
+}
+
+// Get processor stats messages
+char *
+DbeView::get_processor_msg (int type)
+{
+  if (ptree == NULL)  // if no PathTree, no messages
+    return NULL;
+
+  StringBuilder sb;
+  Emsg *m = (type == PSTAT_MSG) ? ptree->fetch_stats () : ptree->fetch_warnings ();
+  for (; m != NULL; m = m->next)
+    {
+      char* newmsg = m->get_msg ();
+      sb.append (newmsg);
+      sb.append ("\n");
+    }
+
+  if (type == PSTAT_MSG)
+    ptree->delete_stats ();
+  else
+    ptree->delete_warnings ();
+  return (sb.length () > 0) ? sb.toString () : NULL;
+}
+
+void
+DbeView::dump_nodes (FILE *outfile)
+{
+  FILE *f = (outfile == NULL ? stderr : outfile);
+  ptree->print (f);
+}
+
+// Dump the clock profile events
+void
+DbeView::dump_profile (FILE *out_file)
+{
+  for (int idx = 0; idx < dbeSession->nexps (); idx++)
+    {
+      Experiment *exp = dbeSession->get_exp (idx);
+      VMode view_mode = get_view_mode ();
+      char * stateNames [/*LMS_NUM_STATES*/] = LMS_STATE_STRINGS;
+
+      // Process clock profile date
+      DataView *packets = get_filtered_events (idx, DATA_CLOCK);
+      if (packets && packets->getSize () != 0)
+       {
+         hrtime_t start = exp->getStartTime ();
+         fprintf (out_file,
+                  GTXT ("\nTotal Clock Profiling Packets:  %d Experiment:  %s\n"),
+                  (int) packets->getSize (), exp->get_expt_name ());
+         for (long i = 0; i < packets->getSize (); i++)
+           {
+             hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
+             hrtime_t ts = expr_ts - start;
+
+             // get the properties from the packet
+             uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
+             uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
+             int mstate = (int) packets->getIntValue (PROP_MSTATE, i);
+             int nticks = (int) packets->getIntValue (PROP_NTICK, i);
+
+             char *sname;
+             char buf[1024];
+             if (mstate >= 0 && mstate < LMS_NUM_STATES)
+                 sname = stateNames[mstate];
+             else
+               {
+                 snprintf (buf, sizeof (buf), NTXT ("Unexpected mstate = %d"), mstate);
+                 sname = buf;
+               }
+
+             // get the stack   IGNORE HIDE
+             Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
+             int stack_size = stack->size ();
+
+             // print the packet header with the count of stack frames
+             fprintf (out_file,
+                      GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"),
+                      i, expr_ts, ts / NANOSEC, ts % NANOSEC,
+                      expr_ts / NANOSEC, expr_ts % NANOSEC,
+                      thrid, cpuid, stack_size);
+             fprintf (out_file,
+                      GTXT ("    mstate = %d (%s), nticks = %d\n"),
+                      mstate, sname, nticks);
+
+             // dump the callstack
+             for (int j = stack_size - 1; j >= 0; j--)
+               {
+                 Histable *frame = stack->fetch (j);
+                 fprintf (out_file, GTXT ("          %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
+               }
+             fprintf (out_file, "\n");
+           }
+       }
+      else
+       fprintf (out_file,
+                GTXT ("\nNo Clock Profiling Packets in Experiment:  %s\n"),
+                exp->get_expt_name ());
+    }
+}
+
+// Dump the sync trace events
+void
+DbeView::dump_sync (FILE *out_file)
+{
+  for (int idx = 0; idx < dbeSession->nexps (); idx++)
+    {
+      Experiment *exp = dbeSession->get_exp (idx);
+      VMode view_mode = get_view_mode ();
+
+      // Process heap trace date
+      DataView *packets = get_filtered_events (idx, DATA_SYNCH);
+      if (packets && packets->getSize () != 0)
+       {
+         hrtime_t start = exp->getStartTime ();
+         fprintf (out_file,
+                  GTXT ("\nTotal Synctrace Packets:  %d Experiment:  %s\n"),
+                  (int) packets->getSize (), exp->get_expt_name ());
+
+         for (long i = 0; i < packets->getSize (); i++)
+           {
+             hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
+             hrtime_t ts = expr_ts - start;
+
+             // get the properties from the packet
+             uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
+             uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
+             uint64_t syncobj = (uint64_t) packets->getLongValue (PROP_SOBJ, i);
+             hrtime_t syncrtime = (uint64_t) packets->getLongValue (PROP_SRQST, i);
+             hrtime_t syncdelay = expr_ts - syncrtime;
+
+             // get the stack   IGNORE HIDE
+             Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
+             int stack_size = stack->size ();
+
+             // print the packet header with the count of stack frames
+             fprintf (out_file,
+                      GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"),
+                      i, expr_ts, ts / NANOSEC, ts % NANOSEC,
+                      expr_ts / NANOSEC, expr_ts % NANOSEC, thrid,
+                      cpuid, stack_size);
+             fprintf (stderr,
+                      GTXT ("       synchronization object @ 0x%016llx;  synchronization delay  %3lld.%09lld\n"),
+                      (unsigned long long) syncobj, (long long) (syncdelay / NANOSEC), (long long) (syncdelay % NANOSEC));
+
+             // dump the callstack
+             for (int j = stack_size - 1; j >= 0; j--)
+               {
+                 Histable *frame = stack->fetch (j);
+                 fprintf (out_file, GTXT ("          %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
+               }
+             fprintf (out_file, "\n");
+           }
+       }
+      else
+       fprintf (out_file, GTXT ("\nNo Synctrace Packets in Experiment:  %s\n"),
+                exp->get_expt_name ());
+    }
+}
+
+// Dump the IO trace events
+void
+DbeView::dump_iotrace (FILE *out_file)
+{
+  for (int idx = 0; idx < dbeSession->nexps (); idx++)
+    {
+      Experiment *exp = dbeSession->get_exp (idx);
+      VMode view_mode = get_view_mode ();
+
+      // Process IO trace date
+      DataView *packets = get_filtered_events (idx, DATA_IOTRACE);
+      if (packets && packets->getSize () != 0)
+       {
+         hrtime_t start = exp->getStartTime ();
+         fprintf (out_file,
+                  GTXT ("\nTotal IO trace Packets:  %d Experiment:  %s\n"),
+                  (int) packets->getSize (), exp->get_expt_name ());
+         for (long i = 0; i < packets->getSize (); i++)
+           {
+             hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
+             hrtime_t ts = expr_ts - start;
+
+             // get the properties from the packet
+             uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
+             uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
+             IOTrace_type iotrtype = (IOTrace_type) packets->getIntValue (PROP_IOTYPE, i);
+             uint32_t iofd = (uint32_t) packets->getIntValue (PROP_IOFD, i);
+             uint64_t ionbyte = (uint64_t) packets->getIntValue (PROP_IONBYTE, i);
+             hrtime_t iorqst = (hrtime_t) packets->getLongValue (PROP_IORQST, i);
+             uint32_t ioofd = (uint32_t) packets->getIntValue (PROP_IOOFD, i);
+             FileSystem_type iofstype = (FileSystem_type) packets->getIntValue (PROP_CPUID, i);
+             int64_t iovfd = (int64_t) packets->getIntValue (PROP_IOVFD, i);
+
+             char *fName = NULL;
+             StringBuilder *sb = (StringBuilder*) packets->getObjValue (PROP_IOFNAME, i);
+             if (sb != NULL && sb->length () > 0)
+               fName = sb->toString ();
+
+             // get the stack  IGNORE HIDE
+             Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
+             int stack_size = stack->size ();
+             const char *iotrname;
+             switch (iotrtype)
+               {
+               case READ_TRACE:
+                 iotrname = "ReadTrace";
+                 break;
+               case WRITE_TRACE:
+                 iotrname = "WriteTrace";
+                 break;
+               case OPEN_TRACE:
+                 iotrname = "OpenTrace";
+                 break;
+               case CLOSE_TRACE:
+                 iotrname = "CloseTrace";
+                 break;
+               case OTHERIO_TRACE:
+                 iotrname = "OtherIOTrace";
+                 break;
+               case READ_TRACE_ERROR:
+                 iotrname = "ReadTraceError";
+                 break;
+               case WRITE_TRACE_ERROR:
+                 iotrname = "WriteTraceError";
+                 break;
+               case OPEN_TRACE_ERROR:
+                 iotrname = "OpenTraceError";
+                 break;
+               case CLOSE_TRACE_ERROR:
+                 iotrname = "CloseTraceError";
+                 break;
+               case OTHERIO_TRACE_ERROR:
+                 iotrname = "OtherIOTraceError";
+                 break;
+               default:
+                 iotrname = "UnknownIOTraceType";
+                 break;
+               }
+
+             // print the packet header with the count of stack frames
+             fprintf (out_file,
+                      GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"),
+                      i, expr_ts, ts / NANOSEC, ts % NANOSEC,
+                      expr_ts / NANOSEC, expr_ts % NANOSEC,
+                      thrid, cpuid, stack_size);
+             fprintf (out_file,
+                      GTXT ("    %s: fd = %d, ofd = %d, vfd = %lld, fstype = %d, rqst =  %3lld.%09lld\n"),
+                      iotrname, (int) iofd, (int) ioofd, (long long) iovfd,
+                      (int) iofstype, (long long) (iorqst / NANOSEC),
+                      (long long) (iorqst % NANOSEC));
+             fprintf (out_file, GTXT ("    filename = `%s', nbytes = %d\n"),
+                      STR (fName), (int) ionbyte);
+             free (fName);
+
+             // dump the callstack
+             for (int j = stack_size - 1; j >= 0; j--)
+               {
+                 Histable *frame = stack->fetch (j);
+                 fprintf (out_file, GTXT ("          %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
+               }
+             fprintf (out_file, "\n");
+           }
+       }
+      else
+       fprintf (out_file, GTXT ("\nNo IO trace Packets in Experiment:  %s\n"),
+                exp->get_expt_name ());
+    }
+}
+
+// Dump the HWC Profiling events
+void
+DbeView::dump_hwc (FILE *out_file)
+{
+  for (int idx = 0; idx < dbeSession->nexps (); idx++)
+    {
+      Experiment *exp = dbeSession->get_exp (idx);
+      VMode view_mode = get_view_mode ();
+
+      // Dump HWC profiling data
+      DataView *packets = get_filtered_events (idx, DATA_HWC);
+      if (packets && packets->getSize () != 0)
+       {
+         hrtime_t start = exp->getStartTime ();
+         fprintf (out_file,
+                  GTXT ("\nTotal HW Counter Profiling Packets:  %d Experiment:  %s\n"),
+                  (int) packets->getSize (), exp->get_expt_name ());
+         for (long i = 0; i < packets->getSize (); i++)
+           {
+             const char * hwc_name;
+             hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
+             hrtime_t ts = expr_ts - start;
+             uint32_t tag = (uint32_t) packets->getIntValue (PROP_HWCTAG, i);
+             uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
+             uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
+
+             // This will work even with a different counter in every packet.
+             if (tag < 0 || tag >= MAX_HWCOUNT
+                 || !exp->coll_params.hw_aux_name[tag])
+               // if the packet has an invalid tag, use <invalid> as its name
+               hwc_name = "<invalid>";
+             else
+               hwc_name = exp->coll_params.hw_aux_name[tag];
+             int64_t mval = packets->getLongValue (PROP_HWCINT, i);
+             const char *err = HWCVAL_HAS_ERR (mval) ? " $$" : "";
+
+             // get the stack IGNORE HIDE
+             Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
+             int stack_size = stack->size ();
+
+             // print the packet header with the count of stack frames
+             fprintf (out_file,
+                      GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n       count = %10lld (0x%016llx), tag = %d (%s)%s\n"),
+                      (long) i, (long long) expr_ts,
+                      (long long) (ts / NANOSEC), (long long) (ts % NANOSEC),
+                      (long long) (expr_ts / NANOSEC), (long long) (expr_ts % NANOSEC),
+                      (int) thrid, (int) cpuid, (int) stack_size,
+                      (long long) (HWCVAL_CLR_ERR (mval)), (long long) mval,
+                      (int) tag, hwc_name, err);
+
+             //  dump extended HWC packets values
+             uint64_t va = (uint64_t) packets->getLongValue (PROP_VADDR, i);
+             uint64_t pa = (uint64_t) packets->getLongValue (PROP_PADDR, i);
+             fprintf (out_file, GTXT ("       va = 0x%016llx, pa = 0x%016llx\n"),
+                      (unsigned long long) va, (unsigned long long) pa);
+
+             // dump the callstack
+             for (int j = stack_size - 1; j >= 0; j--)
+               {
+                 Histable *frame = stack->fetch (j);
+                 fprintf (out_file, GTXT ("          %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
+               }
+             fprintf (out_file, "\n");
+           }
+       }
+      else
+       fprintf (out_file,
+                GTXT ("\nNo HWC Profiling Packets in Experiment:  %s\n"),
+                exp->get_expt_name ());
+    }
+}
+
+// Dump the Heap events
+void
+DbeView::dump_heap (FILE *out_file)
+{
+  char *heapstrings[] = HEAPTYPE_STATE_USTRINGS;
+  for (int idx = 0; idx < dbeSession->nexps (); idx++)
+    {
+      Experiment *exp = dbeSession->get_exp (idx);
+      VMode view_mode = get_view_mode ();
+
+      // Process heap trace date
+      DataView *packets = get_filtered_events (idx, DATA_HEAP);
+      if (packets && packets->getSize () != 0)
+       {
+         hrtime_t start = exp->getStartTime ();
+         fprintf (out_file, GTXT ("\nTotal Heaptrace Packets:  %d Experiment:  %s\n"),
+                  (int) packets->getSize (), exp->get_expt_name ());
+         for (long i = 0; i < packets->getSize (); i++)
+           {
+             hrtime_t expr_ts = (hrtime_t) packets->getLongValue (PROP_TSTAMP, i);
+             hrtime_t ts = expr_ts - start;
+
+             // get the properties from the packet
+             uint32_t thrid = (uint32_t) packets->getIntValue (PROP_THRID, i);
+             uint32_t cpuid = (uint32_t) packets->getIntValue (PROP_CPUID, i);
+             uint32_t heaptype = (uint32_t) packets->getIntValue (PROP_HTYPE, i);
+             uint64_t heapsize = (uint64_t) packets->getULongValue (PROP_HSIZE, i);
+             uint64_t heapvaddr = (uint64_t) packets->getULongValue (PROP_HVADDR, i);
+             uint64_t heapovaddr = (uint64_t) packets->getULongValue (PROP_HOVADDR, i);
+             if (heaptype == MUNMAP_TRACE)
+               {
+                 heapsize = (uint64_t) packets->getULongValue (PROP_HOVADDR, i);
+                 heapovaddr = 0;
+               }
+
+             // get the stack  IGNORE HIDE
+             Vector<Histable*> *stack = getStackPCs (view_mode, packets, i);
+             int stack_size = stack->size ();
+
+             // print the packet header with the count of stack frames
+             fprintf (out_file,
+                      GTXT ("#%6ld: %lld, %3lld.%09lld (%4lld.%09lld) t = %d, cpu = %d, frames = %d\n"),
+                      i, expr_ts, ts / NANOSEC, ts % NANOSEC,
+                      expr_ts / NANOSEC, expr_ts % NANOSEC,
+                      thrid, cpuid, stack_size);
+             char *typestr = heapstrings[heaptype];
+             fprintf (out_file,
+                      GTXT ("    type = %d (%s), size = %llu (0x%llx), VADDR = 0x%016llx, OVADDR = 0x%016llx\n"),
+                      (int) heaptype, typestr, (long long unsigned int) heapsize,
+                      (long long unsigned int) heapsize,
+                      (long long unsigned int) heapvaddr,
+                      (long long unsigned int) heapovaddr);
+
+             // dump the callstack
+             for (int j = stack_size - 1; j >= 0; j--)
+               {
+                 Histable *frame = stack->fetch (j);
+                 fprintf (out_file, GTXT ("          %s [0x%016llx]\n"), frame->get_name (), (long long) frame);
+               }
+             fprintf (out_file, "\n");
+           }
+       }
+      else
+       fprintf (out_file, GTXT ("\nNo Heaptrace Packets in Experiment:  %s\n"),
+                exp->get_expt_name ());
+    }
+}
+
+// Dump the Java garbage collector events
+void
+DbeView::dump_gc_events (FILE *out_file)
+{
+  for (int idx = 0; idx < dbeSession->nexps (); idx++)
+    {
+      Experiment *exp = dbeSession->get_exp (idx);
+      if (!exp->has_java)
+       fprintf (out_file,
+                GTXT ("# No GC events in experiment %d, %s (PID %d, %s)\n"),
+                idx, exp->get_expt_name (), exp->getPID (), exp->utargname);
+      else
+       {
+         Vector<GCEvent*> *gce = exp->get_gcevents ();
+         GCEvent *this_event;
+         int index;
+         fprintf (out_file,
+                  GTXT ("# %li events in experiment %d: %s (PID %d, %s)\n"),
+                  gce->size (), idx,
+                  exp->get_expt_name (), exp->getPID (), exp->utargname);
+         fprintf (out_file,
+              GTXT ("# exp:idx     GC_start,        GC_end,   GC_duration\n"));
+         Vec_loop (GCEvent*, gce, index, this_event)
+         {
+           hrtime_t start = this_event->start - exp->getStartTime ();
+           hrtime_t end = this_event->end - exp->getStartTime ();
+           hrtime_t delta = this_event->end - this_event->start;
+           fprintf (out_file,
+                    "%5d:%d, %3lld.%09lld, %3lld.%09lld, %3lld.%09lld\n",
+                    idx, index,
+                    (long long) (start / NANOSEC), (long long) (start % NANOSEC),
+                    (long long) (end / NANOSEC), (long long) (end % NANOSEC),
+                    (long long) (delta / NANOSEC), (long long) (delta % NANOSEC));
+         }
+       }
+    }
+}
+
+void
+DbeView::purge_events (int n)
+{
+  phaseIdx++;
+  int lst;
+  if (n == -1)
+    lst = filters->size ();
+  else
+    lst = n > filters->size () ? filters->size () : n + 1;
+  for (int i = n == -1 ? 0 : n; i < lst; i++)
+    {
+      Vector<DataView*> *expDataViewList = dataViews->fetch (i);
+      if (expDataViewList)
+       {
+         // clear out all the data_ids, but don't change the vector size
+         for (int data_id = 0; data_id < expDataViewList->size (); ++data_id)
+           {
+             delete expDataViewList->fetch (data_id);
+             expDataViewList->store (data_id, NULL);
+           }
+       }
+    }
+  filter_active = false;
+}
+
+
+// LIBRARY_VISIBILITY
+void
+DbeView::resetAndConstructShowHideStacks ()
+{
+  for (int n = 0, nexps = dbeSession->nexps (); n < nexps; n++)
+    {
+      Experiment *exp = dbeSession->get_exp (n);
+      if (exp != NULL)
+       resetAndConstructShowHideStack (exp);
+    }
+}
+
+// LIBRARY_VISIBILITY
+void
+DbeView::resetAndConstructShowHideStack (Experiment *exp)
+{
+  exp->resetShowHideStack ();
+  /*  Vector<DataDescriptor*> *dDscrs = */ exp->getDataDescriptors ();
+
+  DataDescriptor *dd;
+  // Construct show hide stack only for objects which have call stacks
+  // list below similar to path tree. What about HEAP_SZ? (DBFIXME)
+  dd = exp->get_raw_events (DATA_CLOCK);
+  if (dd != NULL)
+    constructShowHideStack (dd, exp);
+  dd = exp->get_raw_events (DATA_SYNCH);
+  if (dd != NULL)
+    constructShowHideStack (dd, exp);
+  dd = exp->get_raw_events (DATA_IOTRACE);
+  if (dd != NULL)
+    constructShowHideStack (dd, exp);
+  dd = exp->get_raw_events (DATA_HWC);
+  if (dd != NULL)
+    constructShowHideStack (dd, exp);
+  dd = exp->get_raw_events (DATA_HEAP);
+  if (dd != NULL)
+    constructShowHideStack (dd, exp);
+  dd = exp->get_raw_events (DATA_RACE);
+  if (dd != NULL)
+    constructShowHideStack (dd, exp);
+  dd = exp->get_raw_events (DATA_DLCK);
+  if (dd != NULL)
+    constructShowHideStack (dd, exp);
+}
+
+// LIBRARY_VISIBILITY
+void
+DbeView::constructShowHideStack (DataDescriptor *dDscr, Experiment *exp)
+{
+  if (dDscr == NULL)
+    return;
+  int stack_prop = PROP_NONE;
+  VMode view_mode = get_view_mode ();
+  if (view_mode == VMODE_MACHINE)
+    stack_prop = PROP_MSTACK;
+  else if (view_mode == VMODE_EXPERT)
+    stack_prop = PROP_XSTACK;
+  else if (view_mode == VMODE_USER)
+    stack_prop = PROP_USTACK;
+
+  for (long j = 0, sz = dDscr->getSize (); j < sz; j++)
+    {
+      void *stackId = dDscr->getObjValue (stack_prop, j);
+      Vector<Histable*> *stack = (Vector<Histable*>*)CallStack::getStackPCs (stackId);
+      int stack_size = stack->size ();
+      bool hide_on = false;
+      LoadObject *hide_lo = NULL;
+      Histable *last_addr = NULL;
+      Histable *api_addr = NULL;
+      DbeInstr *h_instr;
+
+      Vector<Histable*> *hidepcs = new Vector<Histable*>;
+      for (int i = stack_size - 1; i >= 0; i--)
+       {
+         bool leaf = (i == 0);
+         Histable *cur_addr = stack->fetch (i);
+         Function *func = (Function*) cur_addr->convertto (Histable::FUNCTION);
+         if (func != NULL)
+           {
+             Module *mod = func->module;
+             LoadObject *lo = mod->loadobject;
+             int segx = lo->seg_idx;
+             if ((get_lo_expand (segx) == LIBEX_API) && (i != (stack_size - 1)))
+               {
+                 leaf = true;
+                 api_addr = cur_addr;
+               }
+             else if (get_lo_expand (segx) == LIBEX_HIDE)
+               {
+                 if (hide_on)
+                   {
+                     if (lo != hide_lo)
+                       {
+                         // Changed hidden loadobject
+                         if (last_addr != NULL)
+                           {
+                             h_instr = hide_lo->get_hide_instr ((DbeInstr*) last_addr);
+                             hidepcs->append (h_instr);
+                             last_addr = cur_addr;
+                           }
+                         hide_lo = lo;
+                       }
+                   }
+                 else
+                   {
+                     // Start hide
+                     hide_on = true;
+                     last_addr = cur_addr;
+                     hide_lo = lo;
+                   }
+                 if (!leaf)
+                   continue;
+               }
+             else
+               {
+                 hide_on = false;
+                 if (last_addr != NULL)
+                   {
+                     h_instr = hide_lo->get_hide_instr ((DbeInstr*) last_addr);
+                     hidepcs->append (h_instr);
+                     last_addr = NULL;
+                   }
+               }
+           }
+         if (last_addr != NULL && leaf) cur_addr = last_addr;
+         if (hide_on)
+           {
+             h_instr = hide_lo->get_hide_instr ((DbeInstr*) cur_addr);
+             hidepcs->append (h_instr);
+             if (api_addr != NULL)
+               hidepcs->append (api_addr);
+           }
+         else
+           hidepcs->append (cur_addr);
+         if (leaf)
+           break;
+       }
+      for (int i = 0, k = hidepcs->size () - 1; i < k; ++i, --k)
+       hidepcs->swap (i, k);
+
+      CallStack *cstkSH = exp->callTreeShowHide ();
+      CallStackNode *hstack = (CallStackNode *) cstkSH->add_stack (hidepcs);
+      dDscr->setObjValue (PROP_HSTACK, j, hstack);
+      CallStack::setHideStack (stackId, hstack);
+      delete hidepcs;
+      delete stack;
+    }
+}
+
+DataView *
+DbeView::get_filtered_events (int idx, int data_id)
+{
+  if (idx < 0 || idx >= dataViews->size ())
+    return NULL;
+  Vector<DataView*> *expDataViewList = dataViews->fetch (idx);
+  if (!expDataViewList)
+    return NULL; // Weird
+
+  DataView *dview = expDataViewList->fetch (data_id);
+  Experiment *exp = dbeSession->get_exp (idx);
+  if (dview)
+    {
+      // if show-hide is on force a reconstruction of hide stacks
+      // LIBRARY_VISIBILITY
+      if (!showAll && (showHideChanged || newViewMode))
+       {
+         DataDescriptor *dDscr = exp->get_raw_events (data_id);
+         constructShowHideStack (dDscr, exp);
+       }
+      return dview;
+    }
+
+  int orig_data_id = data_id;
+  data_id = exp->base_data_id (data_id);
+  if (orig_data_id != data_id)
+    // orig_data_id is a derived DataView.  Get the master DataView:
+    dview = expDataViewList->fetch (data_id);
+  if (dview == NULL)
+    {
+      Expression *saved = cur_filter_expr;
+      if (!adjust_filter (exp))
+       return NULL;
+
+      DataDescriptor *dDscr = exp->get_raw_events (data_id);
+      if (!showAll && (showHideChanged || newViewMode))
+       constructShowHideStack (dDscr, exp);
+
+      Emsg *m = exp->fetch_warnings ();
+      if (m != NULL)
+       this->warning_msg = m->get_msg ();
+
+      if (dDscr != NULL)
+       {
+         FilterExp *filter = get_FilterExp (exp);
+         dview = dDscr->createView ();
+         dview->setFilter (filter);
+         if (dview->getSize () < dDscr->getSize ())
+           filter_active = true;
+       }
+      expDataViewList->store (data_id, dview);
+
+      if (saved)
+       {
+         delete cur_filter_expr;
+         cur_filter_expr = saved;
+       }
+    }
+  if (orig_data_id != data_id)
+    {
+      // create the derived DataView:
+      dview = exp->create_derived_data_view (orig_data_id, dview);
+      expDataViewList->store (orig_data_id, dview);
+    }
+  return dview;
+}
+
+DataView *
+DbeView::get_filtered_events (int idx, int data_id,
+                             const int sortprops[], int sortprop_count)
+{
+  DataView *packets = get_filtered_events (idx, data_id);
+  if (packets)
+    packets->sort (sortprops, sortprop_count);
+  return packets;
+}
+
+bool
+DbeView::adjust_filter (Experiment *exp)
+{
+  if (cur_filter_expr)
+    {
+      Expression::Context ctx (this, exp);
+      resetFilterHideMode ();
+      Expression *fltr = cur_filter_expr->pEval (&ctx);
+      if (fltr->complete ())
+       { // Filter is a constant
+         if (fltr->eval (NULL) == 0)
+           return false;
+         delete fltr;
+         fltr = NULL;
+       }
+      cur_filter_expr = fltr;
+    }
+  return true;
+}
+
+// Moved from Cacheable.cc:
+char *
+DbeView::status_str (DbeView_status status)
+{
+  switch (status)
+    {
+    case DBEVIEW_SUCCESS:
+      return NULL;
+    case DBEVIEW_NO_DATA:
+      return dbe_strdup (GTXT ("Data not available for this filter selection"));
+    case DBEVIEW_IO_ERROR:
+      return dbe_strdup (GTXT ("Unable to open file"));
+    case DBEVIEW_BAD_DATA:
+      return dbe_strdup (GTXT ("Data corrupted"));
+    case DBEVIEW_BAD_SYMBOL_DATA:
+      return dbe_strdup (GTXT ("Functions/Modules information corrupted"));
+    case DBEVIEW_NO_SEL_OBJ:
+      return dbe_strdup (GTXT ("No selected object, bring up Functions Tab"));
+    }
+  return NULL;
+}
+
+Histable *
+DbeView::set_sel_obj (Histable *obj)
+{
+  if (obj)
+    {
+      switch (obj->get_type ())
+       {
+       case Histable::INSTR:
+         lastSelInstr = (DbeInstr *) obj;
+         lastSelFunc = lastSelInstr->func;
+         this->sel_binctx = lastSelFunc;
+         break;
+       case Histable::FUNCTION:
+         if (lastSelInstr && lastSelInstr->func != obj)
+           lastSelInstr = NULL;
+         lastSelFunc = (Function *) obj;
+         break;
+       case Histable::LINE:
+         {
+           DbeLine *dbeLine = (DbeLine *) obj;
+           if (dbeLine->func)
+             {
+               // remember previous DbeInstr and DbeFunc
+               lastSelFunc = dbeLine->func;
+               if (lastSelInstr && lastSelInstr->func != lastSelFunc)
+                 lastSelInstr = NULL;
+               this->sel_binctx = lastSelFunc;
+             }
+           else
+             this->sel_binctx = dbeLine->convertto (Histable::FUNCTION);
+           break;
+         }
+       case Histable::MODULE:
+       case Histable::LOADOBJECT:
+       case Histable::EADDR:
+       case Histable::MEMOBJ:
+       case Histable::INDEXOBJ:
+       case Histable::PAGE:
+       case Histable::DOBJECT:
+       case Histable::SOURCEFILE:
+       case Histable::IOACTFILE:
+       case Histable::IOACTVFD:
+       case Histable::IOCALLSTACK:
+       case Histable::HEAPCALLSTACK:
+       case Histable::EXPERIMENT:
+       case Histable::OTHER:
+         break;
+       }
+    }
+  sel_obj = obj;
+  Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d obj %s\n"),
+          __LINE__, obj ? obj->dump () : "NULL");
+  Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d sel_obj %s\n"),
+          __LINE__, sel_obj ? sel_obj->dump () : "NULL");
+  Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d lastSelFunc %s\n"),
+          __LINE__, lastSelFunc ? lastSelFunc->dump () : "NULL");
+  Dprintf (DEBUG_DBE, NTXT ("### set_sel_obj: DbeView.cc:%d lastSelInstr %s\n"),
+          __LINE__, lastSelInstr ? lastSelInstr->dump () : "NULL");
+  return sel_obj;
+}
+
+DbeInstr *
+DbeView::convert_line_to_instr (DbeLine *dbeLine)
+{
+  Dprintf (DEBUG_DBE, "### convert_line_to_instr DbeView::%d dbeLine=%s\n", __LINE__, dbeLine->dump ());
+  Function *func = convert_line_to_func (dbeLine);
+  if (func)
+    {
+      Dprintf (DEBUG_DBE, "### convert_line_to_instr DbeView::%d func=%s\n", __LINE__, func->dump ());
+      DbeInstr *dbeInstr = func->mapLineToPc (dbeLine);
+      Dprintf (DEBUG_DBE && dbeInstr, "### convert_line_to_instr DbeView::%d dbeInstr=%s\n", __LINE__, dbeInstr->dump ());
+      return dbeInstr;
+    }
+  Dprintf (DEBUG_DBE && lastSelInstr, "### convert_line_to_instr DbeView::%d lastSelInstr=%s\n", __LINE__, lastSelInstr->dump ());
+  return lastSelInstr;
+}
+
+DbeInstr *
+DbeView::convert_func_to_instr (Function *func)
+{
+  return (lastSelInstr && lastSelInstr->func == func) ?
+         lastSelInstr : (DbeInstr *) func->convertto (Histable::INSTR);
+}
+
+Function *
+DbeView::convert_line_to_func (DbeLine *dbeLine)
+{
+  Function *func = dbeLine->func;
+  if (func)
+    return func;
+  if (lastSelFunc != NULL)
+    // Can be mapped to the same function ?
+    for (DbeLine *dl = dbeLine->dbeline_base; dl; dl = dl->dbeline_func_next)
+      if (dl->func == lastSelFunc)
+       return lastSelFunc;
+
+  PathTree *pathTree = NULL;
+  Function *firstFunc = NULL;
+  for (DbeLine *dl = dbeLine->dbeline_base; dl; dl = dl->dbeline_func_next)
+    {
+      // Find a first function with non-zero metrics
+      if (dl->func)
+       {
+         if (pathTree == NULL)
+           pathTree = get_path_tree ();
+         if (pathTree->get_func_nodeidx (dl->func))
+           return dl->func;
+         if (firstFunc == NULL)
+           firstFunc = dl->func;
+       }
+    }
+  // Take a first function
+  return firstFunc;
+}
+
+Histable *
+DbeView::get_sel_obj (Histable::Type type)
+{
+  Histable *lastSelObj = sel_obj;
+  Dprintf (DEBUG_DBE, NTXT ("### get_sel_obj: DbeView.cc:%d type=%d sel_obj %s\n"),
+          __LINE__, type, lastSelObj ? lastSelObj->dump () : "NULL");
+  if (lastSelObj == NULL)
+    return NULL;
+  switch (type)
+    {
+    case Histable::INSTR:
+      if (!showAll)
+       {
+         // DBFIXME LIBRARY VISIBILITY
+         // hack to get to the hide mode object for PCs when filtering
+         // with a PC in timeline
+         if (lastSelObj->get_type () == Histable::INSTR)
+           {
+             Function *func = (Function*) (lastSelObj->convertto (Histable::FUNCTION));
+             LoadObject *lo = func->module->loadobject;
+             if (get_lo_expand (lo->seg_idx) == LIBEX_HIDE)
+               return lo->get_hide_function ();
+           }
+       }
+      if (lastSelObj->get_type () == Histable::LINE)
+       return convert_line_to_instr ((DbeLine*) lastSelObj);
+      else if (lastSelObj->get_type () == Histable::FUNCTION)
+       return convert_func_to_instr ((Function *) lastSelObj);
+      return lastSelObj->convertto (type);
+    case Histable::FUNCTION:
+      if (lastSelObj->get_type () == Histable::LINE)
+       {
+         Function *func = convert_line_to_func ((DbeLine*) lastSelObj);
+         if (func)
+           return func;
+         return NULL;
+       }
+      return lastSelObj->convertto (type);
+    case Histable::LINE:
+    default:
+      return lastSelObj->convertto (type);
+    }
+}
diff --git a/gprofng/src/DbeView.h b/gprofng/src/DbeView.h
new file mode 100644 (file)
index 0000000..bb6bb90
--- /dev/null
@@ -0,0 +1,842 @@
+/* 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.  */
+
+/*
+ * The DbeView class represents a window into the data managed by a DbeSession
+ *
+ *  A DbeView has a Settings class that determines the user preferences,
+ *  instantiated initially as a copy of the one in the DbeSession
+ *  that created it, or in the DbeView being cloned by the DbeSession
+ *
+ *  A DbeView has a vector of Experiment pointers, matching the one in the
+ *  DbeSession, and a vector of enable bits governing which of the
+ *  Experiments are currently being used to process the data.
+ *
+ *  A DbeView has three vectors of Metrics, one for functions, etc.,
+ *  a second for callers/callees, and a third for dataspace/memoryspace.
+ *
+ *  A DbeView has a vector of FilterSet's (q.v.), one for each Experiment,
+ *  used to determine how the data is filtered.
+ *
+ *  Each DbeView has its own instantiation of the objects representing
+ *  the processed, filtered data.  Currently these are a PathTree
+ *  for computing text-based metrics, a DataSpace for computing
+ *  data-based metrics, and a MemorySpace used for computing
+ *  memory-object-based metrics.
+ */
+
+#ifndef _DBEVIEW_H
+#define _DBEVIEW_H
+
+#include <stdio.h>
+#include "dbe_structs.h"
+#include "vec.h"
+#include "enums.h"
+#include "util.h"
+#include "DerivedMetrics.h"
+#include "Histable.h"
+#include "Hist_data.h"
+#include "Settings.h"
+#include "Metric.h"
+#include "Table.h"
+#include "PathTree.h"
+
+class Application;
+class DataView;
+class Experiment;
+class Expression;
+class FilterSet;
+class FilterNumeric;
+class FilterExp;
+class Function;
+class Histable;
+class MetricList;
+class Module;
+class Ovw_data;
+class PathTree;
+class DataSpace;
+class MemorySpace;
+class Stats_data;
+class LoadObject;
+class IOActivity;
+class HeapActivity;
+
+class DbeView
+{
+public:
+  DbeView (Application *app, Settings *_settings, int _vindex);
+  DbeView (DbeView *dbev, int _vindex);
+  ~DbeView ();
+
+  // Access functions for settings in the view
+  Settings *
+  get_settings ()
+  {
+    return settings;
+  };
+
+  // Get the list of tabs for this view
+  Vector<DispTab*> *
+  get_TabList ()
+  {
+    return settings->get_TabList ();
+  };
+
+  // Get the list of memory tabs for this view
+  Vector<bool> *
+  get_MemTabState ()
+  {
+    return settings->get_MemTabState ();
+  };
+
+  // Set the list of memory tabs for this view
+  void
+  set_MemTabState (Vector<bool>*sel)
+  {
+    settings->set_MemTabState (sel);
+  };
+
+  // Get the list of index tabs for this view
+  Vector<bool> *
+  get_IndxTabState ()
+  {
+    return settings->get_IndxTabState ();
+  };
+
+  // Set the list of memory tabs for this view
+  void
+  set_IndxTabState (Vector<bool>*sel)
+  {
+    settings->set_IndxTabState (sel);
+  };
+
+  // controlling the name format
+  Cmd_status
+  set_name_format (char *str)
+  {
+    return settings->set_name_format (str);
+  };
+
+  void
+  set_name_format (int fname_format, bool soname)
+  {
+    settings->set_name_format (fname_format, soname);
+  };
+
+  Histable::NameFormat
+  get_name_format ()
+  {
+    return settings->name_format;
+  }
+
+  // processing modes: view_mode
+  Cmd_status set_view_mode (char *str, bool fromRC); // from a string
+  void set_view_mode (VMode mode); // from the analyzer
+
+  VMode
+  get_view_mode ()
+  {
+    return settings->get_view_mode ();
+  };
+
+  // handling of descendant processes
+  Cmd_status set_en_desc (char *str, bool rc); // from a string
+
+  bool
+  check_en_desc (const char * lineage_name = NULL, const char *targname = NULL)
+  {
+    return settings->check_en_desc (lineage_name, targname);
+  };
+
+  // Controlling the print line-limit
+  char *
+  set_limit (char *str, bool rc) // from a string
+  {
+    settings->set_limit (str, rc);
+    return NULL;
+  };
+
+  char *
+  set_limit (int _limit)
+  {
+    settings->limit = _limit;
+    return NULL;
+  };
+
+  int
+  get_limit ()
+  {
+    return settings->limit;
+  };
+
+  // Controlling the print format mode
+  char *
+  set_printmode (char *str)
+  {
+    return settings->set_printmode (str);
+  };
+
+  enum PrintMode
+  get_printmode ()
+  {
+    return settings->print_mode;
+  };
+
+  char
+  get_printdelimiter ()
+  {
+    return settings->print_delim;
+  };
+
+  char *
+  get_printmode_str ()
+  {
+    return dbe_strdup (settings->str_printmode);
+  };
+
+  // processing compiler commentary visibility bits, and other source annotation
+  // controls
+  Cmd_status
+  proc_compcom (const char *cmd, bool isSrc, bool rc)
+  {
+    return settings->proc_compcom (cmd, isSrc, rc);
+  };
+
+  char *
+  get_str_scompcom ()
+  {
+    return settings->str_scompcom;
+  };
+
+  char *
+  get_str_dcompcom ()
+  {
+    return settings->str_dcompcom;
+  };
+
+  void
+  set_src_compcom (int v)
+  {
+    settings->src_compcom = v;
+  };
+
+  int
+  get_src_compcom ()
+  {
+    return settings->src_compcom;
+  };
+
+  void
+  set_dis_compcom (int v)
+  {
+    settings->dis_compcom = v;
+  };
+
+  int
+  get_dis_compcom ()
+  {
+    return settings->dis_compcom;
+  };
+
+  void
+  set_cmpline_visible (bool vis)
+  {
+    settings->set_cmpline_visible (vis);
+  }
+
+  int
+  get_cmpline_visible ()
+  {
+    return settings->cmpline_visible;
+  }
+
+  void
+  set_funcline_visible (bool vis)
+  {
+    settings->set_funcline_visible (vis);
+  }
+
+  int
+  get_funcline_visible ()
+  {
+    return settings->funcline_visible;
+  }
+
+  // controls for disassembly presentation
+  void
+  set_src_visible (int vis)
+  {
+    settings->set_src_visible (vis);
+  }
+
+  int
+  get_src_visible ()
+  {
+    return settings->src_visible;
+  }
+
+  void
+  set_srcmetric_visible (bool vis)
+  {
+    settings->set_srcmetric_visible (vis);
+  }
+
+  bool
+  get_srcmetric_visible ()
+  {
+    return settings->srcmetric_visible;
+  }
+
+  void
+  set_hex_visible (bool vis)
+  {
+    settings->set_hex_visible (vis);
+  }
+
+  bool
+  get_hex_visible ()
+  {
+    return settings->hex_visible;
+  }
+
+  // processing and accessing the threshold settings
+  Cmd_status
+  proc_thresh (char *cmd, bool isSrc, bool rc)
+  {
+    return settings->proc_thresh (cmd, isSrc, rc);
+  };
+
+  void
+  set_thresh_src (int v)
+  {
+    settings->threshold_src = v;
+  };
+
+  int
+  get_thresh_src ()
+  {
+    return settings->threshold_src;
+  };
+
+  void
+  set_thresh_dis (int v)
+  {
+    settings->threshold_dis = v;
+  };
+
+  int
+  get_thresh_dis ()
+  {
+    return settings->threshold_dis;
+  };
+
+  // controls for the Timeline mode, stack presentation
+  Cmd_status
+  proc_tlmode (char *cmd, bool rc)
+  {
+    return settings->proc_tlmode (cmd, rc);
+  };
+
+  void
+  set_tlmode (int _tlmode)
+  {
+    settings->tlmode = _tlmode;
+  };
+
+  int
+  get_tlmode ()
+  {
+    return settings->tlmode;
+  };
+
+  void
+  set_stack_align (int _stack_align)
+  {
+    settings->stack_align = _stack_align;
+  };
+
+  int
+  get_stack_align ()
+  {
+    return settings->stack_align;
+  };
+
+  void
+  set_stack_depth (int _stack_depth)
+  {
+    settings->stack_depth = _stack_depth;
+  };
+
+  int
+  get_stack_depth ()
+  {
+    return settings->stack_depth;
+  };
+
+  // Controls for which data is shown in Timeline
+  Cmd_status
+  proc_tldata (char *cmd, bool rc)
+  {
+    return settings->proc_tldata (cmd, rc);
+  };
+
+  void
+  set_tldata (const char* tldata_cmd)
+  {
+    settings->set_tldata (tldata_cmd);
+  };
+
+  char*
+  get_tldata ()
+  {
+    return settings->get_tldata ();
+  };
+
+  // settings controlling the expand/collapse of functions within each LoadObject
+  enum LibExpand get_lo_expand (int idx);
+
+  // set_lo_expand -- returns true if any change
+  bool set_lo_expand (int idx, enum LibExpand how);
+
+  // set_libexpand -- returns true if any change
+  bool set_libexpand (char *liblist, enum LibExpand flag);
+  void update_lo_expands ();
+  bool set_libdefaults ();
+  void reset ();
+  void reset_data (bool all);
+
+  char *
+  get_error_msg ()
+  {
+    return error_msg;
+  };
+
+  void
+  clear_error_msg ()
+  {
+    error_msg = NULL;
+  };
+
+  char *
+  get_warning_msg ()
+  {
+    return warning_msg;
+  };
+
+  void
+  clear_warning_msg ()
+  {
+    warning_msg = NULL;
+  };
+  char *get_processor_msg (int type);
+
+  // methods controlling the metric list
+  BaseMetric *register_metric_expr (BaseMetric::Type type, char *aux, char *expr_spec);
+  Vector<BaseMetric*> *get_all_reg_metrics ();
+  void reset_metric_list (MetricList *mlist, int cmp_mode);
+
+  // Get the various metric master lists
+  MetricList *get_metric_ref (MetricType mtype);
+
+  // Get the various current metric lists
+  MetricList *get_metric_list (int dsptype, int subtype);
+  MetricList *get_metric_list (MetricType mtype);
+  MetricList *get_metric_list (MetricType mtype, bool compare, int gr_num);
+  MetricList *get_compare_mlist (MetricList *met_list, int grInd);
+
+  // Set the metric list, from a string specification
+  char *setMetrics (char *metricspec, bool fromRcFile);
+
+  // Set the sort metric, from its name
+  char *setSort (char *sortname, MetricType mtype, bool fromRcFile);
+
+  // Set the sort metric, from its visible index (Analyzer)
+  void setSort (int visindex, MetricType mtype, bool reverse);
+
+  // Resort any cached data, after changing sort
+  void resortData (MetricType mtype);
+
+  // Get the sort metric
+  char *getSort (MetricType mtype);
+  char *getSortCmd (MetricType mtype);
+
+  // reset the metrics
+  void reset_metrics ();
+  bool comparingExperiments ();
+
+  int
+  get_compare_mode ()
+  {
+    return settings->compare_mode;
+  };
+
+  void
+  reset_compare_mode (int mode)
+  {
+    settings->compare_mode = mode;
+  };
+
+  void set_compare_mode (int mode); // modifies the global MET_* arrays
+  void add_compare_metrics (MetricList *mlist);
+  void remove_compare_metrics (MetricList *mlist);
+  Histable *get_compare_obj (Histable *obj);
+
+  // method for printing the instruction-frequency report
+  void ifreq (FILE *);
+
+  // methods controlling the experiment list
+  void add_experiment (int index, bool enabled);
+  void add_subexperiment (int index, bool enabled);
+  void add_experiment_epilogue ();
+  void drop_experiment (int index);
+  bool get_exp_enable (int n);
+  void set_exp_enable (int n, bool e);
+
+  // method for new-style filtering
+  char *set_filter (const char *filter_spec);
+  char *get_filter (void);
+  char *get_advanced_filter ();
+  void backtrack_filter ();
+  void update_advanced_filter ();
+  FilterExp *get_FilterExp (Experiment *exp);
+
+  Expression *
+  get_filter_expr ()
+  {
+    return cur_filter_expr;
+  };
+
+  // methods controlling old-style filtering
+  Vector<FilterNumeric*> *get_all_filters (int nexp);
+  FilterNumeric *get_FilterNumeric (int nexp, int idx);
+  bool set_pattern (int n, Vector<char *> *pattern_str, bool *error);
+  bool set_pattern (int m, char *pattern);
+
+  // Data processing objects
+  PathTree *
+  get_path_tree ()
+  {
+    return ptree;
+  };
+
+  DataSpace *
+  get_data_space ()
+  {
+    return dspace;
+  };
+
+  IOActivity *
+  get_io_space ()
+  {
+    return iospace;
+  };
+
+  HeapActivity *
+  get_heap_space ()
+  {
+    return heapspace;
+  };
+  Hist_data *get_data (MetricList *mlist, Histable *selObj, int type, int subtype);
+  int get_sel_ind (Histable *selObj, int type, int subtype);
+
+  // Return histogram data for the specified arguments.
+  Hist_data *get_hist_data (MetricList *mlist, Histable::Type type,
+                           int subtype, // used for memory objects only
+                           Hist_data::Mode mode,
+                           Vector<Histable*> *objs = NULL,
+                           Histable *context = NULL,
+                           Vector<Histable*> *sel_objs = NULL,
+                           PathTree::PtreeComputeOption flag = PathTree::COMPUTEOPT_NONE
+                           );
+  Hist_data *get_hist_data (MetricList *mlist, Histable::Type type,
+                           int subtype, // used for memory objects only
+                           Hist_data::Mode mode, Histable *obj,
+                           Histable *context = NULL,
+                           Vector<Histable*> *sel_objs = NULL,
+                           PathTree::PtreeComputeOption flag = PathTree::COMPUTEOPT_NONE
+                           );
+  CStack_data *get_cstack_data (MetricList *);
+  Stats_data *get_stats_data (int index);
+  Ovw_data *get_ovw_data (int index);
+
+  char *names_src[3]; // names for anno-src
+  char *names_dis[3]; // names for anno-dis
+
+  // Get filtered packets.  Ordering is NOT guaranteed to be
+  // stable between calls; DataView indexes are not persistent -
+  // use underlying DataDescriptor ids if you don't consume data right away.
+  // Parameters: idx==exp_id, data_id==kind==ProfData_type
+  DataView *get_filtered_events (int idx, int data_id);
+  DataView *get_filtered_events (int idx, int data_id,
+                                const int sortprops[], int sortprop_count);
+
+  // SORT is not used for PathTree.
+  // PathTree reads data once and discards. It doesn't
+  // depend on the indices so sort can be performed w/o recomputing pathtree.
+  // Timeline is the primary consumer of sort(), however Races also need to sort.
+  //
+  // YM: I can't remember the context for the following note, but
+  // In case I need it when we refactor more TBR stuff, here it is:
+  // base metrics like USER_CPU are known,(but we should/should not?)
+  // explicitly set DATA_CLOCK as a property/attribute?
+  bool adjust_filter (Experiment *exp);
+
+  // Generated report data
+  Hist_data *func_data;     // function list data
+  Hist_data *line_data;     // hot line list data
+  Hist_data *pc_data;       // hot PC list data
+  Hist_data *src_data;      // annotated source data
+  Hist_data *dis_data;      // annotated disasm data
+  Hist_data *fitem_data;    // func item for callers/callees
+  Hist_data *callers;       // callers data
+  Hist_data *callees;       // callees data
+  Hist_data *dobj_data;     // data object list data
+  Hist_data *dlay_data;     // data layout data
+  Hist_data *iofile_data;   // io data aggregated by file name
+  Hist_data *iovfd_data;    // io data aggregated by virtual fd
+  Hist_data *iocs_data;     // io data aggregated by call stack
+  Hist_data *heapcs_data;   // heap data aggregated by call stack
+  Vector<Hist_data*> *indx_data; // index object data
+  Vector<int> *lobjectsNoJava; // List of indices into LoadObjects excluding java classes
+
+  // memory object data -- create MemorySpace, if needed
+  MemorySpace *getMemorySpace (int subtype);
+  char *get_mobj_name (int subtype);
+  void addIndexSpace (int type);
+  Hist_data *get_indxobj_data (int subtype);
+  void set_indxobj_sel (int subtype, int sel_ind);
+  Histable *get_indxobj_sel (int subtype);
+  void set_obj_sel_io (int type, long sel_ind);
+  Histable *set_sel_obj (Histable *obj);
+  Histable *get_sel_obj (Histable::Type type);
+  Histable *get_sel_obj_io (uint64_t id, Histable::Type type);
+  Histable *get_sel_obj_heap (uint64_t id);
+  Histable *sel_obj;        // current selected obj
+  Histable *sel_dobj;       // current selected data obj
+  Histable *sel_binctx;     // current binary context
+  Vector<Histable*> *sel_idxobj; // selected index objects
+  char *error_msg;      // error message
+  char *warning_msg;    // warning message
+  Vector<int> *marks;   // flagged as important for anno src/dis
+  Vector<int_pair_t> *marks2dsrc;
+  Vector<int_pair_t> *marks2dsrc_inc;
+  Vector<int_pair_t> *marks2ddis;
+  Vector<int_pair_t> *marks2ddis_inc;
+
+  void dump_nodes (FILE *);     // dump out the pathtree nodes
+  void dump_profile (FILE *);   // dump out the clock profiling events
+  void dump_sync (FILE *);      // dump out the synctrace events
+  void dump_iotrace (FILE *);   // dump out the IO trace events
+  void dump_hwc (FILE *);       // dump out the HWC Profiling events
+  void dump_heap (FILE *);      // dump out the heap trace events
+  void dump_gc_events (FILE *); // dump out the Java garbage collector events
+
+  int vindex;       // index of this view -- set by Analyzer
+  bool func_scope;
+
+  bool
+  get_func_scope ()
+  {
+    return func_scope;
+  };
+
+  void
+  set_func_scope (bool scope_only)
+  {
+    func_scope = scope_only;
+  };
+
+  // value set T if filtering is active, i.e., some packets were dropped
+  bool filter_active;
+
+  bool
+  get_filter_active ()
+  {
+    return filter_active;
+  };
+
+  DerivedMetrics *
+  get_derived_metrics ()
+  {
+    return derived_metrics;
+  }
+
+  // Internal time (time means change)
+  int
+  getPhaseIdx ()
+  {
+    return phaseIdx;
+  }
+
+  enum DbeView_status
+  {
+    DBEVIEW_SUCCESS = 0,
+    DBEVIEW_NO_DATA,
+    DBEVIEW_IO_ERROR,
+    DBEVIEW_BAD_DATA,
+    DBEVIEW_BAD_SYMBOL_DATA,
+    DBEVIEW_NO_SEL_OBJ
+  };
+  static char *status_str (DbeView_status status);
+
+  bool
+  isOmpDisMode ()
+  {
+    return ompDisMode;
+  }
+
+  void
+  setOmpDisMode ()
+  {
+    ompDisMode = true;
+  }
+
+  void
+  resetOmpDisMode ()
+  {
+    ompDisMode = false;
+  }
+
+  bool
+  isShowHideChanged ()
+  {
+    return showHideChanged;
+  }
+
+  void
+  setShowHideChanged ()
+  {
+    showHideChanged = true;
+  }
+
+  void
+  resetShowHideChanged ()
+  {
+    showHideChanged = false;
+  }
+
+  bool
+  isNewViewMode ()
+  {
+    return newViewMode;
+  }
+
+  void
+  setNewViewMode ()
+  {
+    newViewMode = true;
+  }
+
+  void
+  resetNewViewMode ()
+  {
+    newViewMode = false;
+  }
+
+  bool
+  isFilterHideMode ()
+  {
+    return filterHideMode;
+  }
+
+  void
+  setFilterHideMode ()
+  {
+    filterHideMode = true;
+  }
+
+  void
+  resetFilterHideMode ()
+  {
+    filterHideMode = false;
+  }
+
+  bool
+  isShowAll ()
+  {
+    return showAll;
+  }
+
+  void
+  setShowAll ()
+  {
+    showAll = true;
+  }
+
+  void
+  resetShowAll ()
+  {
+    showAll = false;
+  }
+  void resetAndConstructShowHideStacks ();
+
+private:
+  void init ();
+  Metric *get_compare_metric (Metric *mtr, int groupNum);
+
+  // methods controlling old-style filtering
+  FilterSet *get_filter_set (int n);
+
+  void purge_events (int n = -1);
+
+  char *cur_filter_str;
+  char *prev_filter_str;
+  Expression *cur_filter_expr;
+  bool noParFilter;
+
+  // MemorySpace's -- added when a request is made; for now, never dropped
+  Vector<MemorySpace*> *memspaces;
+  MemorySpace *addMemorySpace (int mtype);
+
+  Vector<FilterSet*> *filters;
+  Vector<enum LibExpand> *lo_expands;
+  Vector<BaseMetric*> *reg_metrics;   // vector of registered metrics
+  Vector<MetricList*> *metrics_lists; // metrics list of MET_NORMAL, MET_CALL...
+                                     // note: includes compare metrics
+  Vector<MetricList*> *metrics_ref_lists;
+  DerivedMetrics *derived_metrics;  // vector of derived metrics
+
+  DataSpace *dspace;
+  PathTree *ptree;
+  Vector<PathTree *> *indxspaces;
+  IOActivity *iospace;
+  HeapActivity *heapspace;
+  int phaseIdx;
+  bool ompDisMode;
+  bool filterHideMode;
+  bool showAll;
+  bool showHideChanged;
+  bool newViewMode;
+
+  // Filtered events
+  Vector<Vector<DataView*>*> *dataViews; //outer idx is exp_id, inner is data_id
+  Settings *settings;
+
+  Application *app;
+  Function *convert_line_to_func (DbeLine *dbeLine);
+  DbeInstr *convert_line_to_instr (DbeLine *dbeLine);
+  DbeInstr *convert_func_to_instr (Function *func);
+  DbeInstr *lastSelInstr;
+  Function *lastSelFunc;
+  void constructShowHideStack (DataDescriptor* dDscr, Experiment *exp);
+  void resetAndConstructShowHideStack (Experiment *exp);
+};
+
+#endif /* _DBEVIEW_H */
diff --git a/gprofng/src/DefaultHandler.h b/gprofng/src/DefaultHandler.h
new file mode 100644 (file)
index 0000000..4c3d82c
--- /dev/null
@@ -0,0 +1,114 @@
+/* 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.  */
+
+/*
+ *  org/xml/sax/helpers/DefaultHandler.java
+ *  Based on JavaTM 2 Platform Standard Ed. 5.0
+ */
+
+#ifndef _DefaultHandler_h
+#define _DefaultHandler_h
+
+/*
+ *     org/xml/sax/Attributes.java
+ */
+class Attributes
+{
+public:
+  virtual ~Attributes () { };
+
+  virtual int getLength () = 0;
+  virtual const char *getQName (int index) = 0;
+  virtual const char *getValue (int index) = 0;
+  virtual int getIndex (const char *qName) = 0;
+  virtual const char *getValue (const char *qName) = 0;
+};
+
+/*
+ *     org/xml/sax/SAXException.java
+ */
+class SAXException
+{
+public:
+  SAXException ();
+  SAXException (const char *message);
+  virtual ~SAXException ();
+  char *getMessage ();
+
+private:
+  char *message;
+};
+
+class SAXParseException : public SAXException
+{
+public:
+  SAXParseException (char *message, int lineNumber, int columnNumber);
+
+  int
+  getLineNumber ()
+  {
+    return lineNumber;
+  }
+
+  int
+  getColumnNumber ()
+  {
+    return columnNumber;
+  }
+
+private:
+  int lineNumber;
+  int columnNumber;
+};
+
+class DefaultHandler
+{
+public:
+  virtual ~DefaultHandler () { };
+
+  virtual void startDocument () = 0;
+  virtual void endDocument () = 0;
+  virtual void startElement (char *uri, char *localName, char *qName,
+                            Attributes *attributes) = 0;
+  virtual void endElement (char *uri, char *localName, char *qName) = 0;
+  virtual void characters (char *ch, int start, int length) = 0;
+  virtual void ignorableWhitespace (char *ch, int start, int length) = 0;
+
+  virtual void
+  warning (SAXParseException *e)
+  {
+    delete e;
+  }
+
+  virtual void
+  error (SAXParseException *e)
+  {
+    delete e;
+  }
+
+  virtual void
+  fatalError (SAXParseException *e)
+  {
+    throw ( e);
+  }
+  void dump_startElement (const char *qName, Attributes *attributes);
+};
+
+#endif /* _DefaultHandler_h */
diff --git a/gprofng/src/DefaultMap.h b/gprofng/src/DefaultMap.h
new file mode 100644 (file)
index 0000000..4a87fcc
--- /dev/null
@@ -0,0 +1,232 @@
+/* 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 _DBE_DEFAULTMAP_H
+#define _DBE_DEFAULTMAP_H
+
+#include <assert.h>
+#include <vec.h>
+#include <Map.h>
+
+template <typename Key_t, typename Value_t>
+class DefaultMap : public Map<Key_t, Value_t>
+{
+public:
+
+  DefaultMap ();
+  ~DefaultMap ();
+  void clear ();
+  void put (Key_t key, Value_t val);
+  Value_t get (Key_t key);
+  Value_t get (Key_t key, typename Map<Key_t, Value_t>::Relation rel);
+  Value_t remove (Key_t);
+  Vector<Key_t> *keySet ();
+  Vector<Value_t> *values ();
+
+private:
+
+  struct Entry
+  {
+    Key_t key;
+    Value_t val;
+  };
+
+  static const int CHUNK_SIZE;
+  static const int HTABLE_SIZE;
+
+  int entries;
+  int nchunks;
+  Entry **chunks;
+  Vector<Entry*> *index;
+  Entry **hashTable;
+};
+
+
+template <typename Key_t, typename Value_t>
+const int DefaultMap<Key_t, Value_t>::CHUNK_SIZE = 16384;
+template <typename Key_t, typename Value_t>
+const int DefaultMap<Key_t, Value_t>::HTABLE_SIZE = 1024;
+
+template <typename Key_t, typename Value_t>
+DefaultMap<Key_t, Value_t>::DefaultMap ()
+{
+  entries = 0;
+  nchunks = 0;
+  chunks = NULL;
+  index = new Vector<Entry*>;
+  hashTable = new Entry*[HTABLE_SIZE];
+  for (int i = 0; i < HTABLE_SIZE; i++)
+    hashTable[i] = NULL;
+}
+
+template <typename Key_t, typename Value_t>
+DefaultMap<Key_t, Value_t>::~DefaultMap ()
+{
+  for (int i = 0; i < nchunks; i++)
+    delete[] chunks[i];
+  delete[] chunks;
+  delete index;
+  delete[] hashTable;
+}
+
+template <typename Key_t, typename Value_t>
+void
+DefaultMap<Key_t, Value_t>::clear ()
+{
+  entries = 0;
+  index->reset ();
+  for (int i = 0; i < HTABLE_SIZE; i++)
+    hashTable[i] = NULL;
+}
+
+template <typename Key_t>
+inline unsigned
+hash (Key_t key)
+{
+  unsigned h = (unsigned) ((unsigned long) key);
+  h ^= (h >> 20) ^ (h >> 12);
+  return (h ^ (h >> 7) ^ (h >> 4));
+}
+
+template <typename Key_t, typename Value_t>
+void
+DefaultMap<Key_t, Value_t>::put (Key_t key, Value_t val)
+{
+  unsigned idx = hash (key) % HTABLE_SIZE;
+  Entry *entry = hashTable[idx];
+  if (entry && entry->key == key)
+    {
+      entry->val = val;
+      return;
+    }
+  int lo = 0;
+  int hi = entries - 1;
+  while (lo <= hi)
+    {
+      int md = (lo + hi) / 2;
+      entry = index->fetch (md);
+      int cmp = entry->key < key ? -1 : entry->key > key ? 1 : 0;
+      if (cmp < 0)
+       lo = md + 1;
+      else if (cmp > 0)
+       hi = md - 1;
+      else
+       {
+         entry->val = val;
+         return;
+       }
+    }
+  if (entries >= nchunks * CHUNK_SIZE)
+    {
+      nchunks++;
+      // Reallocate Entry chunk array
+      Entry **new_chunks = new Entry*[nchunks];
+      for (int i = 0; i < nchunks - 1; i++)
+       new_chunks[i] = chunks[i];
+      delete[] chunks;
+      chunks = new_chunks;
+
+      // Allocate new chunk for entries.
+      chunks[nchunks - 1] = new Entry[CHUNK_SIZE];
+    }
+  entry = &chunks[entries / CHUNK_SIZE][entries % CHUNK_SIZE];
+  entry->key = key;
+  entry->val = val;
+  index->insert (lo, entry);
+  hashTable[idx] = entry;
+  entries++;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+DefaultMap<Key_t, Value_t>::get (Key_t key)
+{
+  unsigned idx = hash (key) % HTABLE_SIZE;
+  Entry *entry = hashTable[idx];
+  if (entry && entry->key == key)
+    return entry->val;
+
+  int lo = 0;
+  int hi = entries - 1;
+  while (lo <= hi)
+    {
+      int md = (lo + hi) / 2;
+      entry = index->fetch (md);
+      int cmp = entry->key < key ? -1 : entry->key > key ? 1 : 0;
+      if (cmp < 0)
+       lo = md + 1;
+      else if (cmp > 0)
+       hi = md - 1;
+      else
+       {
+         hashTable[idx] = entry;
+         return entry->val;
+       }
+    }
+  return (Value_t) 0;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+DefaultMap<Key_t, Value_t>::get (Key_t key,
+                                typename Map<Key_t, Value_t>::Relation rel)
+{
+  if (rel != Map<Key_t, Value_t>::REL_EQ)
+    return (Value_t) 0;
+  return get (key);
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+DefaultMap<Key_t, Value_t>::remove (Key_t)
+{
+  // Not implemented
+  if (1)
+    assert (0);
+  return (Value_t) 0;
+}
+
+template <typename Key_t, typename Value_t>
+Vector<Value_t> *
+DefaultMap<Key_t, Value_t>::values ()
+{
+  Vector<Value_t> *vals = new Vector<Value_t>(entries);
+  for (int i = 0; i < entries; ++i)
+    {
+      Entry *entry = index->fetch (i);
+      vals->append (entry->val);
+    }
+  return vals;
+}
+
+template <typename Key_t, typename Value_t>
+Vector<Key_t> *
+DefaultMap<Key_t, Value_t>::keySet ()
+{
+  Vector<Key_t> *keys = new Vector<Key_t>(entries);
+  for (int i = 0; i < entries; ++i)
+    {
+      Entry *entry = index->fetch (i);
+      keys->append (entry->key);
+    }
+  return keys;
+}
+
+#endif
diff --git a/gprofng/src/DefaultMap2D.h b/gprofng/src/DefaultMap2D.h
new file mode 100644 (file)
index 0000000..8045aad
--- /dev/null
@@ -0,0 +1,147 @@
+/* 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 _DBE_DEFAULTMAP2D_H
+#define _DBE_DEFAULTMAP2D_H
+
+#include <assert.h>
+#include <vec.h>
+#include <DefaultMap.h>
+#include <IntervalMap.h>
+#include <Map2D.h>
+
+/*
+ *     Default Map2D implementation.
+ *
+ *    Default Map2D is a cartesian product of two default Maps.
+ */
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+class DefaultMap2D : public Map2D<Key1_t, Key2_t, Value_t>
+{
+public:
+  DefaultMap2D ();
+  DefaultMap2D (typename Map2D<Key1_t, Key2_t, Value_t>::MapType _type);
+  ~DefaultMap2D ();
+  void put (Key1_t key1, Key2_t key2, Value_t val);
+  Value_t get (Key1_t key1, Key2_t key2);
+  Value_t get (Key1_t key1, Key2_t key2,
+              typename Map2D<Key1_t, Key2_t, Value_t>::Relation rel);
+  Value_t remove (Key1_t, Key2_t);
+
+private:
+  typename Map2D<Key1_t, Key2_t, Value_t>::MapType type;
+  Map<Key1_t, Map<Key2_t, Value_t>*> *map1;
+  Vector<Map<Key2_t, Value_t>*> *map2list;
+};
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+DefaultMap2D<Key1_t, Key2_t, Value_t>::DefaultMap2D ()
+{
+  type = Map2D<Key1_t, Key2_t, Value_t>::Default;
+  map1 = new DefaultMap<Key1_t, Map<Key2_t, Value_t>*>;
+  map2list = new Vector<Map<Key2_t, Value_t>*>;
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+DefaultMap2D<Key1_t, Key2_t, Value_t>::DefaultMap2D (
+                        typename Map2D<Key1_t, Key2_t, Value_t>::MapType _type)
+{
+  type = _type;
+  map1 = new DefaultMap<Key1_t, Map<Key2_t, Value_t>*>;
+  map2list = new Vector<Map<Key2_t, Value_t>*>;
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+DefaultMap2D<Key1_t, Key2_t, Value_t>::~DefaultMap2D ()
+{
+  map2list->destroy ();
+  delete map2list;
+  delete map1;
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+void
+DefaultMap2D<Key1_t, Key2_t, Value_t>::put (Key1_t key1, Key2_t key2, Value_t val)
+{
+  Map<Key2_t, Value_t> *map2 = map1->get (key1);
+  if (map2 == NULL)
+    {
+      if (type == Map2D<Key1_t, Key2_t, Value_t>::Interval)
+       map2 = new IntervalMap<Key2_t, Value_t>;
+      else
+       map2 = new DefaultMap<Key2_t, Value_t>;
+      map2list->append (map2);
+      map1->put (key1, map2);
+    }
+  map2->put (key2, val);
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+Value_t
+DefaultMap2D<Key1_t, Key2_t, Value_t>::get (Key1_t key1, Key2_t key2)
+{
+  Map<Key2_t, Value_t> *map2 = map1->get (key1);
+  if (map2 == NULL)
+    return (Value_t) 0;
+  return map2->get (key2);
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+Value_t
+DefaultMap2D<Key1_t, Key2_t, Value_t>::get (Key1_t key1, Key2_t key2,
+                         typename Map2D<Key1_t, Key2_t, Value_t>::Relation rel)
+{
+  Map<Key2_t, Value_t> *map2 = map1->get (key1);
+  if (map2 == NULL)
+    return (Value_t) 0;
+  typename Map<Key2_t, Value_t>::Relation rel2;
+  switch (rel)
+    {
+    case Map2D<Key1_t, Key2_t, Value_t>::REL_EQLT:
+      rel2 = map2->REL_LT;
+      break;
+    case Map2D<Key1_t, Key2_t, Value_t>::REL_EQLE:
+      rel2 = map2->REL_LE;
+      break;
+    case Map2D<Key1_t, Key2_t, Value_t>::REL_EQGE:
+      rel2 = map2->REL_GE;
+      break;
+    case Map2D<Key1_t, Key2_t, Value_t>::REL_EQGT:
+      rel2 = map2->REL_GT;
+      break;
+    default:
+      rel2 = map2->REL_EQ;
+      break;
+    }
+  return map2->get (key2, rel2);
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+Value_t
+DefaultMap2D<Key1_t, Key2_t, Value_t>::remove (Key1_t, Key2_t)
+{
+  // Not implemented
+  if (1)
+    assert (0);
+  return (Value_t) 0;
+}
+
+#endif
diff --git a/gprofng/src/DerivedMetrics.cc b/gprofng/src/DerivedMetrics.cc
new file mode 100644 (file)
index 0000000..9f504a5
--- /dev/null
@@ -0,0 +1,293 @@
+/* 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 <strings.h>
+#include "DerivedMetrics.h"
+#include "util.h"
+
+enum opType
+{
+  opNULL,
+  opPrimitive,
+  opDivide
+};
+
+class definition
+{
+public:
+  definition();
+  ~definition();
+  char *name;
+  char *def;
+  opType op;
+  definition *arg1;
+  definition *arg2;
+  int index;
+};
+
+definition::definition ()
+{
+  name = def = NULL;
+  arg1 = arg2 = NULL;
+}
+
+definition::~definition ()
+{
+  free (name);
+  free (def);
+}
+
+DerivedMetrics::DerivedMetrics ()
+{
+  items = new Vector<definition*>;
+}
+
+DerivedMetrics::~DerivedMetrics ()
+{
+  Destroy (items);
+}
+
+definition *
+DerivedMetrics::add_definition (char *_name, char *_username, char *_def)
+{
+  definition *p;
+
+  // if the name doesn't matter, maybe there is a duplicate we can use
+  if (_name == NULL)
+    {
+      int i;
+      Vec_loop (definition*, items, i, p)
+      {
+       if (strcmp (p->def, _def) == 0)
+         return p;
+      }
+    }
+
+  p = new definition;
+  p->name = dbe_strdup (_name);
+  p->def = dbe_strdup (_def);
+
+  // parse the definition
+  if (strchr (_def, '/') == NULL)
+    {
+      // it's a primitive metric
+      p->op = opPrimitive;
+      p->arg1 = p->arg2 = NULL;
+
+    }
+  else
+    {
+      // it's some operation on arguments
+      p->op = opDivide;
+      char *op_ptr = strchr (p->def, '/');
+      *op_ptr = 0;
+      p->arg1 = add_definition (NULL, NULL, p->def);
+      *op_ptr = '/';
+      p->arg2 = add_definition (NULL, NULL, op_ptr + 1);
+    }
+  p->index = items->size ();
+  items->append (p);
+  return p;
+}
+
+int *
+DerivedMetrics::construct_map (Vector<Metric*> *mitems, BaseMetric::SubType st, char *expr_spec)
+{
+  if (items == NULL)
+    return NULL;
+  int ndm = items->size ();
+  if (ndm == 0)
+    return NULL;
+  int nmetrics = mitems->size ();
+
+  // allocate arrays for the mapping between derived metrics and requested values
+  int *map = (int *) malloc (ndm * sizeof (int));
+
+  // map derived metrics to requested metrics    // EUGENE explain this more clearly
+  //   0  means not mapped
+  //  >0  means primitive metric maps to map-1
+  //  <0  means  derived  metric maps to 1-map
+  int ndm_requested = 0;
+  for (int idm = 0; idm < ndm; idm++)
+    {
+      definition *defdm = items->fetch (idm);
+      map[idm] = 0;
+
+      // figure out what name to use for this derived metric
+      char *dname;
+      if (defdm->op == opPrimitive)
+       dname = defdm->def;
+      else
+       {
+         dname = defdm->name;
+         if (dname == NULL) break;
+       }
+
+      // look for this name among metrics
+      int im;
+      for (im = 0; im < nmetrics; im++)
+       {
+         Metric *m = mitems->fetch (im);
+         if (strcmp (dname, m->get_cmd ()) == 0 && m->get_subtype () == st)
+           // apparent match, but let's check comparison mode
+           if (dbe_strcmp (expr_spec, m->get_expr_spec ()) == 0)
+             break;
+       }
+
+      // encode the mapping
+      if (im >= nmetrics)
+       map[idm] = 0; // does not map to requested metrics
+      else if (defdm->op == opPrimitive)
+       map[idm] = +1 + im; // encode as a positive index
+      else
+       {
+         map[idm] = -1 - im; // encode as a negative index
+         ndm_requested++;
+       }
+    }
+  if (ndm_requested == 0)
+    {
+      free (map);
+      map = NULL;
+    }
+  return map;
+}
+
+void
+DerivedMetrics::fill_dependencies (definition *def, int *vec)
+{
+  switch (def->op)
+    {
+    case opPrimitive:
+      vec[def->index] = 1;
+      break;
+    case opDivide:
+      fill_dependencies (def->arg1, vec);
+      fill_dependencies (def->arg2, vec);
+      break;
+    default:
+      break;
+    }
+}
+
+Vector<definition*> *
+DerivedMetrics::get_dependencies (definition *def)
+{
+  int n = items->size ();
+
+  // zero out a vector representing definitions
+  int *vec = (int *) malloc (n * sizeof (int));
+  for (int i = 0; i < n; i++)
+    vec[i] = 0;
+  fill_dependencies (def, vec);
+
+  // construct the dependency vector
+  Vector<definition*> *dependencies = new Vector<definition*>;
+  for (int i = 0; i < n; i++)
+    if (vec[i] == 1)
+      dependencies->append (items->fetch (i));
+  free (vec);
+  return dependencies;
+}
+
+void
+DerivedMetrics::dump (FILE *dis_file, int verbosity)
+{
+  int i;
+  definition *item;
+
+  // deal with the possibility that names might be NULL
+  const char *UNNAMED = "(unnamed)";
+#define NAME(x) ( (x) ? (x) : UNNAMED)
+
+  Vec_loop (definition*, items, i, item)
+  {
+    // at low verbosity, skip over some items
+    if (verbosity == 0)
+      {
+       if (item->name == NULL)
+         continue;
+       if (strcmp (item->name, item->def) && item->op == opPrimitive)
+         continue;
+      }
+
+    // dump the definition
+    switch (item->op)
+      {
+      case opPrimitive:
+       fprintf (dis_file, "%s [%s] is a primitive metric\n", NAME (item->name),
+                item->def);
+       break;
+      case opDivide:
+       fprintf (dis_file, "%s [%s] = %s [%s] / %s [%s]\n", NAME (item->name),
+                item->def, NAME (item->arg1->name), item->arg1->def,
+                NAME (item->arg2->name), item->arg2->def);
+       break;
+      default:
+       fprintf (dis_file, "%s [%s] has an unrecognized op %d\n",
+                NAME (item->name), item->def, item->op);
+       break;
+      }
+  }
+}
+
+double
+DerivedMetrics::eval_one_item (definition *def, int *map, double *values)
+{
+  switch (def->op)
+    {
+    case opNULL:
+      fprintf (stderr, GTXT ("cannot eval NULL expression\n"));
+      return 0.;
+    case opPrimitive:
+      {
+       int ival = map[def->index];
+       if (ival <= 0) return 0.;
+       ival--;
+       return values[ival];
+      }
+    case opDivide:
+      {
+       double x1 = eval_one_item (def->arg1, map, values);
+       double x2 = eval_one_item (def->arg2, map, values);
+       if (x2 == 0) return 0.;
+       return (x1 / x2);
+      }
+    default:
+      fprintf (stderr, GTXT ("unknown expression\n"));
+      return 0.;
+    }
+}
+
+int
+DerivedMetrics::eval (int *map, double *values)
+{
+  for (int i = 0, n = items->size (); i < n; i++)
+    {
+      if (map[i] < 0)
+       {
+         int ival = -1 - map[i];
+         values[ival] = eval_one_item (items->fetch (i), map, values);
+       }
+    }
+  return 0;
+}
+
diff --git a/gprofng/src/DerivedMetrics.h b/gprofng/src/DerivedMetrics.h
new file mode 100644 (file)
index 0000000..b457e5e
--- /dev/null
@@ -0,0 +1,54 @@
+/* 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 _DERIVEDMETRICS_H
+#define _DERIVEDMETRICS_H
+
+#include <stdio.h>
+#include "BaseMetric.h"
+#include "Metric.h"
+
+class definition;
+
+class DerivedMetrics
+{
+public:
+  DerivedMetrics ();
+  ~DerivedMetrics ();
+  definition *add_definition (char *_name, char *_username, char *_def);
+  int *construct_map (Vector<Metric*> *mitems, BaseMetric::SubType st,
+                     char *expr_spec);
+  void dump (FILE *dis_file, int verbosity);
+  double eval_one_item (definition *def, int *map, double *values);
+  int eval (int *map, double *values);
+  void fill_dependencies (definition *def, int *vec);
+  Vector<definition*> *get_dependencies (definition *def);
+
+  Vector<definition*> *
+  get_items ()
+  {
+    return items;
+  }
+
+private:
+  Vector<definition*> *items;
+};
+
+#endif
diff --git a/gprofng/src/Disasm.cc b/gprofng/src/Disasm.cc
new file mode 100644 (file)
index 0000000..0fec9c3
--- /dev/null
@@ -0,0 +1,403 @@
+/* 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 <stdio.h>
+#include <string.h>
+#include <sys/param.h>
+
+#include "disassemble.h"
+#include "dis-asm.h"
+#include "demangle.h"
+#include "dbe_types.h"
+#include "DbeSession.h"
+#include "Elf.h"
+#include "Disasm.h"
+#include "Stabs.h"
+#include "i18n.h"
+#include "util.h"
+#include "StringBuilder.h"
+
+struct DisContext
+{
+  bool is_Intel;
+  Stabs *stabs;
+  uint64_t pc;          // first_pc <= pc < last_pc
+  uint64_t first_pc;
+  uint64_t last_pc;
+  uint64_t f_offset;    // file offset for first_pc
+  int codeptr[4];       // longest instruction length may not be > 16
+  Data_window *elf;
+};
+
+static const int MAX_DISASM_STR     = 2048;
+static const int MAX_INSTR_SIZE     = 8;
+
+Disasm::Disasm (char *fname)
+{
+  dwin = NULL;
+  dis_str = NULL;
+  need_swap_endian = false;
+  my_stabs = Stabs::NewStabs (fname, fname);
+  if (my_stabs == NULL)
+    return;
+  stabs = my_stabs;
+  platform = stabs->get_platform ();
+  disasm_open ();
+}
+
+Disasm::Disasm (Platform_t _platform, Stabs *_stabs)
+{
+  dwin = NULL;
+  dis_str = NULL;
+  need_swap_endian = false;
+  stabs = _stabs;
+  platform = _platform;
+  my_stabs = NULL;
+  disasm_open ();
+}
+
+static int
+fprintf_func (void *arg, const char *fmt, ...)
+{
+  char buf[512];
+  va_list vp;
+  va_start (vp, fmt);
+  int cnt = vsnprintf (buf, sizeof (buf), fmt, vp);
+  va_end (vp);
+
+  Disasm *dis = (Disasm *) arg;
+  dis->dis_str->append (buf);
+  return cnt;
+}
+
+/* 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, disassemble_info *info)
+{
+  (*info->fprintf_func) (info->stream, "0x%llx", (unsigned long long) addr);
+}
+
+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, bfd_vma addr, disassemble_info *info)
+{
+  info->fprintf_func (info->stream, "Address 0x%llx is out of bounds.\n",
+                     (unsigned long long) addr);
+}
+
+void
+Disasm::disasm_open ()
+{
+  hex_visible = 1;
+  snprintf (addr_fmt, sizeof (addr_fmt), NTXT ("%s"), NTXT ("%8llx:  "));
+  if (dis_str == NULL)
+    dis_str = new StringBuilder;
+
+  switch (platform)
+    {
+    case Aarch64:
+    case Intel:
+    case Amd64:
+      need_swap_endian = (DbeSession::platform == Sparc);
+      break;
+    case Sparcv8plus:
+    case Sparcv9:
+    case Sparc:
+    default:
+      need_swap_endian = (DbeSession::platform != Sparc);
+      break;
+    }
+
+  memset (&dis_info, 0, sizeof (dis_info));
+  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 = this;
+  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;
+  switch (platform)
+    {
+    case Aarch64:
+      dis_info.arch = bfd_arch_aarch64;
+      dis_info.mach = bfd_mach_aarch64;
+      break;
+    case Intel:
+    case Amd64:
+      dis_info.arch = bfd_arch_i386;
+      dis_info.mach = bfd_mach_x86_64;
+      break;
+    case Sparcv8plus:
+    case Sparcv9:
+    case Sparc:
+    default:
+      dis_info.arch = bfd_arch_unknown;
+      dis_info.endian = BFD_ENDIAN_UNKNOWN;
+      break;
+    }
+  dis_info.display_endian = dis_info.endian = BFD_ENDIAN_BIG;
+  dis_info.display_endian = dis_info.endian = BFD_ENDIAN_LITTLE;
+  dis_info.display_endian = dis_info.endian = BFD_ENDIAN_UNKNOWN;
+  disassemble_init_for_target (&dis_info);
+}
+
+Disasm::~Disasm ()
+{
+  delete my_stabs;
+  delete dwin;
+  delete dis_str;
+}
+
+void
+Disasm::set_img_name (char *img_fname)
+{
+  if (stabs == NULL && img_fname && dwin == NULL)
+    {
+      dwin = new Data_window (img_fname);
+      if (dwin->not_opened ())
+       {
+         delete dwin;
+         dwin = NULL;
+         return;
+       }
+      dwin->need_swap_endian = need_swap_endian;
+    }
+}
+
+void
+Disasm::remove_disasm_hndl (void *hndl)
+{
+  DisContext *ctx = (DisContext *) hndl;
+  delete ctx;
+}
+
+#if 0
+int
+Disasm::get_instr_size (uint64_t vaddr, void *hndl)
+{
+  DisContext *ctx = (DisContext *) hndl;
+  if (ctx == NULL || vaddr < ctx->first_pc || vaddr >= ctx->last_pc)
+    return -1;
+  ctx->pc = vaddr;
+  size_t sz = ctx->is_Intel ? sizeof (ctx->codeptr) : 4;
+  if (sz > ctx->last_pc - vaddr)
+    sz = (size_t) (ctx->last_pc - vaddr);
+  if (ctx->elf->get_data (ctx->f_offset + (vaddr - ctx->first_pc),
+                         sz, ctx->codeptr) == NULL)
+    return -1;
+
+  char buf[MAX_DISASM_STR];
+  *buf = 0;
+  uint64_t inst_vaddr = vaddr;
+#if MEZ_NEED_TO_FIX
+  size_t instrs_cnt = 0;
+  disasm_err_code_t status = disasm (handle, &inst_vaddr, ctx->last_pc, 1,
+                                    ctx, buf, sizeof (buf), &instrs_cnt);
+  if (instrs_cnt != 1 || status != disasm_err_ok)
+    return -1;
+#endif
+  return (int) (inst_vaddr - vaddr);
+}
+#endif
+
+void
+Disasm::set_addr_end (uint64_t end_address)
+{
+  char buf[32];
+  int len = snprintf (buf, sizeof (buf), "%llx", (long long) end_address);
+  snprintf (addr_fmt, sizeof (addr_fmt), "%%%dllx:  ", len < 8 ? 8 : len);
+}
+
+char *
+Disasm::get_disasm (uint64_t inst_address, uint64_t end_address,
+                 uint64_t start_address, uint64_t f_offset, int64_t &inst_size)
+{
+  inst_size = 0;
+  if (inst_address >= end_address)
+    return NULL;
+  Data_window *dw = stabs ? stabs->openElf (false) : dwin;
+  if (dw == NULL)
+    return NULL;
+
+  unsigned char buffer[MAX_DISASM_STR];
+  dis_info.buffer = buffer;
+  dis_info.buffer_length = end_address - inst_address;
+  if (dis_info.buffer_length > sizeof (buffer))
+    dis_info.buffer_length = sizeof (buffer);
+  dw->get_data (f_offset + (inst_address - start_address),
+               dis_info.buffer_length, dis_info.buffer);
+
+  dis_str->setLength (0);
+  bfd abfd;
+  disassembler_ftype disassemble = disassembler (dis_info.arch, dis_info.endian,
+                                                dis_info.mach, &abfd);
+  if (disassemble == NULL)
+    {
+      printf ("ERROR: unsupported disassemble\n");
+      return NULL;
+    }
+  inst_size = disassemble (0, &dis_info);
+  if (inst_size <= 0)
+    {
+      inst_size = 0;
+      return NULL;
+    }
+  StringBuilder sb;
+  sb.appendf (addr_fmt, inst_address); // Write address
+
+  // Write hex bytes of instruction
+  if (hex_visible)
+    {
+      char bytes[64];
+      *bytes = '\0';
+      for (int i = 0; i < inst_size; i++)
+       {
+         unsigned int hex_value = buffer[i] & 0xff;
+         snprintf (bytes + 3 * i, sizeof (bytes) - 3 * i, "%02x ", hex_value);
+       }
+      const char *fmt = "%s   ";
+      if (platform == Intel)
+       fmt = "%-21s   "; // 21 = 3 * 7 - maximum instruction length on Intel
+      sb.appendf (fmt, bytes);
+    }
+  sb.append (dis_str);
+#if MEZ_NEED_TO_FIX
+  // Write instruction
+  if (ctx.is_Intel)  // longest instruction length for Intel is 7
+    sb.appendf (NTXT ("%-7s %s"), parts_array[1], parts_array[2]);
+  else  // longest instruction length for SPARC is 11
+    sb.appendf (NTXT ("%-11s %s"), parts_array[1], parts_array[2]);
+  if (strcmp (parts_array[1], NTXT ("call")) == 0)
+    {
+      if (strncmp (parts_array[2], NTXT ("0x"), 2) == 0)
+       sb.append (GTXT ("\t! (Unable to determine target symbol)"));
+    }
+#endif
+  return sb.toString ();
+}
+
+#if MEZ_NEED_TO_FIX
+void *
+Disasm::get_inst_ptr (disasm_handle_t, uint64_t vaddr, void *pass_through)
+{
+  // Actually it fetches only one instruction at a time for sparc,
+  // and one byte at a time for intel.
+  DisContext *ctx = (DisContext*) pass_through;
+  size_t sz = ctx->is_Intel ? 1 : 4;
+  if (vaddr + sz > ctx->last_pc)
+    {
+      ctx->codeptr[0] = -1;
+      return ctx->codeptr;
+    }
+  if (ctx->elf->get_data (ctx->f_offset + (vaddr - ctx->first_pc), sz, ctx->codeptr) == NULL)
+    {
+      ctx->codeptr[0] = -1;
+      return ctx->codeptr;
+    }
+  if (ctx->elf->need_swap_endian && !ctx->is_Intel)
+    ctx->codeptr[0] = ctx->elf->decode (ctx->codeptr[0]);
+  return ctx->codeptr;
+}
+
+// get a symbol name for an address
+disasm_err_code_t
+Disasm::get_sym_name (disasm_handle_t,          // an open disassembler handle
+                     uint64_t target_address,  // the target virtual address
+                     uint64_t inst_address,  // virtual address of instruction
+                                             // being disassembled
+                     int use_relocation, // flag to use relocation information
+                     char *buffer,             // places the symbol here
+                     size_t buffer_size,       // limit on symbol length
+                     int *,                    // sys/elf_{SPARC.386}.h
+                     uint64_t *offset,       // from the symbol to the address
+                     void *pass_through)       // disassembler context
+{
+  char buf[MAXPATHLEN];
+  if (!use_relocation)
+    return disasm_err_symbol;
+
+  DisContext *ctxp = (DisContext*) pass_through;
+  char *name = NULL;
+  if (ctxp->stabs)
+    {
+      uint64_t addr = ctxp->f_offset + (inst_address - ctxp->first_pc);
+      name = ctxp->stabs->sym_name (target_address, addr, use_relocation);
+    }
+  if (name == NULL)
+    return disasm_err_symbol;
+
+  char *s = NULL;
+  if (*name == '_')
+    s = cplus_demangle (name, DMGL_PARAMS);
+  if (s)
+    {
+      snprintf (buffer, buffer_size, NTXT ("%s"), s);
+      free (s);
+    }
+  else
+    snprintf (buffer, buffer_size, NTXT ("%s"), name);
+
+  *offset = 0;
+  return disasm_err_ok;
+}
+#endif
diff --git a/gprofng/src/Disasm.h b/gprofng/src/Disasm.h
new file mode 100644 (file)
index 0000000..c1530cc
--- /dev/null
@@ -0,0 +1,66 @@
+/* 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 _DISASM_H
+#define _DISASM_H
+
+#include "disassemble.h"
+
+class Data_window;
+class Stabs;
+class StringBuilder;
+enum Platform_t;
+
+class Disasm
+{
+public:
+  Disasm (char *fname);
+  Disasm (Platform_t _platform, Stabs *_stabs);
+  ~Disasm ();
+  void remove_disasm_hndl (void *hndl);
+  void *get_disasm_hndl (uint64_t vaddr, uint64_t f_offset, size_t size);
+  int get_instr_size (uint64_t vaddr, void *hndl);
+  void set_addr_end (uint64_t end_address);
+
+  void
+  set_hex_visible (int set)
+  {
+    hex_visible = set;
+  }
+
+  char *get_disasm (uint64_t inst_address, uint64_t end_address,
+                uint64_t start_address, uint64_t f_offset, int64_t &inst_size);
+  void set_img_name (char *fname);  // Only for dynfunc
+
+  StringBuilder *dis_str;
+
+private:
+  void disasm_open ();
+
+  disassemble_info dis_info;
+  Data_window *dwin;
+  Stabs *stabs, *my_stabs;
+  Platform_t platform;
+  char addr_fmt[32];
+  int hex_visible;
+  bool need_swap_endian;
+};
+
+#endif  /* _DISASM_H */
diff --git a/gprofng/src/Dwarf.cc b/gprofng/src/Dwarf.cc
new file mode 100644 (file)
index 0000000..eb8bd9e
--- /dev/null
@@ -0,0 +1,1041 @@
+/* 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 "util.h"
+#include "DbeSession.h"
+#include "Elf.h"
+#include "Stabs.h"
+#include "Dwarf.h"
+#include "DataObject.h"
+#include "Function.h"
+#include "LoadObject.h"
+#include "Module.h"
+#include "DefaultMap.h"
+
+static int
+datatypeCmp (const void *a, const void *b)
+{
+  uint32_t o1 = ((datatype_t *) a)->datatype_id;
+  uint32_t o2 = ((datatype_t *) b)->datatype_id;
+  return o1 == o2 ? 0 : (o1 < o2 ? -1 : 1);
+}
+
+static int
+targetOffsetCmp (const void *a, const void *b)
+{
+  uint32_t o1 = ((target_info_t *) a)->offset;
+  uint32_t o2 = ((target_info_t *) b)->offset;
+  return o1 == o2 ? 0 : (o1 < o2 ? -1 : 1);
+}
+
+
+//////////////////////////////////////////////////////////
+//  class Dwr_type
+class Dwr_type
+{
+public:
+
+  Dwr_type (int64_t _cu_die_offset, int _tag)
+  {
+    cu_die_offset = _cu_die_offset;
+    tag = _tag;
+    name = NULL;
+    dobj_name = NULL;
+    dtype = NULL;
+    extent = 0;
+    parent = 0;
+    child = 0;
+    next = 0;
+    ref_type = 0;
+    size = 0;
+    elems = 0;
+    offset = -1;
+    bit_size = 0;
+  };
+
+  char *name, *dobj_name;
+  int64_t cu_die_offset, ref_type, extent, parent, child, next;
+  int64_t size, elems, offset;
+  int tag, bit_size;
+
+  DataObject *get_dobj (Dwarf_cnt *ctx);
+  char *get_dobjname (Dwarf_cnt *ctx);
+  char *dump ();
+
+private:
+  datatype_t *dtype;
+  datatype_t *get_datatype (Dwarf_cnt *ctx);
+  void get_dobj_for_members (Dwarf_cnt *ctx);
+  void set_dobjname (char *spec, char *nm);
+};
+
+
+//////////////////////////////////////////////////////////
+//  class Dwarf_cnt
+Dwarf_cnt::Dwarf_cnt ()
+{
+  cu_offset = 0;
+  parent = 0;
+  module = NULL;
+  name = NULL;
+  func = NULL;
+  fortranMAIN = NULL;
+  dwr_types = NULL;
+  inlinedSubr = NULL;
+  level = 0;
+}
+
+Dwr_type *
+Dwarf_cnt::get_dwr_type (int64_t cu_die_offset)
+{
+  Dwr_type *t = dwr_types->get (cu_die_offset);
+  if (t == NULL)
+    {
+      Dprintf (DUMP_DWARFLIB, "DWARF_ERROR: %s:%d wrong cu_die_offset=%lld in Dwarf_cnt::get_dwr_type\n",
+              get_basename (__FILE__), (int) __LINE__,
+              (long long) cu_die_offset);
+      t = put_dwr_type (cu_die_offset, 0); // DOBJ_UNSPECIFIED
+    }
+  return t;
+}
+
+Dwr_type *
+Dwarf_cnt::put_dwr_type (int64_t cu_die_offset, int tag)
+{
+  Dwr_type *t = new Dwr_type (cu_die_offset, tag);
+  dwr_types->put (cu_die_offset, t);
+  return t;
+}
+
+Dwr_type *
+Dwarf_cnt::put_dwr_type (Dwr_Tag *dwrTag)
+{
+  Dwr_type *t = new Dwr_type (dwrTag->die, dwrTag->tag);
+  dwr_types->put (dwrTag->die, t);
+  return t;
+}
+
+//////////////////////////////////////////////////////////
+//  class Dwr_type
+char *
+Dwr_type::dump ()
+{
+  char *s = dbe_sprintf ("%lld %-15s name='%s' parent=%lld next=%lld child=%lld dtype=%llx",
+                        (long long) cu_die_offset, DwrCU::tag2str (tag),
+                        STR (name), (long long) parent, (long long) next,
+                        (long long) child, (long long) dtype);
+  return s;
+}
+
+void
+Dwr_type::set_dobjname (char *spec, char *nm)
+{
+  if (spec)
+    {
+      if (nm)
+       dobj_name = dbe_sprintf ("%s%s", spec, nm);
+      else
+       dobj_name = dbe_sprintf ("%s<ANON=%lld>", spec,
+                                (long long) cu_die_offset);
+    }
+  else
+    {
+      if (nm)
+       dobj_name = dbe_sprintf ("%s", nm);
+      else
+       dobj_name = dbe_sprintf ("<ANON=%lld>", (long long) cu_die_offset);
+    }
+}
+
+char *
+Dwr_type::get_dobjname (Dwarf_cnt *ctx)
+{
+  if (dobj_name)
+    return dobj_name;
+  switch (tag)
+    {
+    case DW_TAG_base_type:
+      set_dobjname (NULL, name);
+      for (int i = 0, len = (int) strlen (dobj_name); i < len; i++)
+       {
+         if (dobj_name[i] == ' ')
+           dobj_name[i] = '_';
+       }
+      break;
+    case DW_TAG_constant:
+    case DW_TAG_formal_parameter:
+    case DW_TAG_variable:
+      {
+       Dwr_type *t = ctx->get_dwr_type (ref_type);
+       set_dobjname (NULL, t->get_dobjname (ctx));
+       break;
+      }
+    case DW_TAG_unspecified_type:
+      set_dobjname (NTXT ("unspecified:"), name);
+      break;
+    case DW_TAG_enumeration_type:
+      set_dobjname (NTXT ("enumeration:"), name);
+      break;
+    case DW_TAG_typedef:
+      {
+       Dwr_type *t = ctx->get_dwr_type (ref_type);
+       dobj_name = dbe_sprintf ("%s=%s", name, t->get_dobjname (ctx));
+       break;
+      }
+    case DW_TAG_const_type:
+      set_dobjname (NTXT ("const+"), name);
+      break;
+    case DW_TAG_volatile_type:
+      set_dobjname (NTXT ("volatile+"), name);
+      break;
+    case DW_TAG_pointer_type:
+      {
+       Dwr_type *t = ctx->get_dwr_type (ref_type);
+       set_dobjname (NTXT ("pointer+"), t->get_dobjname (ctx));
+       break;
+      }
+    case DW_TAG_reference_type:
+      {
+       Dwr_type *t = ctx->get_dwr_type (ref_type);
+       set_dobjname (NTXT ("reference+"), t->get_dobjname (ctx));
+       break;
+      }
+    case DW_TAG_array_type:
+      {
+       Dwr_type *t = ctx->get_dwr_type (ref_type);
+       if (elems > 0)
+         dobj_name = dbe_sprintf ("array[%lld]:%s",
+                                  (long long) elems, t->get_dobjname (ctx));
+       else
+         dobj_name = dbe_sprintf ("array[]:%s", t->get_dobjname (ctx));
+       break;
+      }
+    case DW_TAG_structure_type:
+      set_dobjname (NTXT ("structure:"), name);
+      break;
+    case DW_TAG_union_type:
+      set_dobjname (NTXT ("union:"), name);
+      break;
+    case DW_TAG_class_type:
+      set_dobjname (NTXT ("class:"), name);
+      break;
+    case DW_TAG_member:
+      {
+       Dwr_type *t = ctx->get_dwr_type (ref_type);
+       if (bit_size > 0)
+         dobj_name = dbe_sprintf (NTXT ("%s:%lld"), t->get_dobjname (ctx),
+                                  (long long) bit_size);
+       else
+         dobj_name = dbe_sprintf (NTXT ("%s"), t->get_dobjname (ctx));
+       break;
+      }
+    default:
+      Dprintf (DUMP_DWARFLIB, NTXT ("DWARF_ERROR: %s:%d No case for %s cu_die_offset=%lld\n"),
+              get_basename (__FILE__), (int) __LINE__,
+              DwrCU::tag2str (tag), (long long) cu_die_offset);
+      set_dobjname (NTXT ("Undefined:"), NULL);
+      break;
+    }
+  return dobj_name;
+}
+
+datatype_t*
+Dwr_type::get_datatype (Dwarf_cnt *ctx)
+{
+  if (dtype)
+    return dtype;
+  dtype = new datatype_t;
+  dtype->datatype_id = (unsigned) cu_die_offset;
+  dtype->memop_refs = 0;
+  dtype->event_data = 0;
+  dtype->dobj = NULL;
+  ctx->module->datatypes->incorporate (dtype, datatypeCmp);
+  return dtype;
+}
+
+DataObject *
+Dwr_type::get_dobj (Dwarf_cnt *ctx)
+{
+  if (dtype == NULL)
+    dtype = get_datatype (ctx);
+  dtype->memop_refs++;
+  DataObject *dobj = dtype->dobj;
+  if (dobj)
+    return dobj;
+
+  if (tag == 0)
+    dobj = dbeSession->find_dobj_by_name (PTXT (DOBJ_UNSPECIFIED));
+  else
+    {
+      dobj = dbeSession->createDataObject ();
+      dobj->size = size;
+      dobj->offset = offset;
+      dobj->scope = ctx->func ? (Histable*) ctx->func : (Histable*) ctx->module;
+    }
+  dtype->dobj = dobj;
+  if (parent)
+    {
+      Dwr_type *t = ctx->get_dwr_type (parent);
+      dobj->parent = t->get_dobj (ctx);
+    }
+
+  if (ref_type)
+    {
+      Dwr_type *t = ctx->get_dwr_type (ref_type);
+      t->get_dobj (ctx);
+      if (size == 0)
+       {
+         size = t->size;
+         dobj->size = size;
+       }
+    }
+
+  switch (tag)
+    {
+    case 0:
+      break;
+    case DW_TAG_array_type:
+    case DW_TAG_base_type:
+    case DW_TAG_unspecified_type:
+    case DW_TAG_enumeration_type:
+    case DW_TAG_typedef:
+    case DW_TAG_const_type:
+    case DW_TAG_volatile_type:
+    case DW_TAG_pointer_type:
+    case DW_TAG_reference_type:
+      dobj->set_dobjname (get_dobjname (ctx), NULL);
+      break;
+    case DW_TAG_structure_type:
+    case DW_TAG_union_type:
+    case DW_TAG_class_type:
+      dobj->set_dobjname (get_dobjname (ctx), NULL);
+      dobj->master = dbeSession->find_dobj_by_name (dobj_name);
+      get_dobj_for_members (ctx);
+      break;
+    case DW_TAG_constant:
+    case DW_TAG_formal_parameter:
+    case DW_TAG_member:
+    case DW_TAG_variable:
+      if (dobj->parent == NULL)
+       dobj->parent = dbeSession->get_Scalars_DataObject ();
+      dobj->set_dobjname (get_dobjname (ctx), name);
+      break;
+    default:
+      Dprintf (DUMP_DWARFLIB, NTXT ("DWARF_ERROR: %s:%d No case for %s cu_die_offset=%lld\n"),
+              get_basename (__FILE__), (int) __LINE__,
+              DwrCU::tag2str (tag), (long long) cu_die_offset);
+      break;
+    }
+  return dobj;
+}
+
+void
+Dwr_type::get_dobj_for_members (Dwarf_cnt *ctx)
+{
+  for (int64_t i = child; i != 0;)
+    {
+      Dwr_type *t = ctx->get_dwr_type (i);
+      t->get_dobj (ctx);
+      i = t->next;
+    }
+}
+
+//////////////////////////////////////////////////////////
+//  class Dwarf
+Dwarf::Dwarf (Stabs *_stabs)
+{
+  stabs = _stabs;
+  status = Stabs::DBGD_ERR_NONE;
+  dwrCUs = 0;
+  debug_infoSec = NULL;
+  debug_abbrevSec = NULL;
+  debug_strSec = NULL;
+  debug_lineSec = NULL;
+  debug_rangesSec = NULL;
+  elf = stabs->openElf (true);
+  if (elf == NULL)
+    {
+      status = Stabs::DBGD_ERR_BAD_ELF_FORMAT;
+      return;
+    }
+  debug_infoSec = dwrGetSec (NTXT (".debug_info"));
+  if (debug_infoSec)
+    {
+      debug_infoSec->reloc = ElfReloc::get_elf_reloc (elf, NTXT (".rela.debug_info"), NULL);
+      debug_infoSec->reloc = ElfReloc::get_elf_reloc (elf, NTXT (".rel.debug_info"), debug_infoSec->reloc);
+      if (debug_infoSec->reloc)
+       debug_infoSec->reloc->dump ();
+    }
+  debug_abbrevSec = dwrGetSec (NTXT (".debug_abbrev"));
+  debug_strSec = dwrGetSec (NTXT (".debug_str"));
+  debug_lineSec = dwrGetSec (NTXT (".debug_line"));
+  debug_rangesSec = dwrGetSec (NTXT (".debug_ranges"));
+
+  if ((debug_infoSec == NULL) || (debug_abbrevSec == NULL) || (debug_lineSec == NULL))
+    {
+      status = Stabs::DBGD_ERR_NO_DWARF;
+      return;
+    }
+}
+
+Dwarf::~Dwarf ()
+{
+  delete debug_infoSec;
+  delete debug_abbrevSec;
+  delete debug_strSec;
+  delete debug_lineSec;
+  delete debug_rangesSec;
+  Destroy (dwrCUs);
+}
+
+DwrSec *
+Dwarf::dwrGetSec (const char *sec_name)
+{
+  int secN = elf->elf_get_sec_num (sec_name);
+  if (secN > 0)
+    {
+      Elf_Data *elfData = elf->elf_getdata (secN);
+      if (elfData)
+       return new DwrSec ((unsigned char *) elfData->d_buf, elfData->d_size,
+                          elf->need_swap_endian,
+                          elf->elf_getclass () == ELFCLASS32);
+    }
+  return NULL;
+}
+
+uint64_t
+DwrCU::get_low_pc ()
+{
+  uint64_t pc = Dwarf_addr (DW_AT_low_pc);
+  if (pc)
+    return pc;
+  return pc;
+}
+
+char *
+DwrCU::get_linkage_name ()
+{
+  char *nm = Dwarf_string (DW_AT_linkage_name);
+  if (nm != NULL)
+    return nm;
+  nm = Dwarf_string (DW_AT_SUN_link_name);
+  if (nm != NULL)
+    return nm;
+  return Dwarf_string (DW_AT_MIPS_linkage_name);
+}
+
+void
+DwrCU::parseChild (Dwarf_cnt *ctx)
+{
+  if (!dwrTag.hasChild)
+    return;
+  uint64_t old_size = debug_infoSec->size;
+  uint64_t next_die_offset = 0;
+  Dwarf_Die next_die;
+  if (read_ref_attr (DW_AT_sibling, &next_die) == DW_DLV_OK)
+    {
+      next_die_offset = next_die + cu_offset;
+      if (next_die_offset <= debug_infoSec->offset)
+       {
+         Dprintf (DEBUG_ERR_MSG, NTXT ("DwrCU::parseChild: next_die(0x%llx) <= debug_infoSec->offset(%llx)\n"),
+                  (long long) next_die, (long long) debug_infoSec->offset);
+         next_die_offset = 0;
+       }
+      else if (debug_infoSec->size > next_die_offset)
+       debug_infoSec->size = next_die_offset;
+    }
+  dwrTag.level++;
+  ctx->level++;
+  for (;;)
+    {
+      if (set_die (0) != DW_DLV_OK)
+       break;
+      Function *func;
+      char *old_name;
+      int hasChild = dwrTag.hasChild;
+      switch (dwrTag.tag)
+       {
+       case DW_TAG_imported_declaration:
+         if (Stabs::is_fortran (ctx->module->lang_code))
+           {
+             char *link_name = Dwarf_string (DW_AT_name);
+             ctx->fortranMAIN = NULL;
+             parseChild (ctx);
+             hasChild = 0;
+             if (ctx->fortranMAIN)
+               {
+                 ctx->fortranMAIN->set_match_name (link_name);
+                 ctx->fortranMAIN = NULL;
+               }
+           }
+         break;
+       case DW_TAG_subprogram:
+         if (dwrTag.get_attr (DW_AT_abstract_origin))
+           break;
+         if (dwrTag.get_attr (DW_AT_declaration))
+           {
+             // Only declaration
+             if (Stabs::is_fortran (ctx->module->lang_code))
+               {
+                 char *link_name = Dwarf_string (DW_AT_name);
+                 if (link_name && streq (link_name, NTXT ("MAIN")))
+                   ctx->fortranMAIN = Stabs::find_func (NTXT ("MAIN"), ctx->module->functions, true, true);
+               }
+             if (get_linkage_name () == NULL)
+               break;
+           }
+         func = append_Function (ctx);
+         if (func)
+           {
+             if (Stabs::is_fortran (ctx->module->lang_code) &&
+                 streq (func->get_match_name (), NTXT ("MAIN")))
+               ctx->fortranMAIN = func;
+             old_name = ctx->name;
+             Function *old_func = ctx->func;
+             ctx->name = func->get_match_name ();
+             ctx->func = func;
+             parseChild (ctx);
+             hasChild = 0;
+             ctx->name = old_name;
+             ctx->func = old_func;
+           }
+         break;
+       case DW_TAG_module:
+         old_name = ctx->name;
+         ctx->name = Dwarf_string (DW_AT_SUN_link_name);
+         parseChild (ctx);
+         hasChild = 0;
+         ctx->name = old_name;
+         break;
+       case DW_TAG_class_type:
+         old_name = ctx->name;
+         ctx->name = Dwarf_string (DW_AT_name);
+         parseChild (ctx);
+         hasChild = 0;
+         ctx->name = old_name;
+         break;
+       case DW_TAG_structure_type:
+         old_name = ctx->name;
+         ctx->name = NULL;
+         parseChild (ctx);
+         hasChild = 0;
+         ctx->name = old_name;
+         break;
+       case DW_TAG_namespace:
+         old_name = ctx->name;
+         ctx->name = Dwarf_string (DW_AT_name);
+         parseChild (ctx);
+         hasChild = 0;
+         ctx->name = old_name;
+         break;
+       case DW_TAG_lexical_block:
+         old_name = ctx->name;
+         ctx->name = NULL;
+         parseChild (ctx);
+         hasChild = 0;
+         ctx->name = old_name;
+         break;
+       case DW_TAG_SUN_memop_info:
+         isMemop = true;
+         break;
+       case DW_TAG_inlined_subroutine:
+         if (ctx->module)
+           {
+             parse_inlined_subroutine (ctx);
+             hasChild = 0;
+           }
+         break;
+       default: // No more special cases
+         break;
+       }
+      if (hasChild)
+       parseChild (ctx);
+    }
+  ctx->level--;
+  dwrTag.level--;
+  if (next_die_offset != 0)
+    debug_infoSec->offset = next_die_offset;
+  debug_infoSec->size = old_size;
+}
+
+bool
+Dwarf::archive_Dwarf (LoadObject *lo)
+{
+  if (debug_infoSec == NULL)
+    return false;
+  if (dwrCUs)
+    return true;
+  dwrCUs = new Vector<DwrCU *>;
+
+  debug_infoSec->offset = 0;
+  while (debug_infoSec->offset < debug_infoSec->sizeSec)
+    {
+      DwrCU *dwrCU = new DwrCU (this);
+      dwrCUs->append (dwrCU);
+      debug_infoSec->size = debug_infoSec->sizeSec;
+      debug_infoSec->offset = dwrCU->next_cu_offset;
+
+      if (dwrCU->set_die (dwrCU->cu_header_offset) != DW_DLV_OK)
+       {
+         Dprintf (1, "DwrCU::archive_Dwarf: CU=%lld  (offset=0x%llx); set_die(0x%llx) failed\n",
+                  (long long) dwrCUs->size (), (long long) dwrCU->cu_offset,
+                  (long long) dwrCU->cu_header_offset);
+         continue;
+       }
+
+      Module *mod = dwrCU->parse_cu_header (lo);
+      if (mod)
+       {
+         mod->hdrOffset = dwrCUs->size ();
+         DwrLineRegs *lineReg = dwrCU->get_dwrLineReg ();
+         dwrCU->srcFiles = new Vector<SourceFile *> (VecSize (lineReg->file_names));
+         for (long i = 0, sz = VecSize (lineReg->file_names); i < sz; i++)
+           {
+             char *fname = lineReg->getPath (i + 1);
+             SourceFile *sf = mod->findSource (fname, true);
+             dwrCU->srcFiles->append (sf);
+           }
+
+         Dwarf_cnt ctx;
+         ctx.module = mod;
+         dwrCU->parseChild (&ctx);
+         if (dwrCU->dwrInlinedSubrs && DUMP_DWARFLIB)
+           {
+             char msg[128];
+             char *lo_name = mod->loadobject ? mod->loadobject->get_name ()
+                     : NULL;
+             snprintf (msg, sizeof (msg), NTXT ("\ndwrCUs[%lld]: %s:%s\n"),
+                       (long long) dwrCUs->size (),
+                       STR (lo_name), STR (mod->get_name ()));
+             dwrCU->dwrInlinedSubrs->dump (msg);
+           }
+       }
+    }
+  return true;
+}
+
+void
+Dwarf::srcline_Dwarf (Module *module)
+{
+  if (module == NULL || module->hdrOffset == 0)
+    return;
+  DwrCU *dwrCU = dwrCUs->get (module->hdrOffset - 1);
+  dwrCU->map_dwarf_lines (module);
+}
+
+
+// parse hwcprof info for given module in loadobject
+
+void
+Dwarf::read_hwcprof_info (Module *module)
+{
+  if (module->datatypes || (module->hdrOffset == 0))
+    return;
+  DwrCU *dwrCU = dwrCUs->get (module->hdrOffset - 1);
+  if (!dwrCU->isMemop)
+    return;
+  module->datatypes = new Vector<datatype_t*>;
+  if (dwrCU->set_die (dwrCU->cu_header_offset) != DW_DLV_OK)
+    {
+      Dprintf (1, "Dwarf::read_hwcprof_info: CU=%lld  (offset=0x%llx); set_die(0x%llx) failed\n",
+              (long long) module->hdrOffset, (long long) dwrCU->cu_offset,
+              (long long) dwrCU->cu_header_offset);
+      return;
+    }
+  Dwarf_cnt ctx;
+  ctx.module = module;
+  ctx.cu_offset = dwrCU->cu_offset; // CU header offset;
+  ctx.dwr_types = new DefaultMap<int64_t, Dwr_type*>;
+  ctx.put_dwr_type (0, 0); // for DOBJ_UNSPECIFIED
+  dwrCU->read_hwcprof_info (&ctx);
+
+  Vector<inst_info_t*> *infoList = module->infoList;
+  Dprintf (DUMP_DWARFLIB,
+     "\n\n ### Dwarf::read_hwcprof_info: module: '%s'  infoList->size()=%lld\n",
+     STR (module->get_name ()),
+     (long long) (infoList ? infoList->size () : -1));
+  for (int i = 0, sz = infoList ? infoList->size () : -1; i < sz; i++)
+    {
+      inst_info_t *ip = infoList->fetch (i);
+      memop_info_t *mp = ip->memop;
+      Dwr_type *t = ctx.get_dwr_type (mp->datatype_id);
+      t->get_dobj (&ctx);
+    }
+
+#ifdef DEBUG
+  Dprintf (DUMP_DWARFLIB,
+          "\n\n ### Dwarf::read_hwcprof_info: '%s'  infoList->size()=%lld\n",
+          STR (module->get_name ()),
+          (long long) (infoList ? infoList->size () : 1));
+  for (int i = 0, sz = infoList ? infoList->size () : -1; i < sz; i++)
+    {
+      inst_info_t *ip = infoList->fetch (i);
+      memop_info_t *mp = ip->memop;
+      Dprintf (DUMP_DWARFLIB,
+              "  %d id=%lld  offset=%lld  signature=%lld  datatype_id=%lld \n",
+              i, (long long) mp->id, (long long) mp->offset,
+              (long long) mp->signature, (long long) mp->datatype_id);
+    }
+
+  Vector<int64_t> *keys = ctx.dwr_types->keySet ();
+  Dprintf (DUMP_DWARFLIB,
+          "\n\n ### Dwarf::read_hwcprof_info: '%s'  keys->size()=%lld\n",
+          STR (module->get_name ()), (long long) (keys ? keys->size () : -1));
+  for (int i = 0, sz = keys->size (); i < sz; i++)
+    {
+      int64_t ind = keys->fetch (i);
+      Dwr_type *t = ctx.get_dwr_type (ind);
+      Dprintf (DUMP_DWARFLIB, NTXT ("  %d %lld %s\n"), i,
+              (long long) ind, t->dump ());
+    }
+#endif
+}
+
+void
+DwrCU::read_hwcprof_info (Dwarf_cnt *ctx)
+{
+  if (!dwrTag.hasChild)
+    return;
+  uint64_t old_size = debug_infoSec->size;
+  uint64_t next_die_offset = 0;
+  Dwarf_Die next_die;
+  if (read_ref_attr (DW_AT_sibling, &next_die) == DW_DLV_OK)
+    {
+      next_die_offset = next_die + cu_offset;
+      if (next_die_offset <= debug_infoSec->offset)
+       next_die_offset = 0;
+      else if (debug_infoSec->size > next_die_offset)
+       debug_infoSec->size = next_die_offset;
+    }
+  dwrTag.level++;
+  ctx->level++;
+  for (;;)
+    {
+      if (set_die (0) != DW_DLV_OK)
+       break;
+      Dprintf (DUMP_DWARFLIB, NTXT ("%s:%d <%lld:%lld> cu_die=%lld %-15s\n"),
+              get_basename (__FILE__), (int) __LINE__, (long long) ctx->level,
+              (long long) dwrTag.die, (long long) dwrTag.offset,
+              DwrCU::tag2str (dwrTag.tag));
+      switch (dwrTag.tag)
+       {
+       case DW_TAG_SUN_memop_info:
+         {
+           if (ctx->func == NULL)
+             break;
+           Dwarf_Unsigned mid = Dwarf_data (DW_AT_SUN_profile_id);
+           Dwarf_Unsigned off = Dwarf_data (DW_AT_SUN_func_offset);
+           Dwarf_Unsigned sig = Dwarf_data (DW_AT_SUN_memop_signature);
+           Dwarf_Off ref = Dwarf_ref (DW_AT_SUN_memop_type_ref);
+
+           // define memop entry
+           memop_info_t *memop = new memop_info_t;
+           memop->id = (unsigned) mid;
+           memop->signature = (unsigned) sig;
+           memop->datatype_id = ref ? (unsigned) ref : 0;
+           memop->offset = (unsigned) (ctx->func->img_offset + off);
+
+           // define instop entry
+           inst_info_t *instop = new inst_info_t;
+           instop->type = CPF_INSTR_TYPE_PREFETCH; // XXXX UNKNOWN
+           instop->offset = memop->offset;
+           instop->memop = memop;
+           if (ctx->module->infoList == NULL)
+             ctx->module->infoList = new Vector<inst_info_t*>;
+           ctx->module->infoList->append (instop);
+           break;
+         }
+       case DW_TAG_SUN_codeflags:
+         {
+           if (ctx->func == NULL)
+             break;
+           Dwarf_Unsigned kind = Dwarf_data (DW_AT_SUN_cf_kind);
+           if (kind == DW_ATCF_SUN_branch_target)
+             {
+               DwrSec *secp = Dwarf_block (DW_AT_SUN_func_offsets);
+               if (secp)
+                 {
+                   int foffset = 0;
+                   for (int i = 0; secp->offset < secp->size; i++)
+                     {
+                       int val = (int) secp->GetSLEB128 ();
+                       if (i == 0 || val != 0)
+                         {
+                           foffset += val;
+                           target_info_t *t = new target_info_t;
+                           t->offset = (unsigned) (ctx->func->img_offset + foffset);
+                           ctx->module->bTargets.incorporate (t, targetOffsetCmp);
+                         }
+                     }
+                   delete(secp);
+                 }
+             }
+           break;
+         }
+       case DW_TAG_subprogram:
+         {
+           Function *old_func = ctx->func;
+           if (dwrTag.get_attr (DW_AT_abstract_origin)
+                                || dwrTag.get_attr (DW_AT_declaration))
+             ctx->func = NULL;
+           else
+             ctx->func = append_Function (ctx);
+           read_hwcprof_info (ctx);
+           ctx->func = old_func;
+           break;
+         }
+       case DW_TAG_base_type:
+         {
+           Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+           t->name = Dwarf_string (DW_AT_name);
+           t->size = Dwarf_data (DW_AT_byte_size);
+           break;
+         }
+       case DW_TAG_unspecified_type:
+         ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+         break;
+       case DW_TAG_enumeration_type:
+         {
+           Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+           t->name = Dwarf_string (DW_AT_name);
+           t->size = Dwarf_data (DW_AT_byte_size);
+           break;
+         }
+       case DW_TAG_constant:
+       case DW_TAG_formal_parameter:
+       case DW_TAG_variable:
+       case DW_TAG_typedef:
+       case DW_TAG_const_type:
+       case DW_TAG_volatile_type:
+         {
+           Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+           t->name = Dwarf_string (DW_AT_name);
+           t->ref_type = Dwarf_ref (DW_AT_type);
+           break;
+         }
+       case DW_TAG_pointer_type:
+       case DW_TAG_reference_type:
+         {
+           Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+           t->name = Dwarf_string (DW_AT_name);
+           t->ref_type = Dwarf_ref (DW_AT_type);
+           t->size = (dwarf->stabs->get_class () == W64) ? 8 : 4;
+           break;
+         }
+       case DW_TAG_array_type:
+         {
+           Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+           t->name = Dwarf_string (DW_AT_name);
+           t->ref_type = Dwarf_ref (DW_AT_type);
+           t->size = Dwarf_data (DW_AT_byte_size);
+           ctx->size = -1;
+           read_hwcprof_info (ctx);
+           t->elems = ctx->size;
+           break;
+         }
+       case DW_TAG_subrange_type:
+         {
+           int64_t ref_type = Dwarf_ref (DW_AT_type);
+           int64_t hi = Dwarf_data (DW_AT_upper_bound);
+           int64_t lo = Dwarf_data (DW_AT_lower_bound);
+           int64_t ss = Dwarf_data (DW_AT_stride_size);
+           ctx->size = 1 + hi - lo;
+           if (ss != 0)
+             ctx->size /= ss;
+           Dprintf (DUMP_DWARFLIB,
+                   "Got subrange [%lld:%lld:%lld] indexed <%lld>: size=%lld\n",
+                    (long long) lo, (long long) hi, (long long) ss,
+                    (long long) ref_type, (long long) ctx->size);
+           break;
+         }
+       case DW_TAG_structure_type:
+       case DW_TAG_union_type:
+       case DW_TAG_class_type:
+         {
+           Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+           t->name = Dwarf_string (DW_AT_name);
+           t->size = Dwarf_data (DW_AT_byte_size);
+           t->extent = Dwarf_ref (DW_AT_sibling);
+           int64_t old_parent = ctx->parent;
+           ctx->parent = t->cu_die_offset;
+
+           char *old_name = ctx->name;
+           ctx->name = (dwrTag.tag == DW_TAG_class_type) ? Dwarf_string (DW_AT_name) : NULL;
+           read_hwcprof_info (ctx);
+           ctx->name = old_name;
+           ctx->parent = old_parent;
+           // Reverse children
+           for (int64_t i = t->child, last = 0; i != 0;)
+             {
+               Dwr_type *t1 = ctx->get_dwr_type (i);
+               t->child = i;
+               i = t1->next;
+               t1->next = last;
+               last = t->child;
+             }
+           break;
+         }
+       case DW_TAG_member:
+         {
+           if (ctx->parent == 0)
+             {
+               Dprintf (DUMP_DWARFLIB, NTXT ("DWARF_ERROR: %s:%d %s cu_die_offset=%lld\n"),
+                        get_basename (__FILE__), (int) __LINE__,
+                        DwrCU::tag2str (dwrTag.tag), (long long) dwrTag.die);
+               break;
+             }
+           Dwr_type *t = ctx->put_dwr_type (dwrTag.die, dwrTag.tag);
+           t->name = Dwarf_string (DW_AT_name);
+           t->ref_type = Dwarf_ref (DW_AT_type);
+           t->offset = Dwarf_location (DW_AT_data_member_location);
+           Dwr_type *parent = ctx->get_dwr_type (ctx->parent);
+           t->parent = ctx->parent;
+           t->next = parent->child; // a reverse order of members
+           parent->child = t->cu_die_offset;
+           t->bit_size = (uint32_t) Dwarf_data (DW_AT_bit_size);
+           break;
+         }
+       case DW_TAG_module:
+         {
+           char *old_name = ctx->name;
+           ctx->name = Dwarf_string (DW_AT_SUN_link_name);
+           read_hwcprof_info (ctx);
+           ctx->name = old_name;
+           break;
+         }
+       case DW_TAG_namespace:
+         {
+           char *old_name = ctx->name;
+           ctx->name = Dwarf_string (DW_AT_name);
+           read_hwcprof_info (ctx);
+           ctx->name = old_name;
+           break;
+         }
+       case DW_TAG_lexical_block:
+         {
+           char *old_name = ctx->name;
+           ctx->name = NULL;
+           read_hwcprof_info (ctx);
+           ctx->name = old_name;
+           break;
+         }
+       default: // No more special cases
+         read_hwcprof_info (ctx);
+         break;
+       }
+    }
+  ctx->level--;
+  dwrTag.level--;
+  if (next_die_offset != 0)
+    debug_infoSec->offset = next_die_offset;
+  debug_infoSec->size = old_size;
+}
+
+// Append function to module
+Function *
+DwrCU::append_Function (Dwarf_cnt *ctx)
+{
+  char *outerName = ctx->name, *name, tmpname[2048];
+  Function *func;
+  char *fname = Dwarf_string (DW_AT_name);
+  if (fname && outerName && !strchr (fname, '.'))
+    {
+      size_t outerlen = strlen (outerName);
+      if (outerlen > 0 && outerName[outerlen - 1] == '_')
+       {
+         outerlen--;
+         snprintf (tmpname, sizeof (tmpname), NTXT ("%s"), outerName);
+         snprintf (tmpname + outerlen, sizeof (tmpname) - outerlen, NTXT (".%s_"), fname);
+       }
+      else
+       snprintf (tmpname, sizeof (tmpname), NTXT ("%s.%s"), outerName, fname);
+      name = tmpname;
+      Dprintf (DUMP_DWARFLIB, NTXT ("Generated innerfunc name %s\n"), name);
+    }
+  else
+    name = fname;
+
+  char *link_name = get_linkage_name ();
+  if (link_name == NULL)
+    link_name = name;
+
+  uint64_t pc = get_low_pc ();
+  func = dwarf->stabs->append_Function (module, link_name, pc);
+  if (func != NULL)
+    {
+      int lineno = (int) Dwarf_data (DW_AT_decl_line);
+      func->set_match_name (name);
+      if (lineno > 0)
+       {
+         func->setLineFirst (lineno);
+         if (dwrLineReg == NULL)
+           dwrLineReg = new DwrLineRegs (new DwrSec (dwarf->debug_lineSec,
+                                                  stmt_list_offset), comp_dir);
+         int fileno = ((int) Dwarf_data (DW_AT_decl_file)) - 1;
+         SourceFile *sf = ((fileno >= 0) && (fileno < VecSize (srcFiles))) ? srcFiles->get (fileno)
+                 : module->getMainSrc ();
+         func->setDefSrc (sf);
+         func->pushSrcFile (func->def_source, 0);
+         func->popSrcFile ();
+       }
+    }
+  return func;
+}
+
+// Get language code
+Sp_lang_code
+DwrCU::Dwarf_lang ()
+{
+  char *str = Dwarf_string (DW_AT_producer);
+  if (str && strncmp (str, NTXT ("GNU"), 3) == 0)
+    isGNU = true;
+  int64_t lang = Dwarf_data (DW_AT_language);
+  switch (lang)
+    {
+    case DW_LANG_C89:
+    case DW_LANG_C:
+      return Sp_lang_c; // Sp_lang_ansic?
+    case DW_LANG_C99:
+      return Sp_lang_c99;
+    case DW_LANG_C_plus_plus:
+      return isGNU ? Sp_lang_gcc : Sp_lang_cplusplus;
+    case DW_LANG_Fortran90:
+      return Sp_lang_fortran90;
+    case DW_LANG_Fortran77:
+      return Sp_lang_fortran;
+    case DW_LANG_Java:
+      return Sp_lang_java;
+    case DW_LANG_Mips_Assembler:
+    case DW_LANG_SUN_Assembler:
+      return Sp_lang_asm;
+    case DW_LANG_Pascal83:
+      return Sp_lang_pascal;
+    default:
+    case DW_LANG_Ada83:
+    case DW_LANG_Cobol74:
+    case DW_LANG_Cobol85:
+    case DW_LANG_Modula2:
+    case DW_LANG_Ada95:
+    case DW_LANG_Fortran95:
+    case DW_LANG_lo_user:
+      return Sp_lang_unknown;
+    }
+}
diff --git a/gprofng/src/Dwarf.h b/gprofng/src/Dwarf.h
new file mode 100644 (file)
index 0000000..12ffbc0
--- /dev/null
@@ -0,0 +1,87 @@
+/* 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 _Dwarf_h_
+#define _Dwarf_h_ 1
+
+#include "dwarf2.h"
+
+#include "Stabs.h"
+#include "dbe_structs.h"
+#include "DwarfLib.h"
+
+enum
+{
+  /* ICC extensions */
+  DW_AT_icc_flags           = 0x3b01,
+  DW_TAG_icc_compile_unit   = 0x7000,
+
+  /* Sun extensions */
+  DW_ATCF_SUN_branch_target = 0x46,
+  DW_AT_SUN_command_line    = 0x2205,
+  DW_AT_SUN_func_offsets    = 0x2211,
+  DW_AT_SUN_cf_kind         = 0x2212,
+  DW_AT_SUN_func_offset     = 0x2216,
+  DW_AT_SUN_memop_type_ref  = 0x2217,
+  DW_AT_SUN_profile_id      = 0x2218,
+  DW_AT_SUN_memop_signature = 0x2219,
+  DW_AT_SUN_obj_dir         = 0x2220,
+  DW_AT_SUN_obj_file        = 0x2221,
+  DW_AT_SUN_original_name   = 0x2222,
+  DW_AT_SUN_link_name       = 0x2226,
+
+  DW_TAG_SUN_codeflags      = 0x4206,
+  DW_TAG_SUN_memop_info     = 0x4207,
+  DW_TAG_SUN_dtor_info      = 0x420a,
+  DW_TAG_SUN_dtor           = 0x420b,
+
+  DW_LANG_SUN_Assembler     = 0x9001
+};
+
+
+class LoadObject;
+class Module;
+class DwrCU;
+class DwrSec;
+
+class Dwarf
+{
+public:
+  Dwarf (Stabs *_stabs);
+  ~Dwarf ();
+  bool archive_Dwarf (LoadObject *lo);
+  void srcline_Dwarf (Module *module);
+  void read_hwcprof_info (Module *module);
+
+  Stabs::Stab_status status;
+  Vector<DwrCU *> *dwrCUs;
+  DwrSec *debug_infoSec;
+  DwrSec *debug_abbrevSec;
+  DwrSec *debug_strSec;
+  DwrSec *debug_lineSec;
+  DwrSec *debug_rangesSec;
+  Elf *elf;
+  Stabs *stabs;
+
+private:
+  DwrSec *dwrGetSec (const char *sec_name);
+};
+
+#endif  /* _Dwarf_h_ */
diff --git a/gprofng/src/DwarfLib.cc b/gprofng/src/DwarfLib.cc
new file mode 100644 (file)
index 0000000..c8af0ab
--- /dev/null
@@ -0,0 +1,2203 @@
+/* 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 <ctype.h>
+
+#include "util.h"
+#include "Dwarf.h"
+#include "DwarfLib.h"
+#include "Elf.h"
+#include "Function.h"
+#include "Module.h"
+#include "StringBuilder.h"
+#include "DbeArray.h"
+#include "DbeSession.h"
+
+#define CASE_S(x)   case x: s = (char *) #x; break
+
+static char *
+gelf_st_type2str (int type)
+{
+  static char buf[128];
+  char *s;
+  switch (type)
+    {
+      CASE_S (STT_NOTYPE);
+      CASE_S (STT_OBJECT);
+      CASE_S (STT_FUNC);
+      CASE_S (STT_SECTION);
+      CASE_S (STT_FILE);
+      CASE_S (STT_COMMON);
+      CASE_S (STT_TLS);
+      //    CASE_S(STT_NUM);
+      CASE_S (STT_LOPROC);
+      CASE_S (STT_HIPROC);
+    default: s = NTXT ("???");
+      break;
+    }
+  snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, type);
+  buf[sizeof (buf) - 1] = 0;
+  return buf;
+}
+
+static char *
+special_opcode2str (int opcode)
+{
+  static char buf[128];
+  snprintf (buf, sizeof (buf), NTXT ("SpecialOpcode: %3d"), opcode);
+  buf[sizeof (buf) - 1] = 0;
+  return buf;
+}
+
+static char *
+extended_opcode2str (int opcode)
+{
+  static char buf[128];
+  char *s;
+  switch (opcode)
+    {
+      CASE_S (DW_LNE_end_sequence);
+      CASE_S (DW_LNE_set_address);
+      CASE_S (DW_LNE_define_file);
+    default:
+      snprintf (buf, sizeof (buf), NTXT ("??? (%d)"), opcode);
+      buf[sizeof (buf) - 1] = 0;
+      s = buf;
+      break;
+    }
+  return s;
+}
+
+static char *
+standard_opcode2str (int opcode)
+{
+  static char buf[128];
+  char *s;
+  switch (opcode)
+    {
+      CASE_S (DW_LNS_copy);
+      CASE_S (DW_LNS_advance_pc);
+      CASE_S (DW_LNS_advance_line);
+      CASE_S (DW_LNS_set_file);
+      CASE_S (DW_LNS_set_column);
+      CASE_S (DW_LNS_negate_stmt);
+      CASE_S (DW_LNS_set_basic_block);
+      CASE_S (DW_LNS_const_add_pc);
+      CASE_S (DW_LNS_fixed_advance_pc);
+    default:
+      snprintf (buf, sizeof (buf), NTXT ("??? (%d)"), opcode);
+      buf[sizeof (buf) - 1] = 0;
+      s = buf;
+      break;
+    }
+  return s;
+}
+
+template<> void Vector<DwrInlinedSubr *>
+::dump (const char *msg)
+{
+  Dprintf (1, NTXT ("%s Vector<DwrInlinedSubr *> [%lld]\n"),
+          msg ? msg : NTXT (""), (long long) size ());
+  for (long i = 0, sz = size (); i < sz; i++)
+    {
+      DwrInlinedSubr *p = get (i);
+      Dprintf (1, NTXT ("%ld: "), (long) i);
+      p->dump ();
+    }
+}
+
+template<> void Vector<DwrLine *>
+::dump (const char *msg)
+{
+  Dprintf (1, "%s Vector<DwrLine *> [%lld]:\n    address [file line column]\n",
+          msg ? msg : NTXT (""), (long long) size ());
+  for (long i = 0, sz = size (); i < sz; i++)
+    {
+      DwrLine *lnp = get (i);
+      Dprintf (1, NTXT (" %2lld 0x%08llx  [ %2lld, %lld, %lld ] \n"),
+              (long long) i, (long long) lnp->address, (long long) lnp->file,
+              (long long) lnp->line, (long long) lnp->column);
+    }
+  Dprintf (1, NTXT ("\n\n"));
+}
+
+//////////////////////////////////////////////////////////
+//  class ElfReloc
+
+ElfReloc::ElfReloc (Elf *_elf)
+{
+  elf = _elf;
+  reloc = NULL;
+  cur_reloc_ind = 0;
+}
+
+ElfReloc::~ElfReloc ()
+{
+  if (reloc)
+    {
+      reloc->destroy ();
+      delete reloc;
+    }
+}
+
+void
+ElfReloc::dump_rela_debug_sec (int sec)
+{
+  if (!DUMP_RELA_SEC)
+    return;
+  Elf_Internal_Shdr *shdr = elf->get_shdr (sec);
+  if (shdr == NULL)
+    return;
+
+  Elf_Data *data = elf->elf_getdata (sec);
+  if (data == NULL)
+    return;
+
+  uint64_t ScnSize = data->d_size;
+  uint64_t EntSize = shdr->sh_entsize;
+  if (ScnSize == 0 || EntSize == 0)
+    return;
+
+  Elf_Internal_Shdr *shdr_sym = elf->get_shdr (shdr->sh_link);
+  if (shdr_sym == NULL)
+    return;
+  Elf_Data *data_sym = elf->elf_getdata (shdr->sh_link);
+  Elf_Data *data_str = elf->elf_getdata (shdr_sym->sh_link);
+  char *Strtab = data_str ? (char*) data_str->d_buf : NULL;
+  Elf_Internal_Rela rela;
+  int n, cnt = (int) (ScnSize / EntSize);
+
+  char *sec_name = elf->get_sec_name (sec);
+  if (sec_name == NULL) // It can not be, but let's check
+    return;
+  Dprintf (DUMP_RELA_SEC,
+          "======= DwarfLib::dump_rela_debug_sec  Section:%2d  '%s'\n",
+          sec, sec_name);
+  Dprintf (DUMP_RELA_SEC,
+          " N |addend|   offset   |       r_info      |    stt_type   |\n");
+  for (n = 0; n < cnt; n++)
+    {
+      if (strncmp (sec_name, NTXT (".rela."), 6) == 0)
+       elf->elf_getrela (data, n, &rela);
+      else
+       {
+         elf->elf_getrel (data, n, &rela);
+         rela.r_addend = 0;
+       }
+      int ndx = (int) GELF_R_SYM (rela.r_info);
+      Elf_Internal_Shdr *secHdr;
+      Elf_Internal_Sym sym;
+      elf->elf_getsym (data_sym, ndx, &sym);
+      Dprintf (DUMP_RELA_SEC, NTXT ("%3d:%5d |%11lld |0x%016llx | %-15s|"),
+              n, (int) rela.r_addend,
+              (long long) rela.r_offset, (long long) rela.r_info,
+              gelf_st_type2str ((int) GELF_ST_TYPE (sym.st_info)));
+      switch (GELF_ST_TYPE (sym.st_info))
+       {
+       case STT_FUNC:
+       case STT_OBJECT:
+       case STT_NOTYPE:
+         secHdr = elf->get_shdr (sym.st_shndx);
+         if (secHdr)
+           Dprintf (DUMP_RELA_SEC, NTXT (" img_offset=0x%llx"),
+                    (long long) (sym.st_value + secHdr->sh_offset));
+         if (Strtab && sym.st_name)
+           Dprintf (DUMP_RELA_SEC, NTXT ("  %s"), Strtab + sym.st_name);
+         break;
+       case STT_SECTION:
+         secHdr = elf->get_shdr (sym.st_shndx);
+         if (secHdr)
+           {
+             Dprintf (DUMP_RELA_SEC, NTXT ("       value=0x%016llx (%lld)"),
+                      (long long) (secHdr->sh_offset + rela.r_addend),
+                      (long long) (secHdr->sh_offset + rela.r_addend));
+           }
+         break;
+       default:
+         break;
+       }
+      Dprintf (DUMP_RELA_SEC, NTXT ("\n"));
+    }
+  Dprintf (DUMP_RELA_SEC, NTXT ("\n"));
+}
+
+void
+ElfReloc::dump ()
+{
+  if (!DUMP_ELF_RELOC || (reloc == NULL) || (reloc->size () == 0))
+    return;
+  Dprintf (DUMP_ELF_RELOC, NTXT ("======= ElfReloc::dump\n"));
+  Dprintf (DUMP_ELF_RELOC, NTXT (" N |   offset   |    value   | STT_TYPE\n"));
+  for (int i = 0; i < reloc->size (); i++)
+    {
+      Sreloc *srlc = reloc->fetch (i);
+      Dprintf (DUMP_ELF_RELOC, NTXT ("%3d:%11lld |%11lld | %s\n"),
+              i, (long long) srlc->offset, (long long) srlc->value,
+              gelf_st_type2str (srlc->stt_type));
+    }
+  Dprintf (DUMP_ELF_RELOC, NTXT ("\n"));
+}
+
+static int
+DwrRelocOffsetCmp (const void *a, const void *b)
+{
+  ElfReloc::Sreloc *item1 = *((ElfReloc::Sreloc **) a);
+  ElfReloc::Sreloc *item2 = *((ElfReloc::Sreloc **) b);
+  return item1->offset < item2->offset ? -1 :
+        item1->offset == item2->offset ? 0 : 1;
+}
+
+ElfReloc *
+ElfReloc::get_elf_reloc (Elf *elfp, char *sec_name, ElfReloc *rlc)
+{
+  int et = elfp->elf_getehdr ()->e_type;
+  if (et == ET_EXEC || et == ET_DYN)
+    return rlc;
+  int sec = elfp->elf_get_sec_num (sec_name);
+  if (sec == 0)
+    return rlc;
+  Elf_Internal_Shdr *shdr = elfp->get_shdr (sec);
+  if (shdr == NULL || shdr->sh_entsize == 0)
+    return rlc;
+
+  Elf_Data *data = elfp->elf_getdata (sec);
+  if (data == NULL || data->d_size == 0)
+    return rlc;
+
+  int cnt = (int) (data->d_size / shdr->sh_entsize);
+  Elf_Internal_Shdr *shdr_sym = elfp->get_shdr (shdr->sh_link);
+  if (shdr_sym == NULL)
+    return rlc;
+  Elf_Data *data_sym = elfp->elf_getdata (shdr->sh_link);
+  Vector<Sreloc *> *vp = NULL;
+
+  for (int n = 0; n < cnt; n++)
+    {
+      Elf_Internal_Shdr *secHdr;
+      Sreloc *srlc;
+      Elf_Internal_Rela rela;
+      if (strncmp (sec_name, NTXT (".rela."), 6) == 0)
+       elfp->elf_getrela (data, n, &rela);
+      else
+       {
+         elfp->elf_getrel (data, n, &rela);
+         rela.r_addend = 0;
+       }
+      int ndx = (int) GELF_R_SYM (rela.r_info);
+      Elf_Internal_Sym sym;
+      elfp->elf_getsym (data_sym, ndx, &sym);
+
+      srlc = new Sreloc;
+      srlc->offset = rela.r_offset;
+      srlc->value = 0;
+      srlc->stt_type = (int) GELF_ST_TYPE (sym.st_info);
+      switch (GELF_ST_TYPE (sym.st_info))
+       {
+       case STT_FUNC:
+         secHdr = elfp->get_shdr (sym.st_shndx);
+         if (secHdr)
+           srlc->value = secHdr->sh_offset + sym.st_value;
+         break;
+       case STT_OBJECT:
+       case STT_NOTYPE:
+         secHdr = elfp->get_shdr (shdr->sh_info);
+         if (secHdr)
+           {
+             srlc->offset = rela.r_info;
+             srlc->value = secHdr->sh_offset + rela.r_addend;
+           }
+         break;
+       case STT_SECTION:
+         secHdr = elfp->get_shdr (sym.st_shndx);
+         if (secHdr)
+           srlc->value = rela.r_addend;
+         break;
+       default:
+         srlc->value = 0;
+         break;
+       }
+      if (rlc == NULL)
+       {
+         rlc = new ElfReloc (elfp);
+         vp = rlc->reloc;
+       }
+      if (vp == NULL)
+       {
+         vp = new Vector<Sreloc*>;
+         rlc->reloc = vp;
+       }
+      vp->append (srlc);
+    }
+  if (vp)
+    vp->sort (DwrRelocOffsetCmp);
+  if (rlc)
+    {
+      rlc->dump_rela_debug_sec (sec);
+      rlc->dump ();
+    }
+  return rlc;
+}
+
+long long
+ElfReloc::get_reloc_addr (long long offset)
+{
+  Sreloc *srlc;
+  int i = cur_reloc_ind - 1;
+  if (i >= 0 && i < reloc->size ())
+    {
+      srlc = reloc->fetch (i);
+      if (srlc->offset > offset)  // need to reset
+       cur_reloc_ind = 0;
+    }
+  for (; cur_reloc_ind < reloc->size (); cur_reloc_ind++)
+    {
+      srlc = reloc->fetch (cur_reloc_ind);
+      if (srlc->offset == offset)
+       return srlc->value;
+      if (srlc->offset > offset)
+       return 0;
+    }
+  return 0;
+}
+
+DwrLocation *
+DwrCU::dwr_get_location (DwrSec *secp, DwrLocation *lp)
+{
+  lp->offset = secp->offset;
+  lp->lc_number = 0;
+  lp->lc_number2 = 0;
+  lp->op = secp->Get_8 ();
+  switch (lp->op)
+    {
+      // registers
+    case DW_OP_reg0:
+    case DW_OP_reg1:
+    case DW_OP_reg2:
+    case DW_OP_reg3:
+    case DW_OP_reg4:
+    case DW_OP_reg5:
+    case DW_OP_reg6:
+    case DW_OP_reg7:
+    case DW_OP_reg8:
+    case DW_OP_reg9:
+    case DW_OP_reg10:
+    case DW_OP_reg11:
+    case DW_OP_reg12:
+    case DW_OP_reg13:
+    case DW_OP_reg14:
+    case DW_OP_reg15:
+    case DW_OP_reg16:
+    case DW_OP_reg17:
+    case DW_OP_reg18:
+    case DW_OP_reg19:
+    case DW_OP_reg20:
+    case DW_OP_reg21:
+    case DW_OP_reg22:
+    case DW_OP_reg23:
+    case DW_OP_reg24:
+    case DW_OP_reg25:
+    case DW_OP_reg26:
+    case DW_OP_reg27:
+    case DW_OP_reg28:
+    case DW_OP_reg29:
+    case DW_OP_reg30:
+    case DW_OP_reg31:
+      break;
+    case DW_OP_regx:
+      lp->lc_number = secp->GetULEB128 ();
+      break;
+    case DW_OP_breg0:
+    case DW_OP_breg1:
+    case DW_OP_breg2:
+    case DW_OP_breg3:
+    case DW_OP_breg4:
+    case DW_OP_breg5:
+    case DW_OP_breg6:
+    case DW_OP_breg7:
+    case DW_OP_breg8:
+    case DW_OP_breg9:
+    case DW_OP_breg10:
+    case DW_OP_breg11:
+    case DW_OP_breg12:
+    case DW_OP_breg13:
+    case DW_OP_breg14:
+    case DW_OP_breg15:
+    case DW_OP_breg16:
+    case DW_OP_breg17:
+    case DW_OP_breg18:
+    case DW_OP_breg19:
+    case DW_OP_breg20:
+    case DW_OP_breg21:
+    case DW_OP_breg22:
+    case DW_OP_breg23:
+    case DW_OP_breg24:
+    case DW_OP_breg25:
+    case DW_OP_breg26:
+    case DW_OP_breg27:
+    case DW_OP_breg28:
+    case DW_OP_breg29:
+    case DW_OP_breg30:
+    case DW_OP_breg31:
+      lp->lc_number = secp->GetSLEB128 ();
+      break;
+    case DW_OP_fbreg:
+      lp->lc_number = secp->GetSLEB128 ();
+      break;
+    case DW_OP_bregx:
+      lp->lc_number = secp->GetULEB128 ();
+      lp->lc_number2 = secp->GetSLEB128 ();
+      break;
+    case DW_OP_lit0:
+    case DW_OP_lit1:
+    case DW_OP_lit2:
+    case DW_OP_lit3:
+    case DW_OP_lit4:
+    case DW_OP_lit5:
+    case DW_OP_lit6:
+    case DW_OP_lit7:
+    case DW_OP_lit8:
+    case DW_OP_lit9:
+    case DW_OP_lit10:
+    case DW_OP_lit11:
+    case DW_OP_lit12:
+    case DW_OP_lit13:
+    case DW_OP_lit14:
+    case DW_OP_lit15:
+    case DW_OP_lit16:
+    case DW_OP_lit17:
+    case DW_OP_lit18:
+    case DW_OP_lit19:
+    case DW_OP_lit20:
+    case DW_OP_lit21:
+    case DW_OP_lit22:
+    case DW_OP_lit23:
+    case DW_OP_lit24:
+    case DW_OP_lit25:
+    case DW_OP_lit26:
+    case DW_OP_lit27:
+    case DW_OP_lit28:
+    case DW_OP_lit29:
+    case DW_OP_lit30:
+    case DW_OP_lit31:
+      lp->lc_number = lp->op - DW_OP_lit0;
+      break;
+    case DW_OP_addr:
+      lp->lc_number = secp->GetADDR ();
+      break;
+    case DW_OP_const1u:
+      lp->lc_number = secp->Get_8 ();
+      break;
+    case DW_OP_const1s:
+      {
+       signed char x;
+       x = secp->Get_8 ();
+       lp->lc_number = x;
+      }
+      break;
+    case DW_OP_const2u:
+      lp->lc_number = secp->Get_16 ();
+      break;
+    case DW_OP_const2s:
+      {
+       signed short x;
+       x = secp->Get_16 ();
+       lp->lc_number = x;
+      }
+      break;
+    case DW_OP_const4u:
+      lp->lc_number = secp->Get_32 ();
+      break;
+    case DW_OP_const4s:
+      {
+       signed int x;
+       x = secp->Get_32 ();
+       lp->lc_number = x;
+      }
+      break;
+    case DW_OP_const8u:
+      lp->lc_number = secp->Get_64 ();
+      break;
+    case DW_OP_const8s:
+      {
+       signed long long x;
+       x = secp->Get_64 ();
+       lp->lc_number = x;
+      }
+      break;
+    case DW_OP_plus_uconst:
+    case DW_OP_constu:
+      lp->lc_number = secp->GetULEB128 ();
+      break;
+    case DW_OP_consts:
+      lp->lc_number = secp->GetSLEB128 ();
+      break;
+
+      // Stack operations
+    case DW_OP_pick:
+    case DW_OP_deref_size:
+    case DW_OP_xderef_size:
+      lp->lc_number = secp->Get_8 ();
+      break;
+    case DW_OP_dup:
+    case DW_OP_drop:
+    case DW_OP_over:
+    case DW_OP_swap:
+    case DW_OP_rot:
+    case DW_OP_deref:
+    case DW_OP_xderef:
+      // Arithmetic and Logical Operations
+    case DW_OP_abs:
+    case DW_OP_and:
+    case DW_OP_div:
+    case DW_OP_minus:
+    case DW_OP_mod:
+    case DW_OP_mul:
+    case DW_OP_neg:
+    case DW_OP_not:
+    case DW_OP_or:
+    case DW_OP_plus:
+    case DW_OP_shl:
+    case DW_OP_shr:
+    case DW_OP_shra:
+    case DW_OP_xor:
+    case DW_OP_le:
+    case DW_OP_ge:
+    case DW_OP_eq:
+    case DW_OP_lt:
+    case DW_OP_gt:
+    case DW_OP_ne:
+    case DW_OP_nop:
+      break;
+    case DW_OP_skip:
+    case DW_OP_bra:
+      lp->lc_number = secp->Get_16 ();
+      break;
+    case DW_OP_piece:
+      lp->lc_number = secp->GetULEB128 ();
+      break;
+    case DW_OP_push_object_address: /* DWARF3 */
+      break;
+    case DW_OP_call2: /* DWARF3 */
+      lp->lc_number = secp->Get_16 ();
+      break;
+    case DW_OP_call4: /* DWARF3 */
+      lp->lc_number = secp->Get_32 ();
+      break;
+    case DW_OP_call_ref: /* DWARF3 */
+      lp->lc_number = secp->GetADDR ();
+      break;
+    default:
+      return (NULL);
+    }
+  return lp;
+}
+
+char *
+DwrCU::tag2str (int tag)
+{
+  static char buf[128];
+  char *s;
+
+  switch (tag)
+    {
+      CASE_S (DW_TAG_array_type);
+      CASE_S (DW_TAG_class_type);
+      CASE_S (DW_TAG_entry_point);
+      CASE_S (DW_TAG_enumeration_type);
+      CASE_S (DW_TAG_formal_parameter);
+      CASE_S (DW_TAG_imported_declaration);
+      CASE_S (DW_TAG_label);
+      CASE_S (DW_TAG_lexical_block);
+      CASE_S (DW_TAG_member);
+      CASE_S (DW_TAG_pointer_type);
+      CASE_S (DW_TAG_reference_type);
+      CASE_S (DW_TAG_compile_unit);
+      CASE_S (DW_TAG_string_type);
+      CASE_S (DW_TAG_structure_type);
+      CASE_S (DW_TAG_subroutine_type);
+      CASE_S (DW_TAG_typedef);
+      CASE_S (DW_TAG_union_type);
+      CASE_S (DW_TAG_unspecified_parameters);
+      CASE_S (DW_TAG_variant);
+      CASE_S (DW_TAG_common_block);
+      CASE_S (DW_TAG_common_inclusion);
+      CASE_S (DW_TAG_inheritance);
+      CASE_S (DW_TAG_inlined_subroutine);
+      CASE_S (DW_TAG_module);
+      CASE_S (DW_TAG_ptr_to_member_type);
+      CASE_S (DW_TAG_set_type);
+      CASE_S (DW_TAG_subrange_type);
+      CASE_S (DW_TAG_with_stmt);
+      CASE_S (DW_TAG_access_declaration);
+      CASE_S (DW_TAG_base_type);
+      CASE_S (DW_TAG_catch_block);
+      CASE_S (DW_TAG_const_type);
+      CASE_S (DW_TAG_constant);
+      CASE_S (DW_TAG_enumerator);
+      CASE_S (DW_TAG_file_type);
+      CASE_S (DW_TAG_friend);
+      CASE_S (DW_TAG_namelist);
+      CASE_S (DW_TAG_namelist_item);
+      CASE_S (DW_TAG_packed_type);
+      CASE_S (DW_TAG_subprogram);
+      CASE_S (DW_TAG_template_type_param);
+      CASE_S (DW_TAG_template_value_param);
+      CASE_S (DW_TAG_thrown_type);
+      CASE_S (DW_TAG_try_block);
+      CASE_S (DW_TAG_variant_part);
+      CASE_S (DW_TAG_variable);
+      CASE_S (DW_TAG_volatile_type);
+      CASE_S (DW_TAG_dwarf_procedure);
+      CASE_S (DW_TAG_restrict_type);
+      CASE_S (DW_TAG_interface_type);
+      CASE_S (DW_TAG_namespace);
+      CASE_S (DW_TAG_imported_module);
+      CASE_S (DW_TAG_unspecified_type);
+      CASE_S (DW_TAG_partial_unit);
+      CASE_S (DW_TAG_imported_unit);
+      CASE_S (DW_TAG_lo_user);
+      CASE_S (DW_TAG_MIPS_loop);
+      CASE_S (DW_TAG_format_label);
+      CASE_S (DW_TAG_function_template);
+      CASE_S (DW_TAG_class_template);
+      CASE_S (DW_TAG_GNU_BINCL);
+      CASE_S (DW_TAG_GNU_EINCL);
+      CASE_S (DW_TAG_GNU_call_site);
+      CASE_S (DW_TAG_GNU_call_site_parameter);
+      CASE_S (DW_TAG_SUN_codeflags);
+      CASE_S (DW_TAG_SUN_memop_info);
+      CASE_S (DW_TAG_hi_user);
+      CASE_S (DW_TAG_icc_compile_unit);
+    default: s = NTXT ("???");
+      break;
+    }
+  snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, tag);
+  buf[sizeof (buf) - 1] = 0;
+  return buf;
+}
+
+char *
+DwrCU::at2str (int tag)
+{
+  static char buf[128];
+  char *s;
+  switch (tag)
+    {
+      CASE_S (DW_AT_sibling);
+      CASE_S (DW_AT_location);
+      CASE_S (DW_AT_name);
+      CASE_S (DW_AT_ordering);
+      CASE_S (DW_AT_subscr_data);
+      CASE_S (DW_AT_byte_size);
+      CASE_S (DW_AT_bit_offset);
+      CASE_S (DW_AT_bit_size);
+      CASE_S (DW_AT_element_list);
+      CASE_S (DW_AT_stmt_list);
+      CASE_S (DW_AT_low_pc);
+      CASE_S (DW_AT_high_pc);
+      CASE_S (DW_AT_language);
+      CASE_S (DW_AT_member);
+      CASE_S (DW_AT_discr);
+      CASE_S (DW_AT_discr_value);
+      CASE_S (DW_AT_visibility);
+      CASE_S (DW_AT_import);
+      CASE_S (DW_AT_string_length);
+      CASE_S (DW_AT_common_reference);
+      CASE_S (DW_AT_comp_dir);
+      CASE_S (DW_AT_const_value);
+      CASE_S (DW_AT_containing_type);
+      CASE_S (DW_AT_default_value);
+      CASE_S (DW_AT_inline);
+      CASE_S (DW_AT_is_optional);
+      CASE_S (DW_AT_lower_bound);
+      CASE_S (DW_AT_producer);
+      CASE_S (DW_AT_prototyped);
+      CASE_S (DW_AT_return_addr);
+      CASE_S (DW_AT_start_scope);
+      CASE_S (DW_AT_stride_size);
+      CASE_S (DW_AT_upper_bound);
+      CASE_S (DW_AT_abstract_origin);
+      CASE_S (DW_AT_accessibility);
+      CASE_S (DW_AT_address_class);
+      CASE_S (DW_AT_artificial);
+      CASE_S (DW_AT_base_types);
+      CASE_S (DW_AT_calling_convention);
+      CASE_S (DW_AT_count);
+      CASE_S (DW_AT_data_member_location);
+      CASE_S (DW_AT_decl_column);
+      CASE_S (DW_AT_decl_file);
+      CASE_S (DW_AT_decl_line);
+      CASE_S (DW_AT_declaration);
+      CASE_S (DW_AT_discr_list);
+      CASE_S (DW_AT_encoding);
+      CASE_S (DW_AT_external);
+      CASE_S (DW_AT_frame_base);
+      CASE_S (DW_AT_friend);
+      CASE_S (DW_AT_identifier_case);
+      CASE_S (DW_AT_macro_info);
+      CASE_S (DW_AT_namelist_item);
+      CASE_S (DW_AT_priority);
+      CASE_S (DW_AT_segment);
+      CASE_S (DW_AT_specification);
+      CASE_S (DW_AT_static_link);
+      CASE_S (DW_AT_type);
+      CASE_S (DW_AT_use_location);
+      CASE_S (DW_AT_variable_parameter);
+      CASE_S (DW_AT_virtuality);
+      CASE_S (DW_AT_vtable_elem_location);
+      CASE_S (DW_AT_allocated);
+      CASE_S (DW_AT_associated);
+      CASE_S (DW_AT_data_location);
+      CASE_S (DW_AT_byte_stride);
+      CASE_S (DW_AT_entry_pc);
+      CASE_S (DW_AT_use_UTF8);
+      CASE_S (DW_AT_extension);
+      CASE_S (DW_AT_ranges);
+      CASE_S (DW_AT_trampoline);
+      CASE_S (DW_AT_call_column);
+      CASE_S (DW_AT_call_file);
+      CASE_S (DW_AT_call_line);
+      CASE_S (DW_AT_description);
+      CASE_S (DW_AT_binary_scale);
+      CASE_S (DW_AT_decimal_scale);
+      CASE_S (DW_AT_small);
+      CASE_S (DW_AT_decimal_sign);
+      CASE_S (DW_AT_digit_count);
+      CASE_S (DW_AT_picture_string);
+      CASE_S (DW_AT_mutable);
+      CASE_S (DW_AT_threads_scaled);
+      CASE_S (DW_AT_explicit);
+      CASE_S (DW_AT_object_pointer);
+      CASE_S (DW_AT_endianity);
+      CASE_S (DW_AT_elemental);
+      CASE_S (DW_AT_pure);
+      CASE_S (DW_AT_recursive);
+      CASE_S (DW_AT_signature);
+      CASE_S (DW_AT_main_subprogram);
+      CASE_S (DW_AT_data_bit_offset);
+      CASE_S (DW_AT_const_expr);
+      CASE_S (DW_AT_enum_class);
+      CASE_S (DW_AT_linkage_name);
+      CASE_S (DW_AT_lo_user);
+      CASE_S (DW_AT_MIPS_fde);
+      CASE_S (DW_AT_MIPS_loop_begin);
+      CASE_S (DW_AT_MIPS_tail_loop_begin);
+      CASE_S (DW_AT_MIPS_epilog_begin);
+      CASE_S (DW_AT_MIPS_loop_unroll_factor);
+      CASE_S (DW_AT_MIPS_software_pipeline_depth);
+      CASE_S (DW_AT_MIPS_linkage_name);
+      CASE_S (DW_AT_MIPS_stride);
+      CASE_S (DW_AT_MIPS_abstract_name);
+      CASE_S (DW_AT_MIPS_clone_origin);
+      CASE_S (DW_AT_MIPS_has_inlines);
+      CASE_S (DW_AT_sf_names);
+      CASE_S (DW_AT_src_info);
+      CASE_S (DW_AT_mac_info);
+      CASE_S (DW_AT_src_coords);
+      CASE_S (DW_AT_body_begin);
+      CASE_S (DW_AT_body_end);
+      CASE_S (DW_AT_GNU_vector);
+      CASE_S (DW_AT_GNU_guarded_by);
+      CASE_S (DW_AT_GNU_pt_guarded_by);
+      CASE_S (DW_AT_GNU_guarded);
+      CASE_S (DW_AT_GNU_pt_guarded);
+      CASE_S (DW_AT_GNU_locks_excluded);
+      CASE_S (DW_AT_GNU_exclusive_locks_required);
+      CASE_S (DW_AT_GNU_shared_locks_required);
+      CASE_S (DW_AT_GNU_odr_signature);
+      CASE_S (DW_AT_GNU_template_name);
+      CASE_S (DW_AT_GNU_call_site_value);
+      CASE_S (DW_AT_GNU_call_site_data_value);
+      CASE_S (DW_AT_GNU_call_site_target);
+      CASE_S (DW_AT_GNU_call_site_target_clobbered);
+      CASE_S (DW_AT_GNU_tail_call);
+      CASE_S (DW_AT_GNU_all_tail_call_sites);
+      CASE_S (DW_AT_GNU_all_call_sites);
+      CASE_S (DW_AT_GNU_all_source_call_sites);
+      CASE_S (DW_AT_SUN_command_line);
+      CASE_S (DW_AT_SUN_func_offsets);
+      CASE_S (DW_AT_SUN_cf_kind);
+      CASE_S (DW_AT_SUN_func_offset);
+      CASE_S (DW_AT_SUN_memop_type_ref);
+      CASE_S (DW_AT_SUN_profile_id);
+      CASE_S (DW_AT_SUN_memop_signature);
+      CASE_S (DW_AT_SUN_obj_dir);
+      CASE_S (DW_AT_SUN_obj_file);
+      CASE_S (DW_AT_SUN_original_name);
+      CASE_S (DW_AT_SUN_link_name);
+      CASE_S (DW_AT_hi_user);
+      CASE_S (DW_AT_icc_flags);
+    default: s = NTXT ("???");
+      break;
+    }
+  snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, tag);
+  buf[sizeof (buf) - 1] = 0;
+  return buf;
+}
+
+char *
+DwrCU::form2str (int tag)
+{
+  static char buf[128];
+  char *s;
+  switch (tag)
+    {
+      CASE_S (DW_FORM_addr);
+      CASE_S (DW_FORM_block2);
+      CASE_S (DW_FORM_block4);
+      CASE_S (DW_FORM_data2);
+      CASE_S (DW_FORM_data4);
+      CASE_S (DW_FORM_data8);
+      CASE_S (DW_FORM_string);
+      CASE_S (DW_FORM_block);
+      CASE_S (DW_FORM_block1);
+      CASE_S (DW_FORM_data1);
+      CASE_S (DW_FORM_flag);
+      CASE_S (DW_FORM_sdata);
+      CASE_S (DW_FORM_strp);
+      CASE_S (DW_FORM_udata);
+      CASE_S (DW_FORM_ref_addr);
+      CASE_S (DW_FORM_ref1);
+      CASE_S (DW_FORM_ref2);
+      CASE_S (DW_FORM_ref4);
+      CASE_S (DW_FORM_ref8);
+      CASE_S (DW_FORM_ref_udata);
+      CASE_S (DW_FORM_indirect);
+      CASE_S (DW_FORM_sec_offset);
+      CASE_S (DW_FORM_exprloc);
+      CASE_S (DW_FORM_flag_present);
+      CASE_S (DW_FORM_ref_sig8);
+    default: s = NTXT ("???");
+      break;
+    }
+  snprintf (buf, sizeof (buf), NTXT ("%s(%d)"), s, tag);
+  buf[sizeof (buf) - 1] = 0;
+  return buf;
+}
+
+void
+Dwr_Tag::dump ()
+{
+  Dprintf (DUMP_DWARFLIB,
+          "\n<%2d>:<0x%08llx> %-30s <abbrev %lld> offset=0x%llx %s\n",
+          (int) level, (long long) die, DwrCU::tag2str (tag), (long long) num,
+          (long long) offset,
+          hasChild ? NTXT ("DW_children_yes") : NTXT ("DW_children_no"));
+  for (int i1 = firstAttribute; i1 < lastAttribute; i1++)
+    {
+      Dwr_Attr *atrp = abbrevAtForm->get (i1);
+      Dprintf (DUMP_DWARFLIB, "       %-30s ", DwrCU::at2str (atrp->at_name));
+      switch (atrp->at_form)
+       {
+       case DW_FORM_strp:
+       case DW_FORM_string:
+         Dprintf (DUMP_DWARFLIB, "  \"%s\"  len=%ld",
+                  atrp->u.str ? atrp->u.str : NTXT ("<NULL>"),
+                  (long) atrp->len);
+         break;
+       case DW_FORM_block:
+       case DW_FORM_block1:
+       case DW_FORM_block2:
+       case DW_FORM_block4:
+         Dprintf (DUMP_DWARFLIB, "  len=%3ld  %p", (long) atrp->len,
+                  atrp->u.str);
+         break;
+       case DW_FORM_addr:
+       case DW_FORM_data2:
+       case DW_FORM_data4:
+       case DW_FORM_data8:
+       case DW_FORM_data1:
+       case DW_FORM_flag:
+       case DW_FORM_sdata:
+       case DW_FORM_udata:
+       case DW_FORM_ref_addr:
+       case DW_FORM_ref1:
+       case DW_FORM_ref2:
+       case DW_FORM_ref4:
+       case DW_FORM_ref8:
+       case DW_FORM_ref_udata:
+       case DW_FORM_indirect:
+       case DW_FORM_sec_offset:
+       case DW_FORM_exprloc:
+       case DW_FORM_ref_sig8:
+       case DW_FORM_flag_present:
+         Dprintf (DUMP_DWARFLIB, "  0x%llx (%lld)", (long long) atrp->u.val,
+                  (long long) atrp->u.val);
+         break;
+       default:
+         DEBUG_CODE
+         {
+           Dprintf (1, "Attribute form 0x%llx (%lld) is not implemented\n",
+                    (long long) atrp->at_form, (long long) atrp->at_form);
+           assert (false);
+         }
+       }
+      Dprintf (DUMP_DWARFLIB, NTXT ("\n"));
+    }
+}
+
+
+//////////////////////////////////////////////////////////
+//  class DwrSec
+
+DwrSec::DwrSec (unsigned char *_data, uint64_t _size, bool _need_swap_endian, bool _addr32)
+{
+  isCopy = false;
+  data = _data;
+  sizeSec = _size;
+  size = (data ? _size : 0);
+  offset = 0;
+  fmt64 = false;
+  reloc = NULL;
+  need_swap_endian = _need_swap_endian;
+  addr32 = _addr32;
+}
+
+DwrSec::DwrSec (DwrSec *secp, uint64_t _offset)
+{
+  isCopy = true;
+  data = secp->data;
+  sizeSec = secp->sizeSec;
+  size = secp->size;
+  offset = _offset;
+  fmt64 = secp->fmt64;
+  reloc = secp->reloc;
+  need_swap_endian = secp->need_swap_endian;
+  addr32 = secp->addr32;
+}
+
+DwrSec::~DwrSec ()
+{
+  if (!isCopy)
+    delete reloc;
+}
+
+bool
+DwrSec::bounds_violation (uint64_t sz)
+{
+  if (offset + sz > size)
+    {
+      Dprintf (DEBUG_ERR_MSG, "DwrSec::bounds_violation: offset=%lld + sz=%lld > size=%lld\n",
+              (long long) offset, (long long) sz, (long long) size);
+      return true;
+    }
+  return false;
+}
+
+uint64_t
+DwrSec::ReadLength ()
+{
+  fmt64 = false;
+  uint64_t val = Get_32 ();
+  if (((uint32_t) val) == 0xffffffff)
+    {
+      fmt64 = true;
+      val = Get_64 ();
+    }
+  size = (val + offset < sizeSec) ? val + offset : sizeSec;
+  return size;
+}
+
+unsigned char
+DwrSec::Get_8 ()
+{
+  unsigned char n = 0;
+  if (bounds_violation (sizeof (char)))
+    return n;
+  n = data[offset];
+  offset += sizeof (char);
+  return n;
+}
+
+unsigned short
+DwrSec::Get_16 ()
+{
+  unsigned short n = 0;
+  if (bounds_violation (sizeof (short)))
+    return n;
+  memcpy ((char *) &n, data + offset, sizeof (short));
+  offset += sizeof (short);
+  if (need_swap_endian)
+    SWAP_ENDIAN (n);
+  return n;
+}
+
+uint32_t
+DwrSec::Get_32 ()
+{
+  uint32_t n = 0;
+  if (bounds_violation (sizeof (uint32_t)))
+    return n;
+  memcpy ((char *) &n, data + offset, sizeof (uint32_t));
+  offset += sizeof (uint32_t);
+  if (need_swap_endian)
+    SWAP_ENDIAN (n);
+  return n;
+}
+
+uint64_t
+DwrSec::Get_64 ()
+{
+  uint64_t n = 0;
+  if (bounds_violation (sizeof (uint64_t)))
+    return n;
+  memcpy ((char *) &n, data + offset, sizeof (uint64_t));
+  offset += sizeof (uint64_t);
+  if (need_swap_endian)
+    SWAP_ENDIAN (n);
+  return n;
+}
+
+char *
+DwrSec::GetData (uint64_t len)
+{
+  char *s = ((char *) data) + offset;
+  if (bounds_violation (len))
+    s = NULL;
+  offset += len;
+  return s;
+}
+
+char *
+DwrSec::GetString (uint64_t *lenp)
+{
+  if (offset < size)
+    {
+      uint64_t len = 0;
+      for (char *s = ((char *) data) + offset; offset + len < size; len++)
+       {
+         if (s[len] == 0)
+           { // '\0' is inside section
+             offset += len + 1;
+             if (len == 0)
+               return NULL;
+             if (lenp)
+               *lenp = len + 1;
+             return s;
+           }
+       }
+      offset += len;
+      return NULL; // The section is not '\0' terminated
+    }
+  return NULL;
+}
+
+uint64_t
+DwrSec::GetLong ()
+{
+  if (fmt64)
+    return Get_64 ();
+  return Get_32 ();
+}
+
+uint64_t
+DwrSec::GetADDR_32 ()
+{
+  uint64_t res = reloc ? reloc->get_reloc_addr (offset) : 0;
+  res += Get_32 ();
+  return res;
+}
+
+uint64_t
+DwrSec::GetADDR_64 ()
+{
+  uint64_t res = reloc ? reloc->get_reloc_addr (offset) : 0;
+  res += Get_64 ();
+  return res;
+}
+
+uint64_t
+DwrSec::GetADDR ()
+{
+  if (addr32)
+    return GetADDR_32 ();
+  return GetADDR_64 ();
+}
+
+uint64_t
+DwrSec::GetRef ()
+{
+  if (fmt64)
+    return GetADDR_64 ();
+  return GetADDR_32 ();
+}
+
+ULEB128
+DwrSec::GetULEB128 ()
+{
+  ULEB128 res = 0;
+  for (int shift = 0;; shift += 7)
+    {
+      ULEB128 val = Get_8 ();
+      res |= (val & 0x7f) << shift;
+      if ((val & 0x80) == 0)
+       break;
+    }
+  return res;
+}
+
+SLEB128
+DwrSec::GetSLEB128 ()
+{
+  ULEB128 res = 0, val = 0;
+  size_t shift;
+  for (shift = 0;;)
+    {
+      val = Get_8 ();
+      res |= (val & 0x7f) << shift;
+      shift += 7;
+      if ((val & 0x80) == 0)
+       break;
+    }
+  if ((val & 0x40) && (shift < 8 * sizeof (res)))
+    res |= -(((ULEB128) 1) << shift);
+  return (SLEB128) res;
+}
+
+static void
+fillBuf (unsigned char *s, int len, int col, unsigned char *buf)
+{
+  const char *nameX = "0123456789abcdef";
+  int i, n, posCh = 2 * col + col / 4 + 5;
+
+  if (len >= col)
+    len = col;
+  for (i = n = 0; i < len; i++, n += 2)
+    {
+      if ((i % 4) == 0 && i > 0)
+       {
+         buf[n] = ' ';
+         n++;
+       }
+      buf[n] = nameX[s[i] >> 4];
+      buf[n + 1] = nameX[s[i] & 0xf];
+      buf[posCh + i] = isprint (s[i]) ? s[i] : ' ';
+    }
+  buf[posCh + i] = 0;
+  for (i = n; i < posCh; i++)
+    buf[i] = ' ';
+}
+
+static void
+dumpArr (unsigned char *s, int len, int col, int num)
+{
+  unsigned char buf[128];
+  if (col <= 0)
+    return;
+  for (int i = 0; i < len; i += col, num += col)
+    {
+      fillBuf (s + i, len - i, col, buf);
+      Dprintf (DUMP_DWARFLIB, "%5d: %s\n", num, buf);
+    }
+}
+
+void
+DwrSec::dump (char *msg)
+{
+  if (sizeSec > 0)
+    {
+      Dprintf (DUMP_DWARFLIB, NTXT ("======= DwrSec::dump\n"));
+      if (msg)
+       Dprintf (DUMP_DWARFLIB, NTXT ("%s:\n"), msg);
+      dumpArr (data, (int) sizeSec, 32, 0);
+      Dprintf (DUMP_DWARFLIB, NTXT ("\n"));
+    }
+}
+
+//////////////////////////////////////////////////////////
+//  class DwrFileNames
+
+DwrFileName::DwrFileName (char *_fname)
+{
+  path = NULL;
+  fname = _fname;
+  dir_index = 0;
+  timestamp = 0;
+  file_size = 0;
+  isUsed = false;
+}
+
+DwrFileName::~DwrFileName ()
+{
+  if (path != fname)
+    free (path);
+}
+
+
+//////////////////////////////////////////////////////////
+//  class DwrLine
+DwrLine::DwrLine ()
+{
+  address = 0;
+  file = 0;
+  line = 0;
+  column = 0;
+}
+
+DwrLine::~DwrLine () { }
+
+
+//////////////////////////////////////////////////////////
+//  class DwrLineRegs
+static int
+LineRegsCmp (const void *a, const void *b)
+{
+  DwrLine *item1 = *((DwrLine **) a);
+  DwrLine *item2 = *((DwrLine **) b);
+  return item1->address == item2->address ? 0 :
+         item1->address > item2->address ? 1 : -1;
+}
+
+DwrLineRegs::DwrLineRegs (DwrSec *secp, char *dirName)
+{
+  // `dwarfdump -vv -l` shows a line section (.debug_line)
+  debug_lineSec = secp;
+  uint64_t stmt_offset = debug_lineSec->offset;
+  uint64_t next_cu_offset = debug_lineSec->ReadLength ();
+  uint64_t header_offset = debug_lineSec->offset;
+  debug_lineSec->size = next_cu_offset;
+  version = debug_lineSec->Get_16 ();
+  header_length = debug_lineSec->GetLong ();
+  opcode_start = debug_lineSec->offset + header_length;
+  minimum_instruction_length = debug_lineSec->Get_8 ();
+  op_index_register = 0;
+  if (version == 4)
+    maximum_operations_per_instruction = debug_lineSec->Get_8 ();
+  else
+    maximum_operations_per_instruction = 1;
+  default_is_stmt = debug_lineSec->Get_8 ();
+  is_stmt = (default_is_stmt != 0);
+  line_base = debug_lineSec->Get_8 ();
+  line_range = debug_lineSec->Get_8 ();
+  opcode_base = debug_lineSec->Get_8 ();
+  standard_opcode_length = (Dwarf_Small*) debug_lineSec->GetData (opcode_base - 1);
+
+  if (DUMP_DWR_LINE_REGS)
+    {
+      Dprintf (DUMP_DWR_LINE_REGS,
+              "\n.debug_line  version=%d stmt_offset=0x%llx"
+              "header_offset=0x%llx size=%lld dirname='%s'\n"
+              "    header_length=0x%llx  opcode_start=0x%llx"
+              "minimum_instruction_length=%d default_is_stmt=%d\n"
+              "    line_base=%d  line_range=%d  opcode_base=%d\n",
+              (int) version, (long long) stmt_offset,
+              (long long) header_offset,
+              (long long) (next_cu_offset - header_offset), STR (dirName),
+              (long long) header_length, (long long) opcode_start,
+              (int) minimum_instruction_length, (int) default_is_stmt,
+              (int) line_base, (int) line_range, (int) opcode_base);
+      if (standard_opcode_length == NULL)
+       Dprintf (DUMP_DWR_LINE_REGS, "ERROR: standard_opcode_length is NULL\n");
+      for (int i = 0, sz = standard_opcode_length ? opcode_base - 1 : 0;
+             i < sz; i++)
+       Dprintf (DUMP_DWR_LINE_REGS, "  opcode[%2d] length %2d\n", i,
+                (int) standard_opcode_length[i]);
+    }
+
+  include_directories = new Vector<char *>;
+  include_directories->append (dirName);
+  while (true)
+    {
+      char *s = debug_lineSec->GetString (NULL);
+      if (s == NULL)
+       break;
+      include_directories->append (s);
+    }
+
+  file_names = new Vector<DwrFileName *>;
+  while (true)
+    {
+      char *s = debug_lineSec->GetString (NULL);
+      if (s == NULL)
+       break;
+      DwrFileName *fnp = new DwrFileName (s);
+      fnp->path = NULL;
+      fnp->fname = s;
+      fnp->dir_index = debug_lineSec->GetULEB128_32 ();
+      fnp->timestamp = debug_lineSec->GetULEB128 ();
+      fnp->file_size = debug_lineSec->GetULEB128 ();
+      file_names->append (fnp);
+    }
+  lines = NULL;
+  dump ();
+}
+
+DwrLineRegs::~DwrLineRegs ()
+{
+  Destroy (file_names);
+  Destroy (lines);
+  delete debug_lineSec;
+  delete include_directories;
+}
+
+void
+DwrLineRegs::dump ()
+{
+  if (!DUMP_DWR_LINE_REGS)
+    return;
+  Dprintf (DUMP_DWR_LINE_REGS, NTXT ("\ninclude_directories size=%lld\n"), (long long) VecSize (include_directories));
+  for (long i = 0, sz = VecSize (include_directories); i < sz; i++)
+    {
+      char *s = include_directories->get (i);
+      Dprintf (DUMP_DWR_LINE_REGS, NTXT (" %2lld %s\n"), (long long) i, STR (s));
+    }
+
+  Dprintf (DUMP_DWR_LINE_REGS, NTXT ("\nfile_names size=%lld\n"), (long long) VecSize (file_names));
+  for (long i = 0, sz = VecSize (file_names); i < sz; i++)
+    {
+      DwrFileName *fnp = file_names->get (i);
+      Dprintf (DUMP_DWR_LINE_REGS, NTXT (" %2lld %-40s dir_index=%4lld  timestamp=%8lld file_size=%lld\n"),
+              (long long) i, STR (fnp->fname),
+              (long long) fnp->dir_index, (long long) fnp->timestamp, (long long) fnp->file_size);
+    }
+  if (lines)
+    lines->dump (fname);
+  Dprintf (DUMP_DWR_LINE_REGS, NTXT ("\n\n"));
+}
+
+void
+DwrLineRegs::DoExtendedOpcode ()
+{
+  uint64_t size = debug_lineSec->GetULEB128 ();
+  if (size == 0)
+    {
+      Dprintf (DUMP_DWR_LINE_REGS, NTXT ("%-20s"), NTXT ("ExtendedOpCode: size=0"));
+      return;
+    }
+  Dwarf_Small opcode = debug_lineSec->Get_8 ();
+  Dprintf (DUMP_DWR_LINE_REGS, NTXT ("%-20s"), extended_opcode2str (opcode));
+  switch (opcode)
+    {
+    case DW_LNE_end_sequence:
+      end_sequence = true;
+      reset ();
+      break;
+    case DW_LNE_set_address:
+      address = debug_lineSec->GetADDR ();
+      break;
+    case DW_LNE_define_file:
+      // TODO, add file to file list
+      fname = debug_lineSec->GetString (NULL);
+      dir_index = debug_lineSec->GetULEB128 ();
+      timestamp = debug_lineSec->GetULEB128 ();
+      file_size = debug_lineSec->GetULEB128 ();
+      break;
+    default:
+      debug_lineSec->GetData (size - 1); // skip unknown opcode
+      break;
+    }
+}
+
+void
+DwrLineRegs::DoStandardOpcode (int opcode)
+{
+  switch (opcode)
+    {
+    case DW_LNS_copy:
+      basic_block = false;
+      EmitLine ();
+      break;
+    case DW_LNS_advance_pc:
+      address += debug_lineSec->GetULEB128 () * minimum_instruction_length;
+      break;
+    case DW_LNS_advance_line:
+      line += (int) debug_lineSec->GetSLEB128 ();
+      break;
+    case DW_LNS_set_file:
+      file = debug_lineSec->GetULEB128_32 ();
+      break;
+    case DW_LNS_set_column:
+      column = debug_lineSec->GetULEB128_32 ();
+      break;
+    case DW_LNS_negate_stmt:
+      is_stmt = -is_stmt;
+      break;
+    case DW_LNS_set_basic_block:
+      basic_block = true;
+      break;
+    case DW_LNS_const_add_pc:
+      address += ((255 - opcode_base) / line_range) * minimum_instruction_length;
+      break;
+    case DW_LNS_fixed_advance_pc:
+      address += debug_lineSec->Get_16 ();
+      break;
+    default:    // skip unknown opcode/operands
+      debug_lineSec->GetData (standard_opcode_length ?
+                             standard_opcode_length[opcode] : 1);
+      break;
+    }
+}
+
+void
+DwrLineRegs::DoSpecialOpcode (int opcode)
+{
+  int max_op_per_instr = maximum_operations_per_instruction == 0 ? 1
+         : maximum_operations_per_instruction;
+  int operation_advance = (opcode / line_range);
+  address += minimum_instruction_length * ((op_index_register + operation_advance) / max_op_per_instr);
+  op_index_register = (op_index_register + operation_advance) % max_op_per_instr;
+  line += line_base + (opcode % line_range);
+  basic_block = false;
+  EmitLine ();
+}
+
+void
+DwrLineRegs::reset ()
+{
+  dir_index = 0;
+  timestamp = 0;
+  file_size = 0;
+  address = 0;
+  file = 1;
+  line = 1;
+  column = 0;
+  is_stmt = (default_is_stmt != 0);
+  basic_block = false;
+  end_sequence = false;
+}
+
+void
+DwrLineRegs::EmitLine ()
+{
+  DwrLine *lnp = new DwrLine;
+
+  lnp->file = file;
+  lnp->line = line;
+  lnp->column = column;
+  lnp->address = address;
+  lines->append (lnp);
+  if ((file > 0) && (file < VecSize (file_names)))
+    {
+      DwrFileName *fnp = file_names->get (file);
+      fnp->isUsed = true;
+    }
+}
+
+Vector<DwrLine *> *
+DwrLineRegs::get_lines ()
+{
+  if (lines == NULL)
+    {
+      lines = new Vector<DwrLine *>;
+      debug_lineSec->offset = opcode_start;
+      reset ();
+      Dprintf (DUMP_DWR_LINE_REGS, "\n  offset        code             address (file, line, column) stmt blck end_seq \n");
+      while (debug_lineSec->offset < debug_lineSec->size)
+       {
+         Dprintf (DUMP_DWR_LINE_REGS, NTXT ("0x%08llx "),
+                  (long long) debug_lineSec->offset);
+         Dwarf_Small opcode = debug_lineSec->Get_8 ();
+         if (opcode == 0)
+           DoExtendedOpcode ();
+         else if (opcode < opcode_base)
+           {
+             DoStandardOpcode (opcode);
+             Dprintf (DUMP_DWR_LINE_REGS, NTXT ("%-20s"), standard_opcode2str (opcode));
+           }
+         else
+           {
+             DoSpecialOpcode (opcode - opcode_base);
+             Dprintf (DUMP_DWR_LINE_REGS, NTXT ("%-20s"),
+                      special_opcode2str (opcode - opcode_base));
+           }
+         Dprintf (DUMP_DWR_LINE_REGS,
+                  "  0x%08llx  (%lld, %lld, %lld)  %c %c %c\n",
+                  (long long) address, (long long) file, (long long) line,
+                  (long long) column, is_stmt ? 'T' : 'F',
+                  basic_block ? 'T' : 'F', end_sequence ? 'T' : 'F');
+       }
+      lines->sort (LineRegsCmp);
+      if (DUMP_DWR_LINE_REGS)
+       lines->dump (fname);
+    }
+  return lines;
+}
+
+char *
+DwrLineRegs::getPath (int fn)
+{
+  fn--;
+  if ((fn >= VecSize (file_names)) || (fn < 0))
+    {
+      Dprintf (DEBUG_ERR_MSG, NTXT ("DwrLineRegs::getPath: fn=0x%lld file_names->size()=%lld\n"),
+              (long long) fn, (long long) VecSize (file_names));
+      return NULL;
+    }
+  DwrFileName *fnp = file_names->fetch (fn);
+  if (fnp->path)
+    return fnp->path;
+
+  char *dir = fnp->dir_index < include_directories->size () ?
+         include_directories->fetch (fnp->dir_index) : NULL;
+  if ((fnp->fname[0] == '/') || (dir == NULL) || (*dir == 0))
+    {
+      fnp->path = fnp->fname;
+      return fnp->path;
+    }
+
+  StringBuilder sb;
+  if (*dir != '/')
+    { // not absolute
+      char *s = include_directories->fetch (0);
+      sb.append (s);
+      sb.append ('/');
+    }
+  sb.append (dir);
+  sb.append ('/');
+  sb.append (fnp->fname);
+  fnp->path = canonical_path (sb.toString ());
+  return fnp->path;
+}
+
+DwrCU::DwrCU (Dwarf *_dwarf)
+{
+  dwarf = _dwarf;
+  cu_offset = dwarf->debug_infoSec->offset;
+  debug_infoSec = new DwrSec (dwarf->debug_infoSec, cu_offset);
+  next_cu_offset = debug_infoSec->ReadLength ();
+  if (next_cu_offset > debug_infoSec->sizeSec)
+    {
+      Dprintf (DEBUG_ERR_MSG,
+       "DwrCU::DwrCU: next_cu_offset(0x%llx) > debug_infoSec->sizeSec(%llx)\n",
+              (long long) next_cu_offset, (long long) debug_infoSec->sizeSec);
+      next_cu_offset = debug_infoSec->sizeSec;
+    }
+  debug_infoSec->size = next_cu_offset;
+  version = debug_infoSec->Get_16 ();
+  debug_abbrev_offset = debug_infoSec->GetLong ();
+  address_size = debug_infoSec->Get_8 ();
+  cu_header_offset = debug_infoSec->offset;
+  comp_dir = NULL;
+  module = NULL;
+  abbrevTable = NULL;
+  dwrInlinedSubrs = NULL;
+  srcFiles = NULL;
+  stmt_list_offset = 0;
+  dwrLineReg = NULL;
+  isMemop = false;
+  isGNU = false;
+  dwrTag.level = 0;
+
+  build_abbrevTable (dwarf->debug_abbrevSec, debug_abbrev_offset);
+#ifdef DEBUG
+  if (DUMP_DWARFLIB)
+    {
+      Dprintf (DUMP_DWARFLIB,
+              "CU_HEADER: header_offset = 0x%08llx %lld"
+              "next_header_offset=0x%08llx %lld\n"
+              "    abbrev_offset = 0x%08llx %lld\n"
+              "    unit_length   = %lld\n"
+              "    version       = %d\n"
+              "    address_size  = %d\n"
+              "    fmt64         = %s\n"
+              "debug_info:   need_swap_endian=%s  fmt64=%s addr32=%s\n",
+              (long long) cu_offset, (long long) cu_offset,
+              (long long) next_cu_offset, (long long) next_cu_offset,
+              (long long) debug_abbrev_offset, (long long) debug_abbrev_offset,
+              (long long) (next_cu_offset - cu_offset),
+              (int) version, (int) address_size,
+              debug_infoSec->fmt64 ? "true" : "false",
+              debug_infoSec->need_swap_endian ? "true" : "false",
+              debug_infoSec->fmt64 ? "true" : "false",
+              debug_infoSec->addr32 ? "true" : "false");
+      Dprintf (DUMP_DWARFLIB, "\n.debug_abbrev  cnt=%d  offset=0x%08llx %lld\n",
+              (int) VecSize (abbrevTable), (long long) debug_abbrev_offset,
+              (long long) debug_abbrev_offset);
+      for (int i = 1, sz = VecSize (abbrevTable); i < sz; i++)
+       {
+         DwrAbbrevTable *abbTbl = abbrevTable->get (i);
+         Dprintf (DUMP_DWARFLIB, NTXT ("%5d: %-30s %-20s offset=0x%08llx\n"),
+                  (int) i, DwrCU::tag2str (abbTbl->tag),
+                  abbTbl->hasChild ? "DW_children_yes" : "DW_children_no",
+                  (long long) abbTbl->offset);
+         for (int i1 = abbTbl->firstAtForm; i1 < abbTbl->lastAtForm; i1++)
+           {
+             Dwr_Attr *atf = abbrevAtForm->get (i1);
+             Dprintf (DUMP_DWARFLIB, "       %-30s %s\n",
+                      DwrCU::at2str (atf->at_name),
+                      DwrCU::form2str (atf->at_form));
+           }
+       }
+    }
+#endif
+}
+
+DwrCU::~DwrCU ()
+{
+  delete debug_infoSec;
+  delete abbrevTable;
+  delete abbrevAtForm;
+  Destroy (dwrInlinedSubrs);
+  delete srcFiles;
+  delete dwrLineReg;
+  free (comp_dir);
+}
+
+void
+DwrCU::build_abbrevTable (DwrSec *_debug_abbrevSec, uint64_t _offset)
+{
+  if (abbrevTable)
+    return;
+  DwrSec *debug_abbrevSec = new DwrSec (_debug_abbrevSec, _offset);
+  abbrevTable = new DbeArray <DwrAbbrevTable>(128);
+  abbrevAtForm = new DbeArray <Dwr_Attr>(512);
+  abbrevTable->allocate (1); // skip first
+  abbrevAtForm->allocate (1); // skip first
+  for (int i = 1; debug_abbrevSec->offset < debug_abbrevSec->size; i++)
+    {
+      DwrAbbrevTable abbTbl;
+      abbTbl.offset = debug_abbrevSec->offset;
+      abbTbl.code = debug_abbrevSec->GetULEB128_32 ();
+      if (abbTbl.code == 0)
+       break;
+      else if (i != abbTbl.code)
+       {
+         dwarf->elf->append_msg (CMSG_ERROR, GTXT ("%s: the abbreviations table is corrupted (%lld <--> %lld)\n"),
+                                 get_basename (dwarf->elf->get_location ()),
+                                 (long long) i, (long long) abbTbl.code);
+         break;
+       }
+      abbTbl.tag = debug_abbrevSec->GetULEB128_32 ();
+      abbTbl.hasChild = (DW_children_yes == debug_abbrevSec->Get_8 ());
+      abbTbl.firstAtForm = abbrevAtForm->size ();
+      while (debug_abbrevSec->offset < debug_abbrevSec->size)
+       {
+         Dwr_Attr atf;
+         atf.at_name = debug_abbrevSec->GetULEB128_32 ();
+         atf.at_form = debug_abbrevSec->GetULEB128_32 ();
+         if (atf.at_name == 0 && atf.at_form == 0)
+           break;
+         abbrevAtForm->append (atf);
+       }
+      abbTbl.lastAtForm = abbrevAtForm->size ();
+      abbrevTable->append (abbTbl);
+    }
+  delete debug_abbrevSec;
+}
+
+int
+DwrCU::set_die (Dwarf_Die die)
+{
+  if (die > 0)
+    debug_infoSec->offset = die;
+  if (debug_infoSec->offset < cu_header_offset
+      || debug_infoSec->offset >= debug_infoSec->size)
+    return DW_DLV_ERROR;
+  dwrTag.offset = debug_infoSec->offset;
+  dwrTag.die = debug_infoSec->offset - cu_offset;
+  dwrTag.num = debug_infoSec->GetULEB128_32 ();
+  if (dwrTag.num == 0)
+    return DW_DLV_NO_ENTRY;
+  dwrTag.abbrevAtForm = abbrevAtForm;
+  DwrAbbrevTable *abbTbl = abbrevTable->get (dwrTag.num);
+  if (abbTbl == NULL)
+    { // corrupt dwarf
+      dwarf->elf->append_msg (CMSG_ERROR, GTXT ("%s: the abbreviation code (%lld) does not match for the Dwarf entry (0x%llx)\n"),
+                             get_basename (dwarf->elf->get_location ()),
+                            (long long) dwrTag.num, (long long) dwrTag.offset);
+      return DW_DLV_ERROR;
+    }
+  dwrTag.tag = abbTbl->tag;
+  dwrTag.hasChild = abbTbl->hasChild;
+  dwrTag.firstAttribute = abbTbl->firstAtForm;
+  dwrTag.lastAttribute = abbTbl->lastAtForm;
+  for (int k = abbTbl->firstAtForm; k < abbTbl->lastAtForm; k++)
+    {
+      Dwr_Attr *atf = abbrevAtForm->get (k);
+      int at_form = atf->at_form;
+      if (at_form == DW_FORM_indirect)
+       at_form = debug_infoSec->GetULEB128_32 ();
+      switch (at_form)
+       {
+       case DW_FORM_addr:
+         atf->u.offset = (address_size == 4) ? debug_infoSec->GetADDR_32 ()
+                 : debug_infoSec->GetADDR_64 ();
+         break;
+       case DW_FORM_flag:
+         atf->u.offset = debug_infoSec->Get_8 ();
+         break;
+       case DW_FORM_block:
+         atf->len = debug_infoSec->GetULEB128 ();
+         atf->u.str = debug_infoSec->GetData (atf->len);
+         break;
+       case DW_FORM_block1:
+         atf->len = debug_infoSec->Get_8 ();
+         atf->u.str = debug_infoSec->GetData (atf->len);
+         break;
+       case DW_FORM_block2:
+         atf->len = debug_infoSec->Get_16 ();
+         atf->u.str = debug_infoSec->GetData (atf->len);
+         break;
+       case DW_FORM_block4:
+         atf->len = debug_infoSec->Get_32 ();
+         atf->u.str = debug_infoSec->GetData (atf->len);
+         break;
+       case DW_FORM_ref1:
+         atf->u.offset = debug_infoSec->Get_8 ();
+         break;
+       case DW_FORM_ref2:
+         atf->u.offset = debug_infoSec->Get_16 ();
+         break;
+       case DW_FORM_ref4:
+         atf->u.offset = debug_infoSec->Get_32 ();
+         break;
+       case DW_FORM_ref8:
+         atf->u.offset = debug_infoSec->Get_64 ();
+         break;
+       case DW_FORM_ref_udata:
+         atf->u.offset = debug_infoSec->GetULEB128 ();
+         break;
+       case DW_FORM_data1:
+         atf->u.offset = debug_infoSec->Get_8 ();
+         break;
+       case DW_FORM_data2:
+         atf->u.offset = debug_infoSec->Get_16 ();
+         break;
+       case DW_FORM_data4:
+         atf->u.offset = debug_infoSec->Get_32 ();
+         break;
+       case DW_FORM_data8:
+         atf->u.offset = debug_infoSec->Get_64 ();
+         break;
+       case DW_FORM_string:
+         atf->u.str = debug_infoSec->GetString (&atf->len);
+         break;
+       case DW_FORM_strp:
+         atf->u.offset = debug_infoSec->GetRef ();
+         if (dwarf->debug_strSec == NULL)
+           {
+             atf->u.str = NULL;
+             atf->len = 0;
+           }
+         else
+           {
+             dwarf->debug_strSec->offset = atf->u.offset;
+             atf->u.str = dwarf->debug_strSec->GetString (&atf->len);
+           }
+         break;
+       case DW_FORM_sdata:
+         atf->u.val = debug_infoSec->GetSLEB128 ();
+         break;
+       case DW_FORM_udata:
+         atf->u.offset = debug_infoSec->GetULEB128 ();
+         break;
+       case DW_FORM_ref_addr:
+         atf->u.offset = debug_infoSec->GetADDR ();
+         break;
+       case DW_FORM_sec_offset:
+         atf->u.offset = debug_infoSec->GetRef ();
+         break;
+       case DW_FORM_exprloc:
+         atf->u.offset = debug_infoSec->GetULEB128 ();
+         debug_infoSec->offset += atf->u.offset;
+         break;
+       case DW_FORM_flag_present:
+         atf->u.val = 1;
+         break;
+       case DW_FORM_ref_sig8:
+         atf->u.offset = debug_infoSec->GetADDR_64 ();
+         break;
+       default:
+         DEBUG_CODE
+         {
+           Dprintf (1, "Attribute form 0x%llx (%lld) is not implemented\n",
+                    (long long) atf->at_form, (long long) atf->at_form);
+           assert (0);
+         }
+         atf->u.str = NULL;
+         atf->len = 0;
+         break;
+       }
+    }
+  dwrTag.dump ();
+  return DW_DLV_OK;
+}
+
+static char *
+composePath (char *dname, char *fname)
+{
+  char *s;
+  if (*fname == '/' || dname == NULL)
+    s = dbe_sprintf (NTXT ("%s"), fname);
+  else
+    s = dbe_sprintf (NTXT ("%s/%s"), dname, fname);
+  return canonical_path (s);
+}
+
+Module *
+DwrCU::parse_cu_header (LoadObject *lo)
+{
+  // Is tag always DW_TAG_compile_unit?
+  if (dwrTag.tag != DW_TAG_compile_unit)
+    {
+      Dprintf (DEBUG_ERR_MSG,
+           "parse_cu_header: die=0x%llx tag=%lld is not DW_TAG_compile_unit\n",
+              (long long) cu_offset, (long long) dwrTag.tag);
+      return NULL;
+    }
+
+  char *name = Dwarf_string (DW_AT_name);
+  if (name == NULL)
+    name = NTXT ("UnnamedUnit");
+  stmt_list_offset = Dwarf_data (DW_AT_stmt_list);
+  comp_dir = dbe_strdup (Dwarf_string (DW_AT_comp_dir));
+  char *dir_name = comp_dir ? StrChr (comp_dir, ':') : NULL;
+  char *orig_name = Dwarf_string (DW_AT_SUN_original_name);
+  char *path = composePath (dir_name, orig_name ? orig_name : name);
+
+  module = dwarf->stabs->append_Module (lo, path);
+  free (path);
+  if (module == NULL)
+    return NULL;
+  module->hasDwarf = true;
+  if (orig_name)
+    module->linkerStabName = composePath (dir_name, name);
+  module->lang_code = Dwarf_lang ();
+  module->comp_flags = dbe_strdup (Dwarf_string (DW_AT_SUN_command_line));
+  if (module->comp_flags == NULL)
+    module->comp_flags = dbe_strdup (Dwarf_string (DW_AT_icc_flags));
+  module->comp_dir = dbe_strdup (dir_name);
+
+  char *obj_file = Dwarf_string (DW_AT_SUN_obj_file);
+  char *obj_dir = Dwarf_string (DW_AT_SUN_obj_dir);
+  if (obj_dir && obj_file)
+    {
+      // object information may not be available
+      dir_name = StrChr (obj_dir, ':');
+      path = composePath (dir_name, obj_file);
+      if (module->dot_o_file == NULL)
+       module->dot_o_file = module->createLoadObject (path);
+    }
+  else
+    path = dbe_strdup (dwarf->stabs->path);
+  module->set_name (path);
+  return module;
+}
+
+Dwr_Attr *
+Dwr_Tag::get_attr (Dwarf_Half attr)
+{
+  for (long i = firstAttribute; i < lastAttribute; i++)
+    {
+      Dwr_Attr *atf = abbrevAtForm->get (i);
+      if (atf->at_name == attr)
+       return atf;
+    }
+  return NULL;
+}
+
+char *
+DwrCU::Dwarf_string (Dwarf_Half attr)
+{
+  Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+  return dwrAttr ? dwrAttr->u.str : NULL;
+}
+
+uint64_t
+DwrCU::get_high_pc (uint64_t low_pc)
+{
+  Dwr_Attr *dwrAttr = dwrTag.get_attr (DW_AT_high_pc);
+  if (dwrAttr)
+    switch (dwrAttr->at_form)
+      {
+      case DW_FORM_addr:
+       return dwrAttr->u.offset;
+      default:
+       return dwrAttr->u.offset + low_pc;
+      }
+  return 0;
+}
+
+Dwarf_Addr
+DwrCU::Dwarf_addr (Dwarf_Half attr)
+{
+  Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+  if (dwrAttr)
+    switch (dwrAttr->at_form)
+      {
+      case DW_FORM_addr:
+       return dwrAttr->u.offset;
+      }
+  return 0;
+}
+
+DwrSec*
+DwrCU::Dwarf_block (Dwarf_Half attr)
+{
+  Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+  if (dwrAttr && dwrAttr->u.block)
+    switch (dwrAttr->at_form)
+      {
+      case DW_FORM_block:
+      case DW_FORM_block1:
+      case DW_FORM_block2:
+      case DW_FORM_block4:
+       return new DwrSec (dwrAttr->u.block, dwrAttr->len,
+                          dwarf->elf->need_swap_endian,
+                          dwarf->elf->elf_getclass () == ELFCLASS32);
+      }
+  return NULL;
+}
+
+int
+DwrCU::read_data_attr (Dwarf_Half attr, int64_t *retVal)
+{
+  Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+  if (dwrAttr)
+    switch (dwrAttr->at_form)
+      {
+      case DW_FORM_data1:
+      case DW_FORM_data2:
+      case DW_FORM_data4:
+      case DW_FORM_data8:
+      case DW_FORM_udata:
+      case DW_FORM_sec_offset:
+       *retVal = dwrAttr->u.val;
+       return DW_DLV_OK;
+
+      }
+  return DW_DLV_ERROR;
+}
+
+int
+DwrCU::read_ref_attr (Dwarf_Half attr, int64_t *retVal)
+{
+  Dwr_Attr *dwrAttr = dwrTag.get_attr (attr);
+  if (dwrAttr)
+    switch (dwrAttr->at_form)
+      {
+      case DW_FORM_ref1:
+      case DW_FORM_ref2:
+      case DW_FORM_ref4:
+      case DW_FORM_ref8:
+      case DW_FORM_ref_udata:
+      case DW_FORM_sec_offset:
+      case DW_FORM_exprloc:
+      case DW_FORM_ref_sig8:
+       *retVal = dwrAttr->u.val;
+       return DW_DLV_OK;
+      }
+  return DW_DLV_ERROR;
+}
+
+int64_t
+DwrCU::Dwarf_data (Dwarf_Half attr)
+{
+  int64_t retVal;
+  if (read_data_attr (attr, &retVal) == DW_DLV_OK)
+    return retVal;
+  return 0;
+}
+
+int64_t
+DwrCU::Dwarf_ref (Dwarf_Half attr)
+{
+  int64_t retVal;
+  if (read_ref_attr (attr, &retVal) == DW_DLV_OK)
+    return retVal;
+  return 0;
+}
+
+Dwarf_Addr
+DwrCU::Dwarf_location (Dwarf_Attribute attr)
+{
+  DwrSec *secp = Dwarf_block (attr);
+  if (secp)
+    {
+      DwrLocation loc;
+      DwrLocation *lp = dwr_get_location (secp, &loc);
+      delete secp;
+      if (lp)
+       return lp->lc_number;
+    }
+  return 0;
+}
+
+void
+DwrCU::map_dwarf_lines (Module *mod)
+{
+  DwrLineRegs *lineReg = get_dwrLineReg ();
+  long inlinedSubrCnt = VecSize (dwrInlinedSubrs);
+  if (isGNU && (inlinedSubrCnt > 0))
+    {
+      Function *func = NULL;
+      mod->inlinedSubr = (InlinedSubr *) malloc (inlinedSubrCnt
+                                                * sizeof (InlinedSubr));
+      for (long i = 0; i < inlinedSubrCnt; i++)
+       {
+         DwrInlinedSubr *inlinedSubr = dwrInlinedSubrs->get (i);
+         uint64_t low_pc;
+         Function *f = dwarf->stabs->map_PC_to_func (inlinedSubr->low_pc,
+                                                     low_pc, mod->functions);
+         if (f == NULL)
+           continue;
+         if (func != f)
+           {
+             func = f;
+             func->inlinedSubrCnt = 0;
+             func->inlinedSubr = mod->inlinedSubr + i;
+           }
+         InlinedSubr *p = func->inlinedSubr + func->inlinedSubrCnt;
+         func->inlinedSubrCnt++;
+         int fileno = inlinedSubr->file - 1;
+         SourceFile *sf = ((fileno >= 0) && (fileno < VecSize (srcFiles))) ?
+                 srcFiles->get (fileno) : dbeSession->get_Unknown_Source ();
+         p->dbeLine = sf->find_dbeline (inlinedSubr->line);
+         p->high_pc = inlinedSubr->high_pc - low_pc;
+         p->low_pc = inlinedSubr->low_pc - low_pc;
+         p->level = inlinedSubr->level;
+         p->func = NULL;
+         p->fname = NULL;
+         if (set_die (inlinedSubr->abstract_origin) == DW_DLV_OK)
+           p->fname = dbe_strdup (Dwarf_string (DW_AT_name));
+         if (p->fname)
+           p->func = Stabs::find_func (p->fname, mod->functions,
+                                       Stabs::is_fortran (mod->lang_code));
+       }
+    }
+  Vector<DwrLine *> *lines = lineReg->get_lines ();
+
+  Include *includes = new Include;
+  includes->new_src_file (mod->getMainSrc (), 0, NULL);
+  char *path = NULL;
+  SourceFile *cur_src = NULL;
+  Function *cur_func = NULL;
+  for (long i = 0, sz = VecSize (lines); i < sz; i++)
+    {
+      DwrLine *dwrLine = lines->get (i);
+      char *filename = dwrLineReg->getPath (dwrLine->file);
+      if (filename == NULL)
+       continue;
+      uint64_t pc = dwrLine->address;
+      int lineno = dwrLine->line;
+      if (path != filename)
+       {
+         path = filename;
+         char *name = StrChr (path, ':');
+         SourceFile *src = mod->setIncludeFile (name);
+         if (cur_src != src)
+           {
+             includes->new_src_file (src, lineno, cur_func);
+             cur_src = src;
+           }
+       }
+      uint64_t low_pc;
+      Function *func = dwarf->stabs->map_PC_to_func (pc, low_pc, mod->functions);
+      if (func && (func->module == mod))
+       {
+         if (func != cur_func)
+           {
+             if (cur_func)
+               while (cur_func->popSrcFile () != NULL)
+                 ;
+             cur_func = func;
+             includes->push_src_files (cur_func);
+           }
+         cur_func->add_PC_info (pc - low_pc, lineno);
+       }
+    }
+  if (cur_func)
+    while (cur_func->popSrcFile ())
+      ;
+  delete includes;
+}
+
+DwrLineRegs *
+DwrCU::get_dwrLineReg ()
+{
+  if (dwrLineReg == NULL)
+    dwrLineReg = new DwrLineRegs (new DwrSec (dwarf->debug_lineSec,
+                                             stmt_list_offset), comp_dir);
+  return dwrLineReg;
+}
+
+void
+DwrCU::parse_inlined_subroutine (Dwarf_cnt *ctx)
+{
+  int64_t abstract_origin = Dwarf_ref (DW_AT_abstract_origin);
+  int fileno = (int) Dwarf_data (DW_AT_call_file);
+  int lineno = (int) Dwarf_data (DW_AT_call_line);
+  int level = ctx->inlinedSubr ? (ctx->inlinedSubr->level + 1) : 0;
+  DwrInlinedSubr *inlinedSubr_old = ctx->inlinedSubr;
+
+  if (dwrInlinedSubrs == NULL)
+    dwrInlinedSubrs = new Vector<DwrInlinedSubr*>;
+  Dwr_Attr *dwrAttr = dwrTag.get_attr (DW_AT_ranges);
+  if (dwrAttr)
+    {
+      uint64_t ranges = Dwarf_ref (DW_AT_ranges);
+      if (dwarf->debug_rangesSec && (ranges < dwarf->debug_rangesSec->size))
+       {
+         dwarf->debug_rangesSec->offset = ranges;
+         for (;;)
+           {
+             uint64_t low_pc = dwarf->debug_rangesSec->GetADDR ();
+             uint64_t high_pc = dwarf->debug_rangesSec->GetADDR ();
+             if ((low_pc > 0) && (low_pc <= high_pc))
+               {
+                 DwrInlinedSubr *p = new DwrInlinedSubr (abstract_origin,
+                                       low_pc, high_pc, fileno, lineno, level);
+                 dwrInlinedSubrs->append (p);
+                 ctx->inlinedSubr = p;
+               }
+             else
+               break;
+           }
+       }
+    }
+  else
+    {
+      uint64_t low_pc = Dwarf_addr (DW_AT_low_pc);
+      uint64_t high_pc = get_high_pc (low_pc);
+      if ((low_pc > 0) && (low_pc <= high_pc))
+       {
+         DwrInlinedSubr *p = new DwrInlinedSubr (abstract_origin, low_pc,
+                                               high_pc, fileno, lineno, level);
+         dwrInlinedSubrs->append (p);
+         ctx->inlinedSubr = p;
+       }
+    }
+  parseChild (ctx);
+  ctx->inlinedSubr = inlinedSubr_old;
+}
+
+
+//////////////////////////////////////////////////////////
+//  class DwrInlinedSubr
+DwrInlinedSubr::DwrInlinedSubr (int64_t _abstract_origin, uint64_t _low_pc,
+                           uint64_t _high_pc, int _file, int _line, int _level)
+{
+  abstract_origin = _abstract_origin;
+  low_pc = _low_pc;
+  high_pc = _high_pc;
+  file = _file;
+  line = _line;
+  level = _level;
+}
+
+void
+DwrInlinedSubr::dump ()
+{
+  Dprintf (DUMP_DWARFLIB,
+          "  level=%d  0x%08llx [0x%08llx - 0x%08llx]  file=%d line=%d\n",
+          (int) level, (long long) abstract_origin, (long long) low_pc,
+          (long long) high_pc, (int) file, (int) line);
+}
diff --git a/gprofng/src/DwarfLib.h b/gprofng/src/DwarfLib.h
new file mode 100644 (file)
index 0000000..95eff57
--- /dev/null
@@ -0,0 +1,313 @@
+/* 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 _DWARFLIB_H_
+#define _DWARFLIB_H_
+
+#include "dwarf2.h"
+
+class ElfReloc;
+class Dwr_type;
+class SourceFile;
+
+template <class ITEM> class Vector;
+template <class ITEM> class DbeArray;
+template <typename Key_t, typename Value_t> class DefaultMap;
+
+typedef uint64_t ULEB128;
+typedef int64_t SLEB128;
+typedef unsigned short Dwarf_Half;
+typedef unsigned char Dwarf_Small;
+typedef uint64_t Dwarf_Off;
+typedef uint64_t Dwarf_Addr;
+typedef uint64_t Dwarf_Unsigned;
+typedef int64_t Dwarf_Die;
+typedef int32_t Dwarf_Debug;
+typedef int32_t Dwarf_Attribute;
+
+
+class DwrSec
+{
+public:
+  DwrSec (unsigned char *_data, uint64_t _size, bool _need_swap_endian, bool _addr32);
+  DwrSec (DwrSec *secp, uint64_t _offset);
+  ~DwrSec ();
+  unsigned char Get_8 ();
+  unsigned short Get_16 ();
+  uint32_t Get_32 ();
+  uint64_t Get_64 ();
+  uint64_t GetRef ();
+  uint64_t GetADDR ();
+  uint64_t GetADDR_32 ();
+  uint64_t GetADDR_64 ();
+  uint64_t GetLong ();
+  uint64_t ReadLength ();
+  SLEB128 GetSLEB128 ();
+  ULEB128 GetULEB128 ();
+  char *GetString (uint64_t *lenp);
+  char *GetData (uint64_t len);
+  void dump (char *msg);
+
+  inline uint32_t
+  GetULEB128_32 ()
+  {
+    return (uint32_t) GetULEB128 ();
+  }
+
+  bool
+  inRange (uint64_t left, uint64_t right)
+  {
+    return (offset >= left) && (offset < right);
+  };
+
+  ElfReloc *reloc;
+  uint64_t sizeSec;
+  uint64_t size;
+  uint64_t offset;
+  bool fmt64;
+  bool addr32;
+  bool need_swap_endian;
+
+private:
+  bool isCopy;
+  unsigned char *data;
+  bool bounds_violation (uint64_t sz);
+};
+
+class DwrFileName
+{
+public:
+  DwrFileName (char *_fname);
+  ~DwrFileName ();
+  uint64_t timestamp;
+  uint64_t file_size;
+  int dir_index;
+  char *fname;
+  char *path;
+  bool isUsed;
+};
+
+class DwrLine
+{
+public:
+  DwrLine ();
+  ~DwrLine ();
+  uint64_t address;
+  uint32_t file;
+  uint32_t line;
+  uint32_t column;
+};
+
+class DwrInlinedSubr
+{
+public:
+  DwrInlinedSubr (int64_t _abstract_origin, uint64_t _low_pc, uint64_t _high_pc,
+                 int _file, int _line, int _level);
+  void dump ();
+  int64_t abstract_origin;
+  uint64_t low_pc;
+  uint64_t high_pc;
+  int file;
+  int line;
+  int level;
+};
+
+class DwrLineRegs
+{
+public:
+  DwrLineRegs (DwrSec *_secp, char *dirName);
+  ~DwrLineRegs ();
+  char *getPath (int fn);
+  Vector<DwrLine *> *get_lines ();
+  void dump ();
+
+  Vector<DwrFileName *> *file_names;
+
+private:
+  void DoExtendedOpcode ();
+  void DoStandardOpcode (int opcode);
+  void DoSpecialOpcode (int opcode);
+  void EmitLine ();
+  void reset ();
+
+  char *fname;
+  uint64_t dir_index;
+  uint64_t timestamp;
+  uint64_t file_size;
+  uint64_t address;
+  uint32_t file;
+  uint32_t line;
+  uint32_t column;
+  Dwarf_Half version;
+  uint64_t op_index_register;
+  Dwarf_Small maximum_operations_per_instruction;
+  Dwarf_Small minimum_instruction_length;
+  Dwarf_Small default_is_stmt;
+  Dwarf_Small line_range;
+  Dwarf_Small opcode_base;
+  signed char line_base;
+  bool is_stmt;
+  bool basic_block;
+  bool end_sequence;
+  Vector<DwrLine *> *lines;
+  Vector<char *> *include_directories;
+  Dwarf_Small *standard_opcode_length;
+  DwrSec *debug_lineSec;
+  uint64_t header_length;
+  uint64_t opcode_start;
+};
+
+typedef struct Dwr_Attr
+{
+  union
+  {
+    char *str;
+    unsigned char *block;
+    uint64_t offset;
+    int64_t val;
+  } u;
+  uint64_t len;     // length of u.str
+  int at_form;
+  int at_name;
+} Dwr_Attr;
+
+typedef struct Dwr_Tag
+{
+public:
+  Dwr_Attr *get_attr (Dwarf_Half attr);
+  void dump ();
+
+  DbeArray<Dwr_Attr> *abbrevAtForm;
+  int64_t die;
+  int64_t offset;
+  int firstAttribute;
+  int lastAttribute;
+  int tag;
+  int hasChild;
+  int num;
+  int level;
+} Dwr_Tag;
+
+enum
+{
+  DW_DLV_OK,
+  DW_DLV_NO_ENTRY,
+  DW_DLV_ERROR,
+  DW_DLV_BAD_ELF,
+  DW_DLV_NO_DWARF,
+  DW_DLV_WRONG_ARG
+};
+
+typedef struct DwrLocation
+{
+  uint64_t offset;
+  uint64_t lc_number;
+  uint64_t lc_number2;
+  uint32_t op;
+} DwrLocation;
+
+typedef struct DwrAbbrevTable
+{
+  int64_t offset;
+  int firstAtForm;
+  int lastAtForm;
+  int code;
+  int tag;
+  bool hasChild;
+} DwrAbbrevTable;
+
+class Dwarf_cnt
+{
+public:
+  Dwarf_cnt ();
+  int64_t cu_offset;
+  int64_t parent;
+  int64_t size;
+  Module *module;
+  char *name;
+  Function *func;
+  Function *fortranMAIN;
+  datatype_t *dtype;
+  DwrInlinedSubr *inlinedSubr;
+  DefaultMap <int64_t, Dwr_type*> *dwr_types;
+  int level;
+
+  Dwr_type *get_dwr_type (int64_t cu_die_offset);
+  Dwr_type *put_dwr_type (int64_t cu_die_offset, int tag);
+  Dwr_type *put_dwr_type (Dwr_Tag *dwrTag);
+};
+
+class DwrCU
+{
+public:
+  DwrCU (Dwarf *_dwarf);
+  ~DwrCU ();
+  Module *parse_cu_header (LoadObject *lo);
+  void parseChild (Dwarf_cnt *ctx);
+  void read_hwcprof_info (Dwarf_cnt *ctx);
+  void map_dwarf_lines (Module *mod);
+  int set_die (Dwarf_Die die);
+  DwrLineRegs *get_dwrLineReg ();
+
+  static char *at2str (int tag);
+  static char *form2str (int tag);
+  static char *tag2str (int tag);
+
+  uint64_t cu_header_offset;
+  uint64_t cu_offset;
+  uint64_t next_cu_offset;
+  Vector<DwrInlinedSubr*> *dwrInlinedSubrs;
+  Vector<SourceFile *> *srcFiles;
+  bool isMemop;
+  bool isGNU;
+
+private:
+  void build_abbrevTable (DwrSec *debug_abbrevSec, uint64_t stmt_list_offset);
+  Function *append_Function (Dwarf_cnt *ctx);
+  void parse_inlined_subroutine (Dwarf_cnt *ctx);
+  uint64_t get_low_pc ();
+  uint64_t get_high_pc (uint64_t low_pc);
+  DwrLocation *dwr_get_location (DwrSec *secp, DwrLocation *lp);
+  int read_data_attr (Dwarf_Half attr, int64_t *retVal);
+  int read_ref_attr (Dwarf_Half attr, int64_t *retVal);
+  char *get_linkage_name ();
+  char *Dwarf_string (Dwarf_Half attr);
+  int64_t Dwarf_data (Dwarf_Half attr);
+  int64_t Dwarf_ref (Dwarf_Half attr);
+  DwrSec *Dwarf_block (Dwarf_Half attr);
+  Dwarf_Addr Dwarf_addr (Dwarf_Half attr);
+  Dwarf_Addr Dwarf_location (Dwarf_Attribute attr);
+  Sp_lang_code Dwarf_lang ();
+
+  Dwarf *dwarf;
+  DwrSec *debug_infoSec;
+  uint64_t debug_abbrev_offset;
+  uint64_t stmt_list_offset;  // offset in .debug_line section (DW_AT_stmt_list)
+  char *comp_dir;             // compilation directory (DW_AT_comp_dir)
+  Module *module;
+  Dwarf_Half version;
+  Dwarf_Small address_size;
+  Dwr_Tag dwrTag;
+  DwrLineRegs *dwrLineReg;
+  DbeArray<DwrAbbrevTable> *abbrevTable;
+  DbeArray<Dwr_Attr> *abbrevAtForm;
+};
+
+#endif /* _DWARFLIB_H_ */
diff --git a/gprofng/src/Elf.cc b/gprofng/src/Elf.cc
new file mode 100644 (file)
index 0000000..4117cf2
--- /dev/null
@@ -0,0 +1,1138 @@
+/* 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 <unistd.h>
+
+#include "util.h"
+#include "bfd.h"
+#include "elf-bfd.h"
+#include "Elf.h"
+#include "Map.h"
+#include "StringBuilder.h"
+#include "DbeFile.h"
+
+typedef uint32_t Elf32_Word;
+typedef uint32_t Elf64_Word;
+typedef uint32_t Elf32_Addr;
+typedef uint64_t Elf64_Addr;
+typedef uint64_t Elf64_Xword;
+typedef int32_t Elf32_Sword;
+typedef int64_t Elf64_Sxword;
+typedef uint16_t Elf32_Half;
+typedef uint16_t Elf64_Half;
+
+// Ancillary entry
+typedef struct
+{
+  Elf32_Word a_tag;         /* how to interpret value */
+  union
+  {
+    Elf32_Word a_val;
+    Elf32_Addr a_ptr;
+  } a_un;
+} Elf32_Ancillary;
+
+struct S_Elf64_Ancillary
+{
+  Elf64_Xword a_tag;        /* how to interpret value */
+  union
+  {
+    Elf64_Xword a_val;
+    Elf64_Addr a_ptr;
+  } a_un;
+};
+
+/* Dynamic section entry.  */
+typedef struct
+{
+  Elf32_Sword d_tag;        /* Dynamic entry type */
+
+  union
+  {
+    Elf32_Word d_val;       /* Integer value */
+    Elf32_Addr d_ptr;       /* Address value */
+  } d_un;
+} Elf32_Dyn;
+
+struct S_Elf64_Dyn
+{
+  Elf64_Sxword d_tag;       /* Dynamic entry type */
+
+  union
+  {
+    Elf64_Xword d_val;      /* Integer value */
+    Elf64_Addr d_ptr;       /* Address value */
+  } d_un;
+};
+
+
+// Symbol table
+typedef struct
+{
+  Elf32_Word st_name;
+  Elf32_Addr st_value;
+  Elf32_Word st_size;
+  unsigned char st_info;    /* bind, type: ELF_32_ST_... */
+  unsigned char st_other;
+  Elf32_Half st_shndx;      /* SHN_... */
+} Elf32_Sym;
+
+typedef struct
+{
+  Elf64_Word st_name;
+  unsigned char st_info;    /* bind, type: ELF_64_ST_... */
+  unsigned char st_other;
+  Elf64_Half st_shndx;      /* SHN_... */
+  Elf64_Addr st_value;
+  Elf64_Xword st_size;
+} Elf64_Sym;
+
+
+// Relocation
+typedef struct
+{
+  Elf32_Addr r_offset;
+  Elf32_Word r_info;        /* sym, type: ELF32_R_... */
+} Elf32_Rel;
+
+typedef struct
+{
+  Elf32_Addr r_offset;
+  Elf32_Word r_info;        /* sym, type: ELF32_R_... */
+  Elf32_Sword r_addend;
+} Elf32_Rela;
+
+typedef struct
+{
+  Elf64_Addr r_offset;
+  Elf64_Xword r_info;       /* sym, type: ELF64_R_... */
+} Elf64_Rel;
+
+typedef struct
+{
+  Elf64_Addr r_offset;
+  Elf64_Xword r_info;       /* sym, type: ELF64_R_... */
+  Elf64_Sxword r_addend;
+} Elf64_Rela;
+
+int Elf::bfd_status = -1;
+
+void
+Elf::elf_init ()
+{
+  if (bfd_status == -1)
+    bfd_status = bfd_init ();
+}
+
+Elf::Elf (char *filename) : DbeMessages (), Data_window (filename)
+{
+  ehdrp = NULL;
+  data = NULL;
+  ancillary_files = NULL;
+  elfSymbols = NULL;
+  gnu_debug_file = NULL;
+  dbeFile = NULL;
+  abfd = NULL;
+  if (bfd_status != BFD_INIT_MAGIC)
+    {
+      status = ELF_ERR_CANT_OPEN_FILE;
+      return;
+    }
+  abfd = bfd_openr (filename, NULL);
+  if (abfd == NULL)
+    {
+      status = ELF_ERR_CANT_OPEN_FILE;
+      return;
+    }
+  if (!bfd_check_format (abfd, bfd_object))
+    {
+      bfd_close (abfd);
+      abfd = NULL;
+      status = ELF_ERR_CANT_OPEN_FILE;
+      return;
+    }
+  ehdrp = elf_getehdr ();
+  if (ehdrp == NULL)
+    {
+      bfd_close (abfd);
+      abfd = NULL;
+      status = ELF_ERR_BAD_ELF_FORMAT;
+      return;
+    }
+  elf_class = ehdrp->e_ident[EI_CLASS];
+  elf_datatype = ehdrp->e_ident[EI_DATA];
+
+  if (not_opened ())
+    {
+      status = ELF_ERR_CANT_OPEN_FILE;
+      return;
+    }
+  status = ELF_ERR_NONE;
+
+#if ARCH(SPARC)
+  need_swap_endian = is_Intel ();
+#else
+  need_swap_endian = !is_Intel ();
+#endif
+
+  analyzerInfo = 0;
+  SUNW_ldynsym = 0;
+  gnuLink = 0;
+  stab = 0;
+  stabStr = 0;
+  stabIndex = 0;
+  stabIndexStr = 0;
+  stabExcl = 0;
+  stabExclStr = 0;
+  symtab = 0;
+  dynsym = 0;
+  info = 0;
+  plt = 0;
+  dwarf = false;
+
+  for (unsigned int sec = 1; sec < elf_getehdr ()->e_shnum; sec++)
+    {
+      char *name = get_sec_name (sec);
+      if (name == NULL)
+       continue;
+      if (streq (name, NTXT (".stab")))
+       stab = sec;
+      else if (streq (name, NTXT (".stabstr")))
+       stabStr = sec;
+      else if (streq (name, NTXT (".stab.index")))
+       stabIndex = sec;
+      else if (streq (name, NTXT (".stab.indexstr")))
+       stabIndexStr = sec;
+      else if (streq (name, NTXT (".stab.excl")))
+       stabExcl = sec;
+      else if (streq (name, NTXT (".stab.exclstr")))
+       stabExclStr = sec;
+      else if (streq (name, NTXT (".gnu_debuglink")))
+       gnuLink = sec;
+      else if (streq (name, NTXT (".__analyzer_info")))
+       analyzerInfo = sec;
+      else if (streq (name, NTXT (".info")))
+       info = true;
+      else if (streq (name, NTXT (".plt")))
+       plt = sec;
+      else if (streq (name, NTXT (".SUNW_ldynsym")))
+       SUNW_ldynsym = sec;
+      else if (streq (name, NTXT (".dynsym")))
+       dynsym = sec;
+      else if (streq (name, NTXT (".symtab")))
+       symtab = sec;
+      else if (strncmp (name, NTXT (".debug"), 6) == 0)
+       dwarf = true;
+    }
+  if (fd != -1)
+    {
+      close (fd);
+      fd = -1;
+    }
+}
+
+Elf::~Elf ()
+{
+  if (data)
+    {
+      for (int i = 0; i < (int) ehdrp->e_shnum; i++)
+       {
+         Elf_Data *p = data[i];
+         if (p && !mmap_on_file && (p->d_flags & SHF_SUNW_ABSENT) == 0)
+           free (p->d_buf);
+         delete p;
+       }
+      free (data);
+    }
+  if (ancillary_files)
+    {
+      ancillary_files->destroy ();
+      delete ancillary_files;
+    }
+  delete elfSymbols;
+  delete gnu_debug_file;
+  delete dbeFile;
+  if (abfd)
+    bfd_close (abfd);
+}
+
+Elf_Internal_Ehdr *
+Elf::elf_getehdr ()
+{
+  if (ehdrp == NULL && abfd)
+    ehdrp = elf_elfheader (abfd);
+  return ehdrp;
+}
+
+Elf_Internal_Phdr *
+Elf::get_phdr (unsigned int ndx)
+{
+  if (ehdrp == NULL || ndx >= ehdrp->e_phnum)
+    return NULL;
+  return &(elf_tdata (abfd)->phdr[ndx]);
+}
+
+Elf_Internal_Shdr *
+Elf::get_shdr (unsigned int ndx)
+{
+  if (ehdrp == NULL || ndx >= ehdrp->e_shnum)
+    return NULL;
+  return elf_elfsections (abfd)[ndx];
+}
+
+Elf64_Dyn *
+Elf::elf_getdyn (Elf_Internal_Phdr *phdr, unsigned int ndx, Elf64_Dyn *pdyn)
+{
+  if (elf_getclass () == ELFCLASS32)
+    {
+      if (ndx * sizeof (Elf32_Dyn) >= phdr->p_filesz)
+       return NULL;
+      Elf32_Dyn *hdr = (Elf32_Dyn*) bind (phdr->p_offset + ndx * sizeof (Elf32_Dyn),
+                                         sizeof (Elf32_Dyn));
+      if (hdr == NULL)
+       return NULL;
+      pdyn->d_tag = decode (hdr->d_tag);
+      pdyn->d_un.d_val = decode (hdr->d_un.d_val);
+    }
+  else
+    {
+      if (ndx * sizeof (Elf64_Dyn) >= phdr->p_filesz)
+       return NULL;
+      Elf64_Dyn *hdr = (Elf64_Dyn*) bind (phdr->p_offset + ndx * sizeof (Elf64_Dyn),
+                                         sizeof (Elf64_Dyn));
+      if (hdr == NULL)
+       return NULL;
+      pdyn->d_tag = decode (hdr->d_tag);
+      pdyn->d_un.d_val = decode (hdr->d_un.d_val);
+    }
+  return pdyn;
+}
+
+unsigned
+Elf::elf_version (unsigned ver)
+{
+  // We compile locally, no need to check the version
+  return ver;
+}
+
+Elf *
+Elf::elf_begin (char *fname, Elf_status *stp)
+{
+  if (fname == NULL)
+    {
+      if (stp)
+       *stp = ELF_ERR_CANT_OPEN_FILE;
+      return NULL;
+    }
+  Elf *elf = new Elf (fname);
+  if (stp)
+    *stp = elf->status;
+  if (elf->status != ELF_ERR_NONE)
+    {
+      delete elf;
+      return NULL;
+    }
+#if DEBUG
+  if (DUMP_ELF_SEC)
+    {
+      char *str = elf->dump ();
+      fprintf (stderr, NTXT ("%s\n\n"), str);
+      free (str);
+    }
+#endif /* DEBUG */
+  return elf;
+}
+
+unsigned int
+Elf::elf_get_sec_num (const char *name)
+{
+  if (name == NULL || ehdrp == NULL)
+    return 0;
+  for (unsigned int sec = 1; sec < ehdrp->e_shnum; sec++)
+    {
+      Elf_Internal_Shdr *shdr = get_shdr (sec);
+      if (shdr == NULL)
+       continue;
+      char *sname = elf_strptr (ehdrp->e_shstrndx, shdr->sh_name);
+      if (sname != NULL && strcmp (name, sname) == 0)
+       return sec;
+    }
+  return 0;
+}
+
+char *
+Elf::get_sec_name (unsigned int sec)
+{
+  Elf_Internal_Shdr *shdr = get_shdr (sec);
+  if (ehdrp == NULL || shdr == NULL)
+    return NULL;
+  return elf_strptr (ehdrp->e_shstrndx, shdr->sh_name);
+}
+
+Elf_Data *
+Elf::elf_getdata (unsigned int sec)
+{
+  if (data == NULL)
+    {
+      data = (Elf_Data **) malloc (ehdrp->e_shnum * sizeof (Elf_Data *));
+      for (int i = 0; i < (int) ehdrp->e_shnum; i++)
+       data[i] = NULL;
+    }
+  Elf_Data *edta = data[sec];
+  if (edta == NULL)
+    {
+      Elf_Internal_Shdr *shdr = get_shdr (sec);
+      if (shdr == NULL)
+       return NULL;
+      edta = new Elf_Data;
+      data[sec] = edta;
+      if ((shdr->sh_flags & SHF_SUNW_ABSENT) != 0)
+       {
+         char *sname = get_sec_name (sec);
+         for (int i = 0, sz = VecSize(ancillary_files); i < sz; i++)
+           {
+             Elf *ancElf = ancillary_files->fetch (i);
+             int secNum = sec;
+             if (dbe_strcmp (sname, ancElf->get_sec_name (sec)) != 0)
+               {
+                 append_msg (CMSG_WARN,
+                             "Warning: the section #%d (%s) is mismatch in ancillary file '%s')\n",
+                             sec, STR (sname), STR (ancElf->fname));
+                 secNum = ancElf->elf_get_sec_num (sname);
+               }
+             if (secNum > 0)
+               {
+                 Elf_Data *ed = ancElf->elf_getdata (secNum);
+                 if (ed && ed->d_buf)
+                   {
+                     *edta = *ed;
+                     edta->d_flags |= SHF_SUNW_ABSENT;
+                     return edta;
+                   }
+               }
+           }
+       }
+      edta->d_buf = get_data (shdr->sh_offset, (size_t) shdr->sh_size, NULL);
+      edta->d_flags = shdr->sh_flags;
+      edta->d_size = ((edta->d_buf == NULL) || (shdr->sh_type == SHT_NOBITS)) ? 0 : shdr->sh_size;
+      edta->d_off = shdr->sh_offset;
+      edta->d_align = shdr->sh_addralign;
+    }
+  return edta;
+}
+
+int64_t
+Elf::elf_checksum ()
+{
+  if (ehdrp == NULL)
+    return 0;
+  int64_t chk = 0;
+  for (unsigned int ndx = 0; ndx < ehdrp->e_phnum; ndx++)
+    {
+      Elf_Internal_Phdr *phdr = get_phdr (ndx);
+      if (phdr == NULL)
+       continue;
+      if (phdr->p_type == PT_DYNAMIC)
+       {
+         Elf64_Dyn edyn;
+         for (unsigned int i = 0; elf_getdyn (phdr, i, &edyn) != NULL; i++)
+           {
+             if (!edyn.d_tag)
+               break;
+             if (edyn.d_tag == DT_CHECKSUM)
+               {
+                 chk = edyn.d_un.d_val;
+                 break;
+               }
+           }
+       }
+    }
+  return normalize_checksum (chk);
+}
+
+uint64_t
+Elf::get_baseAddr ()
+{
+  uint64_t addr = 0;
+  for (unsigned int pnum = 0; pnum < elf_getehdr ()->e_phnum; pnum++)
+    {
+      Elf_Internal_Phdr *phdr = get_phdr (pnum);
+      if (phdr->p_type == PT_LOAD && phdr->p_flags == (PF_R | PF_X))
+       {
+         if (addr == 0)
+           addr = phdr->p_vaddr;
+         else
+           {
+             addr = 0;
+             break;
+           }
+       }
+    }
+  return addr;
+}
+
+char *
+Elf::elf_strptr (unsigned int sec, uint64_t off)
+{
+  Elf_Data *edta = elf_getdata (sec);
+  if (edta && edta->d_buf && edta->d_size > off)
+    return ((char *) edta->d_buf) + off;
+  return NULL;
+}
+
+Elf_Internal_Sym *
+Elf::elf_getsym (Elf_Data *edta, unsigned int ndx, Elf_Internal_Sym *dst)
+{
+  if (dst == NULL || edta == NULL)
+    return NULL;
+  if (elf_getclass () == ELFCLASS32)
+    {
+      if (edta->d_size <= ndx * sizeof (Elf32_Sym))
+       return NULL;
+      Elf32_Sym *hdr = (Elf32_Sym*) bind (edta->d_off + ndx * sizeof (Elf32_Sym), sizeof (Elf32_Sym));
+      if (hdr == NULL)
+       return NULL;
+      dst->st_name = decode (hdr->st_name);
+      dst->st_value = decode (hdr->st_value);
+      dst->st_size = decode (hdr->st_size);
+      dst->st_info = ELF64_ST_INFO (ELF32_ST_BIND (decode (hdr->st_info)),
+                                   ELF32_ST_TYPE (decode (hdr->st_info)));
+      dst->st_other = decode (hdr->st_other);
+      dst->st_shndx = decode (hdr->st_shndx);
+    }
+  else
+    {
+      if (edta->d_size <= ndx * sizeof (Elf64_Sym))
+       return NULL;
+      Elf64_Sym *hdr = (Elf64_Sym*) bind (edta->d_off + ndx * sizeof (Elf64_Sym),
+                                         sizeof (Elf64_Sym));
+      if (hdr == NULL)
+       return NULL;
+      dst->st_name = decode (hdr->st_name);
+      dst->st_value = decode (hdr->st_value);
+      dst->st_size = decode (hdr->st_size);
+      dst->st_info = decode (hdr->st_info);
+      dst->st_other = decode (hdr->st_other);
+      dst->st_shndx = decode (hdr->st_shndx);
+    }
+  return dst;
+}
+
+Elf_Internal_Rela *
+Elf::elf_getrel (Elf_Data *edta, unsigned int ndx, Elf_Internal_Rela *dst)
+{
+  if (dst == NULL || edta == NULL || edta->d_buf == NULL)
+    return NULL;
+  if (elf_getclass () == ELFCLASS32)
+    {
+      Elf32_Rel *rel = ((Elf32_Rel *) edta->d_buf) + ndx;
+      dst->r_offset = decode (rel->r_offset);
+      dst->r_info = ELF64_R_INFO (ELF32_R_SYM (decode (rel->r_info)),
+                                 ELF32_R_TYPE (decode (rel->r_info)));
+    }
+  else
+    {
+      Elf64_Rel *rel = ((Elf64_Rel *) edta->d_buf) + ndx;
+      dst->r_offset = decode (rel->r_offset);
+      dst->r_info = decode (rel->r_info);
+    }
+  return dst;
+}
+
+Elf_Internal_Rela *
+Elf::elf_getrela (Elf_Data *edta, unsigned int ndx, Elf_Internal_Rela *dst)
+{
+  if (dst == NULL || edta == NULL || edta->d_buf == NULL)
+    return NULL;
+  if (elf_getclass () == ELFCLASS32)
+    {
+      Elf32_Rela *rela = ((Elf32_Rela *) edta->d_buf) + ndx;
+      dst->r_offset = decode (rela->r_offset);
+      dst->r_addend = decode (rela->r_addend);
+      dst->r_info = ELF64_R_INFO (ELF32_R_SYM (decode (rela->r_info)),
+                                 ELF32_R_TYPE (decode (rela->r_info)));
+    }
+  else
+    {
+      Elf64_Rela *rela = ((Elf64_Rela *) edta->d_buf) + ndx;
+      dst->r_offset = decode (rela->r_offset);
+      dst->r_addend = decode (rela->r_addend);
+      dst->r_info = decode (rela->r_info);
+    }
+  return dst;
+}
+
+Elf64_Ancillary *
+Elf::elf_getancillary (Elf_Data *edta, unsigned int ndx, Elf64_Ancillary *dst)
+{
+  if (dst == NULL || edta == NULL || edta->d_buf == NULL)
+    return NULL;
+  if (elf_getclass () == ELFCLASS32)
+    {
+      Elf32_Ancillary *p = ((Elf32_Ancillary *) edta->d_buf) + ndx;
+      dst->a_tag = decode (p->a_tag);
+      dst->a_un.a_val = decode (p->a_un.a_val);
+    }
+  else
+    {
+      Elf64_Ancillary *p = ((Elf64_Ancillary *) edta->d_buf) + ndx;
+      dst->a_tag = decode (p->a_tag);
+      dst->a_un.a_val = decode (p->a_un.a_val);
+    }
+  return dst;
+}
+
+Elf *
+Elf::get_related_file (const char *lo_name, const char *nm)
+{
+  DbeFile *df;
+  if (*nm == '/')
+    {
+      df = new DbeFile (nm);
+      df->filetype |= (DbeFile::F_FILE | DbeFile::F_DEBUG_FILE);
+    }
+  else
+    {
+      char *bname = get_basename (lo_name);
+      char *fnm = dbe_sprintf ("%.*s/%s", (int) (bname - lo_name), lo_name, nm);
+      df = new DbeFile (fnm);
+      df->filetype |= (DbeFile::F_FILE | DbeFile::F_DEBUG_FILE);
+      free (fnm);
+    }
+  Dprintf (DEBUG_STABS, "get_related_file: %s  -> '%s'\n", nm, df->get_name ());
+  Elf_status st = ELF_ERR_CANT_OPEN_FILE;
+  Elf *elf = elf_begin (df->get_location (), &st);
+  if (elf)
+    {
+      elf->dbeFile = df;
+      return elf;
+    }
+  switch (st)
+    {
+    case ELF_ERR_CANT_OPEN_FILE:
+      append_msg (CMSG_ERROR, GTXT ("Cannot open file `%s'"), df->get_name ());
+      break;
+    case ELF_ERR_BAD_ELF_FORMAT:
+    default:
+      append_msg (CMSG_ERROR, GTXT ("Cannot read ELF header of `%s'"),
+                 df->get_name ());
+      break;
+    }
+  delete df;
+  return NULL;
+}
+
+Elf *
+Elf::find_ancillary_files (char *lo_name)
+{
+  // read the .gnu_debuglink and .SUNW_ancillary seections
+  if (gnu_debug_file)
+    return gnu_debug_file;
+  unsigned int sec = elf_get_sec_num (NTXT (".gnu_debuglink"));
+  if (sec > 0)
+    {
+      Elf_Data *dp = elf_getdata (sec);
+      if (dp)
+       {
+         gnu_debug_file = get_related_file (lo_name, (char *) (dp->d_buf));
+         if (gnu_debug_file)
+           return gnu_debug_file;
+       }
+    }
+
+  sec = elf_get_sec_num (NTXT (".SUNW_ancillary"));
+  if (sec > 0)
+    {
+      Elf_Internal_Shdr *shdr = get_shdr (sec);
+      uint64_t check_sum = 0;
+      char *ancName = NULL;
+      if (shdr)
+       {
+         Elf_Data *dp = elf_getdata (sec);
+         for (int i = 0, sz = (int) (shdr->sh_size / shdr->sh_entsize);
+                 i < sz; i++)
+           {
+             Elf64_Ancillary anc;
+             if (elf_getancillary (dp, i, &anc) == NULL
+                 || anc.a_tag == ANC_SUNW_NULL)
+               break;
+             if (anc.a_tag == ANC_SUNW_MEMBER)
+               ancName = elf_strptr (shdr->sh_link, anc.a_un.a_ptr);
+             else if (anc.a_tag == ANC_SUNW_CHECKSUM)
+               {
+                 if (i == 0)
+                   {
+                     check_sum = anc.a_un.a_val;
+                     continue;
+                   }
+                 if (check_sum == anc.a_un.a_val)
+                   ancName = NULL;
+                 if (ancName)
+                   {
+                     Elf *ancElf = get_related_file (lo_name, ancName);
+                     if (ancElf == NULL)
+                       continue;
+                     int ancSec = ancElf->elf_get_sec_num (".SUNW_ancillary");
+                     if (ancSec > 0)
+                       {
+                         Elf_Internal_Shdr *ancHdr = ancElf->get_shdr (ancSec);
+                         if (ancHdr)
+                           {
+                             Elf_Data *anc_dp = ancElf->elf_getdata (ancSec);
+                             Elf64_Ancillary anc1;
+                             if (ancElf->elf_getancillary (anc_dp, 0, &anc1)
+                                 && (anc1.a_tag == ANC_SUNW_CHECKSUM) &&
+                                 anc1.a_un.a_val == anc.a_un.a_val)
+                               {
+                                 if (ancillary_files == NULL)
+                                   ancillary_files = new Vector<Elf*>(2);
+                                 ancillary_files->append (ancElf);
+                               }
+                             else
+                               append_msg (CMSG_WARN, GTXT ("Load Object: '%s' (checksum Ox%lld). The .anc file '%s' has checksum Ox%llx"),
+                                           STR (fname), (long long) check_sum,
+                                           STR (ancElf->dbeFile->get_location ()),
+                                           (long long) anc1.a_un.a_val);
+                           }
+                       }
+                     ancName = NULL;
+                   }
+               }
+           }
+       }
+    }
+  return NULL;
+}
+
+char*
+Elf::get_location ()
+{
+  return dbeFile ? dbeFile->get_location () : fname;
+}
+
+#define RET_S(x)   if (t == x) return (char *) #x
+
+static char *
+get_elf_class_name (int t)
+{
+  RET_S (ELFCLASSNONE);
+  RET_S (ELFCLASS32);
+  RET_S (ELFCLASS64);
+  return NTXT ("ELFCLASS_UNKNOWN");
+}
+
+static char *
+get_elf_data_name (int t)
+{
+  RET_S (ELFDATANONE);
+  RET_S (ELFDATA2LSB);
+  RET_S (ELFDATA2MSB);
+  return NTXT ("ELFDATA_UNKNOWN");
+}
+
+static char *
+get_elf_osabi_name (int t)
+{
+  RET_S (ELFOSABI_NONE);
+  RET_S (ELFOSABI_HPUX);
+  RET_S (ELFOSABI_NETBSD);
+  RET_S (ELFOSABI_LINUX);
+  RET_S (ELFOSABI_SOLARIS);
+  RET_S (ELFOSABI_AIX);
+  RET_S (ELFOSABI_IRIX);
+  RET_S (ELFOSABI_FREEBSD);
+  RET_S (ELFOSABI_TRU64);
+  RET_S (ELFOSABI_MODESTO);
+  RET_S (ELFOSABI_OPENBSD);
+  return NTXT ("ELFOSABI_UNKNOWN");
+}
+
+static char *
+get_elf_etype_name (int t)
+{
+  RET_S (ET_NONE);
+  RET_S (ET_REL);
+  RET_S (ET_EXEC);
+  RET_S (ET_DYN);
+  RET_S (ET_CORE);
+  RET_S (ET_LOPROC);
+  RET_S (ET_HIPROC);
+  return NTXT ("ETYPE_UNKNOWN");
+}
+
+static char *
+get_elf_ptype_name (int t)
+{
+  RET_S (PT_NULL);
+  RET_S (PT_LOAD);
+  RET_S (PT_DYNAMIC);
+  RET_S (PT_INTERP);
+  RET_S (PT_NOTE);
+  RET_S (PT_SHLIB);
+  RET_S (PT_PHDR);
+  RET_S (PT_TLS);
+  RET_S (PT_LOOS);
+  RET_S (PT_GNU_EH_FRAME);
+  RET_S (PT_GNU_EH_FRAME);
+  RET_S (PT_HIOS);
+  RET_S (PT_LOPROC);
+  RET_S (PT_HIPROC);
+  return NTXT ("PTYPE_UNKNOWN");
+}
+
+static char *
+get_elf_shtype_name (unsigned int t)
+{
+  RET_S (SHT_NULL);
+  RET_S (SHT_PROGBITS);
+  RET_S (SHT_SYMTAB);
+  RET_S (SHT_STRTAB);
+  RET_S (SHT_RELA);
+  RET_S (SHT_HASH);
+  RET_S (SHT_DYNAMIC);
+  RET_S (SHT_NOTE);
+  RET_S (SHT_NOBITS);
+  RET_S (SHT_REL);
+  RET_S (SHT_SHLIB);
+  RET_S (SHT_DYNSYM);
+  RET_S (SHT_INIT_ARRAY);
+  RET_S (SHT_FINI_ARRAY);
+  RET_S (SHT_PREINIT_ARRAY);
+  RET_S (SHT_GROUP);
+  RET_S (SHT_SYMTAB_SHNDX);
+  RET_S (SHT_LOOS);
+  RET_S (SHT_SUNW_verdef);
+  RET_S (SHT_SUNW_verneed);
+  RET_S (SHT_HIOS);
+  RET_S (SHT_LOPROC);
+  RET_S (SHT_HIPROC);
+  RET_S (SHT_LOUSER);
+  RET_S (SHT_HIUSER);
+  return NTXT ("SHTYPE_UNKNOWN");
+}
+
+static char *
+get_elf_machine_name (int t)
+{
+  RET_S (EM_NONE);
+  RET_S (EM_M32);
+  RET_S (EM_SPARC);
+  RET_S (EM_386);
+  RET_S (EM_68K);
+  RET_S (EM_88K);
+  RET_S (EM_860);
+  RET_S (EM_MIPS);
+  RET_S (EM_S370);
+  RET_S (EM_MIPS_RS3_LE);
+  RET_S (EM_SPARC32PLUS);
+  RET_S (EM_960);
+  RET_S (EM_PPC);
+  RET_S (EM_PPC64);
+  RET_S (EM_V800);
+  RET_S (EM_FR20);
+  RET_S (EM_RH32);
+  RET_S (EM_RCE);
+  RET_S (EM_ARM);
+  RET_S (EM_ALPHA);
+  RET_S (EM_SH);
+  RET_S (EM_SPARCV9);
+  RET_S (EM_TRICORE);
+  RET_S (EM_ARC);
+  RET_S (EM_H8_300);
+  RET_S (EM_H8_300H);
+  RET_S (EM_H8S);
+  RET_S (EM_H8_500);
+  RET_S (EM_IA_64);
+  RET_S (EM_MIPS_X);
+  RET_S (EM_COLDFIRE);
+  RET_S (EM_68HC12);
+  RET_S (EM_MMA);
+  RET_S (EM_PCP);
+  RET_S (EM_NCPU);
+  RET_S (EM_NDR1);
+  RET_S (EM_STARCORE);
+  RET_S (EM_ME16);
+  RET_S (EM_ST100);
+  RET_S (EM_TINYJ);
+  RET_S (EM_X86_64);
+  RET_S (EM_PDSP);
+  RET_S (EM_FX66);
+  RET_S (EM_ST9PLUS);
+  RET_S (EM_ST7);
+  RET_S (EM_68HC16);
+  RET_S (EM_68HC11);
+  RET_S (EM_68HC08);
+  RET_S (EM_68HC05);
+  RET_S (EM_SVX);
+  RET_S (EM_ST19);
+  RET_S (EM_VAX);
+  RET_S (EM_CRIS);
+  RET_S (EM_JAVELIN);
+  RET_S (EM_FIREPATH);
+  RET_S (EM_ZSP);
+  RET_S (EM_MMIX);
+  RET_S (EM_HUANY);
+  RET_S (EM_PRISM);
+  RET_S (EM_AVR);
+  RET_S (EM_FR30);
+  RET_S (EM_D10V);
+  RET_S (EM_D30V);
+  RET_S (EM_V850);
+  RET_S (EM_M32R);
+  RET_S (EM_MN10300);
+  RET_S (EM_MN10200);
+  RET_S (EM_PJ);
+  RET_S (EM_OPENRISC);
+  RET_S (EM_XTENSA);
+  return NTXT ("ELFMACHINE_UNKNOWN");
+}
+
+static char *
+get_elf_version_name (int t)
+{
+  RET_S (EV_NONE);
+  RET_S (EV_CURRENT);
+  return NTXT ("VERSION_UNKNOWN");
+}
+
+static char *
+get_elf_ancillary_tag (int t)
+{
+  RET_S (ANC_SUNW_NULL);
+  RET_S (ANC_SUNW_CHECKSUM);
+  RET_S (ANC_SUNW_MEMBER);
+  RET_S (ANC_SUNW_NUM);
+  return NTXT ("ANCILLARY_TAG_UNKNOWN");
+}
+
+#define ADD_S(x)    if ((f & (x)) == (x)) { sb->append(' '); sb->append(#x); f &= ~(x); }
+
+static void
+dump_sh_flags (StringBuilder *sb, long long flags)
+{
+  long long f = flags;
+  if (f != 0)
+    {
+      sb->append (NTXT (" ["));
+      ADD_S (SHF_WRITE)
+      ADD_S (SHF_ALLOC)
+      ADD_S (SHF_EXECINSTR)
+      ADD_S (SHF_MERGE)
+      ADD_S (SHF_STRINGS)
+      ADD_S (SHF_INFO_LINK)
+      ADD_S (SHF_LINK_ORDER)
+      ADD_S (SHF_OS_NONCONFORMING)
+      ADD_S (SHF_GROUP)
+      ADD_S (SHF_TLS)
+      ADD_S (SHF_SUNW_ABSENT)
+      ADD_S (SHF_EXCLUDE)
+      if (f != 0 && f != flags)
+       sb->appendf (NTXT (" 0x%llx"), (long long) f);
+      sb->append (NTXT (" ]"));
+    }
+  sb->append (NTXT ("\n"));
+}
+
+static void
+dump_p_flags (StringBuilder *sb, long long flags)
+{
+  long long f = flags;
+  if (f != 0)
+    {
+      sb->append (NTXT (" ["));
+      ADD_S (PF_X)
+      ADD_S (PF_W)
+      ADD_S (PF_R)
+      ADD_S (PF_MASKPROC)
+      if (f != 0 && f != flags)
+       sb->appendf (NTXT (" 0x%llx"), (long long) f);
+      sb->append (NTXT (" ]"));
+    }
+  sb->append (NTXT ("\n"));
+}
+
+char *
+Elf::dump ()
+{
+  StringBuilder sb;
+  sb.sprintf (NTXT ("ELF Header: %s\n"), fname ? fname : GTXT ("(unknown)"));
+  if (ehdrp == NULL)
+    {
+      sb.appendf (GTXT ("\n\n Cannot read Elf header\n"));
+      return sb.toString ();
+    }
+  sb.appendf (NTXT ("  %-15s "), NTXT ("e_ident"));
+  for (int i = 0; i < EI_NIDENT; i++)
+    sb.appendf (NTXT ("%x"), ehdrp->e_ident[i]);
+  sb.append (NTXT ("\n"));
+  char *fmt0 = NTXT ("  %-15s %10lld ( %s )\n");
+  char *fmt1 = NTXT ("  %-15s 0x%08llx ( %lld )\n");
+  char *fmt2 = NTXT ("  %-15s 0x%08llx");
+  sb.appendf (fmt0, NTXT ("EI_CLASS"), (long long) ehdrp->e_ident[EI_CLASS],
+             get_elf_class_name (ehdrp->e_ident[EI_CLASS]));
+  sb.appendf (fmt0, NTXT ("EI_DATA"), (long long) ehdrp->e_ident[EI_DATA],
+             get_elf_data_name (ehdrp->e_ident[EI_DATA]));
+  sb.appendf (fmt0, NTXT ("EI_OSABI"), (long long) ehdrp->e_ident[EI_OSABI],
+             get_elf_osabi_name (ehdrp->e_ident[EI_OSABI]));
+  sb.appendf (fmt0, NTXT ("e_type"), (long long) ehdrp->e_type,
+             get_elf_etype_name (ehdrp->e_type));
+  sb.appendf (fmt0, NTXT ("e_machine"), (long long) ehdrp->e_machine,
+             get_elf_machine_name (ehdrp->e_machine));
+  sb.appendf (fmt0, NTXT ("e_version"), (long long) ehdrp->e_version,
+             get_elf_version_name (ehdrp->e_version));
+  sb.appendf (fmt1, NTXT ("e_entry"), (long long) ehdrp->e_entry,
+             (long long) ehdrp->e_entry);
+  sb.appendf (fmt1, NTXT ("e_phoff"), (long long) ehdrp->e_phoff,
+             (long long) ehdrp->e_phoff);
+  sb.appendf (fmt1, NTXT ("e_shoff"), (long long) ehdrp->e_shoff,
+             (long long) ehdrp->e_shoff);
+  sb.appendf (fmt1, NTXT ("e_flags"), (long long) ehdrp->e_flags,
+             (long long) ehdrp->e_flags);
+  sb.appendf (fmt1, NTXT ("e_ehsize"), (long long) ehdrp->e_ehsize,
+             (long long) ehdrp->e_ehsize);
+  sb.appendf (fmt1, NTXT ("e_phentsize"), (long long) ehdrp->e_phentsize,
+             (long long) ehdrp->e_phentsize);
+  sb.appendf (fmt1, NTXT ("e_phnum"), (long long) ehdrp->e_phnum,
+             (long long) ehdrp->e_phnum);
+  sb.appendf (fmt1, NTXT ("e_shentsize"), (long long) ehdrp->e_shentsize,
+             (long long) ehdrp->e_shentsize);
+  sb.appendf (fmt1, NTXT ("e_shnum"), (long long) ehdrp->e_shnum,
+             (long long) ehdrp->e_shnum);
+  sb.appendf (fmt1, NTXT ("e_shstrndx"), (long long) ehdrp->e_shstrndx,
+             (long long) ehdrp->e_shstrndx);
+
+  for (unsigned int i = 0; i < ehdrp->e_phnum; i++)
+    {
+      sb.appendf (NTXT ("\nProgram Header[%d]:\n"), i);
+      Elf_Internal_Phdr *phdr = get_phdr (i);
+      if (phdr == NULL)
+       {
+         sb.appendf (NTXT ("      ERROR: get_phdr(%d) failed\n"), i);
+         continue;
+       }
+      sb.appendf (fmt0, "p_type", (long long) phdr->p_type,
+                 get_elf_ptype_name (phdr->p_type));
+      sb.appendf (fmt2, "p_flags", (long long) phdr->p_flags);
+      dump_p_flags (&sb, phdr->p_flags);
+      sb.appendf (fmt1, "p_offset", (long long) phdr->p_offset,
+                 (long long) phdr->p_offset);
+      sb.appendf (fmt1, "p_vaddr", (long long) phdr->p_vaddr,
+                 (long long) phdr->p_vaddr);
+      sb.appendf (fmt1, "p_paddr", (long long) phdr->p_paddr,
+                 (long long) phdr->p_paddr);
+      sb.appendf (fmt1, "p_filesz", (long long) phdr->p_filesz,
+                 (long long) phdr->p_filesz);
+      sb.appendf (fmt1, "p_memsz", (long long) phdr->p_memsz,
+                 (long long) phdr->p_memsz);
+      sb.appendf (fmt1, "p_align", (long long) phdr->p_align,
+                 (long long) phdr->p_align);
+    }
+
+  for (unsigned int i = 1; i < ehdrp->e_shnum; i++)
+    {
+      sb.appendf (NTXT ("\nSection Header[%d]:\n"), i);
+      Elf_Internal_Shdr *shdr = get_shdr (i);
+      if (shdr == NULL)
+       {
+         sb.appendf (NTXT ("      ERROR: get_shdr(%d) failed\n"), i);
+         continue;
+       }
+      char *s = get_sec_name (i);
+      sb.appendf (fmt0, "sh_name", (long long) shdr->sh_name,
+                 s ? s : NTXT ("NULL"));
+      sb.appendf (fmt0, "sh_type", (long long) shdr->sh_type,
+                 get_elf_shtype_name (shdr->sh_type));
+      sb.appendf (fmt2, "sh_flags", (long long) shdr->sh_flags);
+      dump_sh_flags (&sb, shdr->sh_flags);
+      sb.appendf (fmt1, "sh_addr", (long long) shdr->sh_addr,
+                 (long long) shdr->sh_addr);
+      sb.appendf (fmt1, "sh_offset", (long long) shdr->sh_offset,
+                 (long long) shdr->sh_offset);
+      sb.appendf (fmt1, "sh_size", (long long) shdr->sh_size,
+                 (long long) shdr->sh_size);
+      sb.appendf (fmt1, "sh_link", (long long) shdr->sh_link,
+                 (long long) shdr->sh_link);
+      sb.appendf (fmt1, "sh_info", (long long) shdr->sh_info,
+                 (long long) shdr->sh_info);
+      sb.appendf (fmt1, "sh_addralign", (long long) shdr->sh_addralign,
+                 (long long) shdr->sh_addralign);
+      sb.appendf (fmt1, "sh_entsize", (long long) shdr->sh_entsize,
+                 (long long) shdr->sh_entsize);
+    }
+
+  for (unsigned int i = 1; i < ehdrp->e_shnum; i++)
+    {
+      Elf_Internal_Shdr *shdr = get_shdr (i);
+      if (shdr == NULL)
+       continue;
+      char *secName = get_sec_name (i);
+      if (secName == NULL)
+       continue;
+      if (strcmp (NTXT (".SUNW_ancillary"), secName) == 0)
+       {
+         sb.appendf (NTXT ("\nSection[%d]:  %s\n"), i, secName);
+         Elf_Data *dp = elf_getdata (i);
+         for (int j = 0, cnt = (int) (shdr->sh_size / shdr->sh_entsize);
+                 j < cnt; j++)
+           {
+             Elf64_Ancillary anc;
+             if (elf_getancillary (dp, j, &anc) == NULL)
+               break;
+             sb.appendf (NTXT ("%10d  %-20s 0x%08llx %6lld"), j,
+                         get_elf_ancillary_tag ((int) anc.a_tag),
+                         (long long) anc.a_un.a_ptr, (long long) anc.a_un.a_ptr);
+             if (anc.a_tag == ANC_SUNW_MEMBER)
+               sb.appendf (NTXT ("  %s\n"), STR (elf_strptr (shdr->sh_link, anc.a_un.a_ptr)));
+             else
+               sb.append (NTXT ("\n"));
+           }
+       }
+    }
+  return sb.toString ();
+}
+
+void
+Elf::dump_elf_sec ()
+{
+  if (!DUMP_ELF_SEC)
+    return;
+  if (ehdrp == NULL)
+    return;
+  Dprintf (DUMP_ELF_SEC, "======= DwarfLib::dump_elf_sec\n"
+          " N |type|flags|  sh_addr | sh_offset | sh_size | sh_link |"
+          " sh_info | sh_addralign | sh_entsize | sh_name | name\n");
+  for (unsigned int sec = 1; sec < ehdrp->e_shnum; sec++)
+    {
+      Elf_Internal_Shdr *shdr = get_shdr (sec);
+      if (shdr == NULL)
+       continue;
+      char *name = elf_strptr (ehdrp->e_shstrndx, shdr->sh_name);
+      Dprintf (DUMP_ELF_SEC, "%3d:%3d |%4d |%9lld | %9lld |%8lld |%8lld |"
+              "%8lld |%14d |%11lld | %6lld %s\n",
+              sec, (int) shdr->sh_type, (int) shdr->sh_flags,
+              (long long) shdr->sh_addr, (long long) shdr->sh_offset,
+              (long long) shdr->sh_size, (long long) shdr->sh_link,
+              (long long) shdr->sh_info,
+              (int) shdr->sh_addralign, (long long) shdr->sh_entsize,
+              (long long) shdr->sh_name, name ? name : NTXT ("NULL"));
+    }
+  Dprintf (DUMP_ELF_SEC, NTXT ("\n"));
+}
diff --git a/gprofng/src/Elf.h b/gprofng/src/Elf.h
new file mode 100644 (file)
index 0000000..3648b88
--- /dev/null
@@ -0,0 +1,170 @@
+/* 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 _Elf_h_
+#define        _Elf_h_
+
+#include <string.h>
+#include "ansidecl.h"
+#include "bfd.h"
+#include "elf/common.h"
+#include "elf/internal.h"
+
+#include "Data_window.h"
+#include "Emsg.h"
+
+class Symbol;
+class DbeFile;
+template <class ITEM> class Vector;
+template <typename Key_t, typename Value_t> class Map;
+
+#define GELF_R_SYM(info)    ((info)>>32)
+#define GELF_ST_TYPE(info)  ((info) & 0xf)
+#define GELF_ST_BIND(info)  ((info) >> 4)
+#define GELF_R_TYPE(info)   ((((uint64_t)(info))<<56)>>56)
+
+#define        SHF_SUNW_ABSENT         0x00200000      /* section data not present */
+
+// Ancillary values.
+#define ANC_SUNW_NULL       0
+#define ANC_SUNW_CHECKSUM   1   /* elf checksum */
+#define ANC_SUNW_MEMBER     2   /* name of ancillary group object */
+#define ANC_SUNW_NUM        3
+
+
+typedef struct S_Elf64_Dyn Elf64_Dyn;
+typedef struct S_Elf64_Ancillary Elf64_Ancillary;
+
+typedef struct
+{
+  void *d_buf;
+  uint64_t d_flags;
+  uint64_t d_size;
+  uint64_t d_off;       // offset into section
+  uint64_t d_align;     // alignment in section
+} Elf_Data;
+
+class Elf : public DbeMessages, public Data_window
+{
+public:
+  enum Elf_status
+  {
+    ELF_ERR_NONE,
+    ELF_ERR_CANT_OPEN_FILE,
+    ELF_ERR_CANT_MMAP,
+    ELF_ERR_BIG_FILE,
+    ELF_ERR_BAD_ELF_FORMAT,
+    ELF_ERR_READ_FILE
+  };
+
+  Elf (char *_fname);
+  ~Elf ();
+
+  static void elf_init ();
+  static unsigned elf_version (unsigned ver);
+  static Elf *elf_begin (char *_fname, Elf_status *stp = NULL);
+
+  unsigned int elf_get_sec_num (const char *sec_name);
+  char *get_sec_name (unsigned int sec);
+  Elf_Internal_Ehdr *elf_getehdr ();
+  Elf_Internal_Phdr *get_phdr (unsigned int ndx);
+  Elf_Internal_Shdr *get_shdr (unsigned int ndx);
+  Elf64_Dyn *elf_getdyn (Elf_Internal_Phdr *phdr, unsigned int ndx, Elf64_Dyn *pdyn);
+  Elf_Data *elf_getdata (unsigned int sec);
+  int64_t elf_checksum ();
+  uint64_t get_baseAddr();
+  char *elf_strptr (unsigned int sec, uint64_t off);
+  Elf_Internal_Sym *elf_getsym (Elf_Data *edta, unsigned int ndx, Elf_Internal_Sym *dst);
+  Elf_Internal_Rela *elf_getrel (Elf_Data *edta, unsigned int ndx, Elf_Internal_Rela *dst);
+  Elf_Internal_Rela *elf_getrela (Elf_Data *edta, unsigned int ndx, Elf_Internal_Rela *dst);
+  Elf64_Ancillary *elf_getancillary (Elf_Data *edta, unsigned int ndx, Elf64_Ancillary *dst);
+  Elf *find_ancillary_files (char *lo_name); // read the .gnu_debuglink and .SUNW_ancillary seections
+  char *get_location ();
+  char *dump ();
+  void dump_elf_sec ();
+
+  static inline int64_t
+  normalize_checksum (int64_t chk)
+  {
+    return (chk == 0xffffffff || chk == -1) ? 0 : chk;
+  };
+
+  inline bool
+  is_Intel ()
+  {
+    return elf_datatype == ELFDATA2LSB;
+  };
+
+  inline int
+  elf_getclass ()
+  {
+    return elf_class;
+  };
+
+  inline int
+  elf_getdatatype ()
+  {
+    return elf_datatype;
+  };
+
+  Elf_status status;
+  Vector<Elf*> *ancillary_files;
+  Elf *gnu_debug_file;
+  DbeFile *dbeFile;
+  Map<const char*, Symbol*> *elfSymbols;
+  unsigned int gnuLink, analyzerInfo, SUNW_ldynsym, stab, stabStr, symtab, dynsym;
+  unsigned int stabIndex, stabIndexStr, stabExcl, stabExclStr, info, plt;
+  bool dwarf;
+
+protected:
+  Elf *get_related_file (const char *lo_name, const char *nm);
+  int elf_class;
+  int elf_datatype;
+  Elf_Internal_Ehdr *ehdrp;
+  Elf_Data **data;
+  bfd *abfd;
+  static int bfd_status;
+};
+
+
+class ElfReloc
+{
+public:
+  struct Sreloc
+  {
+    long long offset;
+    long long value;
+    int stt_type;
+  };
+
+  static ElfReloc *get_elf_reloc (Elf *elf, char *sec_name, ElfReloc *rlc);
+  ElfReloc (Elf *_elf);
+  ~ElfReloc ();
+  long long get_reloc_addr (long long offset);
+  void dump ();
+  void dump_rela_debug_sec (int sec);
+
+private:
+  Elf *elf;
+  Vector<Sreloc *> *reloc;
+  int cur_reloc_ind;
+};
+
+#endif
diff --git a/gprofng/src/Emsg.cc b/gprofng/src/Emsg.cc
new file mode 100644 (file)
index 0000000..11bad97
--- /dev/null
@@ -0,0 +1,614 @@
+/* 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 <stdarg.h>
+
+#include "util.h"
+#include "Emsg.h"
+#include "StringBuilder.h"
+
+// The Emsg, experiment message, has as objects I18N'd messages
+//     in a structure suitable for attaching to and fetching
+//     from a queue of such messages.  It is intended to
+//     be used for collector errors, collector warnings, parser
+//     errors, and er_archive errors that are encountered when
+//     reading an experiment
+
+// ----------------------- Message --------------------------
+
+Emsg::Emsg (Cmsg_warn w, const char *i18n_text)
+{
+  warn = w;
+  flavor = 0;
+  par = NULL;
+  text = strdup (i18n_text);
+  next = NULL;
+}
+
+Emsg::Emsg (Cmsg_warn w, StringBuilder& sb)
+{
+  warn = w;
+  flavor = 0;
+  par = NULL;
+  text = sb.toString ();
+  next = NULL;
+}
+
+Emsg::Emsg (Cmsg_warn w, int f, const char *param)
+{
+  char *type;
+  warn = w;
+  flavor = f;
+  if (param != NULL)
+    par = dbe_strdup (param);
+  else
+    par = dbe_strdup ("");
+  next = NULL;
+
+  // determine type
+  switch (warn)
+    {
+    case CMSG_WARN:
+      type = GTXT ("*** Collector Warning");
+      break;
+    case CMSG_ERROR:
+      type = GTXT ("*** Collector Error");
+      break;
+    case CMSG_FATAL:
+      type = GTXT ("*** Collector Fatal Error");
+      break;
+    case CMSG_COMMENT:
+      type = GTXT ("Comment");
+      break;
+    case CMSG_PARSER:
+      type = GTXT ("*** Log Error");
+      break;
+    case CMSG_ARCHIVE:
+      type = GTXT ("*** Archive Error");
+      break;
+    default:
+      type = GTXT ("*** Internal Error");
+      break;
+    };
+
+  // now convert the message to its I18N'd string
+  switch (flavor)
+    {
+    case COL_ERROR_NONE:
+      text = dbe_sprintf (GTXT ("%s: No error"), type);
+      break;
+    case COL_ERROR_ARGS2BIG:
+      text = dbe_sprintf (GTXT ("%s: Data argument too long"), type);
+      break;
+    case COL_ERROR_BADDIR:
+      text = dbe_sprintf (GTXT ("%s: Bad experiment directory name"), type);
+      break;
+    case COL_ERROR_ARGS:
+      text = dbe_sprintf (GTXT ("%s: Data argument format error `%s'"), type, par);
+      break;
+    case COL_ERROR_PROFARGS:
+      text = dbe_sprintf (GTXT ("%s: [UNUSED] Bad clock-profiling argument"), type);
+      break;
+    case COL_ERROR_SYNCARGS:
+      text = dbe_sprintf (GTXT ("%s: [UNUSED] Bad synchronization tracing argument"), type);
+      break;
+    case COL_ERROR_HWCARGS:
+      text = dbe_sprintf (GTXT ("%s: Bad hardware counter profiling argument"), type);
+      break;
+    case COL_ERROR_DIRPERM:
+      text = dbe_sprintf (GTXT ("%s: Experiment directory is not writeable; check umask and permissions"), type);
+      break;
+    case COL_ERROR_NOMSACCT:
+      text = dbe_sprintf (GTXT ("%s: Turning on microstate accounting failed"), type);
+      break;
+    case COL_ERROR_PROFINIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing clock-profiling failed"), type);
+      break;
+    case COL_ERROR_SYNCINIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing synchronization tracing failed"), type);
+      break;
+    case COL_ERROR_HWCINIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing hardware counter profiling failed -- %s"), type, par);
+      break;
+    case COL_ERROR_HWCFAIL:
+      text = dbe_sprintf (GTXT ("%s: HW counter data collection failed; likely cause is that another process preempted the counters"), type);
+      break;
+    case COL_ERROR_EXPOPEN:
+      text = dbe_sprintf (GTXT ("%s: Experiment initialization failed, %s"), type, par);
+      break;
+    case COL_ERROR_SIZELIM:
+      text = dbe_sprintf (GTXT ("%s: Experiment size limit exceeded, writing %s"), type, par);
+      break;
+    case COL_ERROR_SYSINFO:
+      text = dbe_sprintf (GTXT ("%s: system name can not be determined"), type);
+      break;
+    case COL_ERROR_OVWOPEN:
+      text = dbe_sprintf (GTXT ("%s: Can't open overview %s"), type, par);
+      break;
+    case COL_ERROR_OVWWRITE:
+      text = dbe_sprintf (GTXT ("%s: Can't write overview %s"), type, par);
+      break;
+    case COL_ERROR_OVWREAD:
+      text = dbe_sprintf (GTXT ("%s: Can't read overview data for %s"), type, par);
+      break;
+    case COL_ERROR_NOZMEM:
+      text = dbe_sprintf (GTXT ("%s: Open of /dev/zero failed: %s"), type, par);
+      break;
+    case COL_ERROR_NOZMEMMAP:
+      text = dbe_sprintf (GTXT ("%s: Mmap of /dev/zero failed: %s"), type, par);
+      break;
+    case COL_ERROR_NOHNDL:
+      text = dbe_sprintf (GTXT ("%s: Out of data handles for %s"), type, par);
+      break;
+    case COL_ERROR_FILEOPN:
+      text = dbe_sprintf (GTXT ("%s: Open failed %s"), type, par);
+      break;
+    case COL_ERROR_FILETRNC:
+      text = dbe_sprintf (GTXT ("%s: Truncate failed for file %s"), type, par);
+      break;
+    case COL_ERROR_FILEMAP:
+      text = dbe_sprintf (GTXT ("%s: Mmap failed %s"), type, par);
+      break;
+    case COL_ERROR_HEAPINIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing heap tracing failed"), type);
+      break;
+    case COL_ERROR_DISPINIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing SIGPROF dispatcher failed"), type);
+      break;
+    case COL_ERROR_ITMRINIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing interval timer failed; %s"), type, par);
+      break;
+    case COL_ERROR_SMPLINIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing periodic sampling failed"), type);
+      break;
+    case COL_ERROR_MPIINIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing MPI tracing failed"), type);
+      break;
+    case COL_ERROR_JAVAINIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing Java profiling failed"), type);
+      break;
+    case COL_ERROR_LINEINIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing descendant process lineage failed"), type);
+      break;
+    case COL_ERROR_NOSPACE:
+      text = dbe_sprintf (GTXT ("%s: Out of disk space writing `%s'"), type, par);
+      break;
+    case COL_ERROR_ITMRRST:
+      text = dbe_sprintf (GTXT ("%s: Resetting interval timer failed: %s"), type, par);
+      break;
+    case COL_ERROR_MKDIR:
+      text = dbe_sprintf (GTXT ("%s: Unable to create directory `%s'"), type, par);
+      break;
+    case COL_ERROR_JVM2NEW:
+      text = dbe_sprintf (GTXT ("%s: JVM version with JVMTI requires more recent release of the performance tools; please upgrade"), type);
+      break;
+    case COL_ERROR_JVMNOTSUPP:
+      text = dbe_sprintf (GTXT ("%s: JVM version does not support JVMTI; no java profiling is available"), type);
+      break;
+    case COL_ERROR_JVMNOJSTACK:
+      text = dbe_sprintf (GTXT ("%s: JVM version does not support java callstacks; java mode data will not be recorded"), type);
+      break;
+    case COL_ERROR_DYNOPEN:
+      text = dbe_sprintf (GTXT ("%s: Can't open dyntext file `%s'"), type, par);
+      break;
+    case COL_ERROR_DYNWRITE:
+      text = dbe_sprintf (GTXT ("%s: Can't write dyntext file `%s'"), type, par);
+      break;
+    case COL_ERROR_MAPOPEN:
+      text = dbe_sprintf (GTXT ("%s: Can't open map file `%s'"), type, par);
+      break;
+    case COL_ERROR_MAPREAD:
+      text = dbe_sprintf (GTXT ("%s: Can't read map file `%s'"), type, par);
+      break;
+    case COL_ERROR_MAPWRITE:
+      text = dbe_sprintf (GTXT ("%s: Can't write map file"), type);
+      break;
+    case COL_ERROR_RESOLVE:
+      text = dbe_sprintf (GTXT ("%s: Can't resolve map file `%s'"), type, par);
+      break;
+    case COL_ERROR_OMPINIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing OpenMP tracing failed"), type);
+      break;
+    case COL_ERROR_DURATION_INIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing experiment-duration setting to `%s' failed"), type, par);
+      break;
+    case COL_ERROR_RDTINIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing RDT failed"), type);
+      break;
+    case COL_ERROR_GENERAL:
+      if (strlen (par))
+       text = dbe_sprintf (GTXT ("%s: %s"), type, par);
+      else
+       text = dbe_sprintf (GTXT ("%s: General error"), type);
+      break;
+    case COL_ERROR_EXEC_FAIL:
+      text = dbe_sprintf (GTXT ("%s: Exec of process failed"), type);
+      break;
+    case COL_ERROR_THR_MAX:
+      text = dbe_sprintf (GTXT ("%s: Thread count exceeds maximum (%s); set SP_COLLECTOR_NUMTHREADS for higher value"), type, par);
+      break;
+    case COL_ERROR_IOINIT:
+      text = dbe_sprintf (GTXT ("%s: Initializing IO tracing failed"), type);
+      break;
+    case COL_ERROR_NODATA:
+      text = dbe_sprintf (GTXT ("%s: No data was recorded in the experiment"), type);
+      break;
+    case COL_ERROR_DTRACE_FATAL:
+      text = dbe_sprintf (GTXT ("%s: Fatal error reported from DTrace -- %s"), type, par);
+      break;
+    case COL_ERROR_MAPSEEK:
+      text = dbe_sprintf (GTXT ("%s: Seek error on map file `%s'"), type, par);
+      break;
+    case COL_ERROR_UNEXP_FOUNDER:
+      text = dbe_sprintf (GTXT ("%s: Unexpected value for founder `%s'"), type, par);
+      break;
+    case COL_ERROR_LOG_OPEN:
+      text = dbe_sprintf (GTXT ("%s: Failure to open log file"), type);
+      break;
+    case COL_ERROR_TSD_INIT:
+      text = dbe_sprintf (GTXT ("%s: TSD could not be initialized"), type);
+      break;
+    case COL_ERROR_UTIL_INIT:
+      text = dbe_sprintf (GTXT ("%s: libcol_util.c initialization failed"), type);
+      break;
+    case COL_ERROR_MAPCACHE:
+      text = dbe_sprintf (GTXT ("%s: Unable to cache mappings;  internal error (`%s')"), type, par);
+      break;
+    case COL_WARN_NONE:
+      text = dbe_sprintf (GTXT ("%s: No warning"), type);
+      break;
+    case COL_WARN_FSTYPE:
+      text = dbe_sprintf (GTXT ("%s: Experiment was written to a filesystem of type `%s'; data may be distorted"), type, par);
+      break;
+    case COL_WARN_PROFRND:
+      text = dbe_sprintf (GTXT ("%s: Profiling interval was changed from requested %s (microsecs.) used"), type, par);
+      break;
+    case COL_WARN_SIZELIM:
+      text = dbe_sprintf (GTXT ("%s: Experiment size limit exceeded"), type);
+      break;
+    case COL_WARN_SIGPROF:
+      text = dbe_sprintf (GTXT ("%s: SIGPROF handler was changed (%s) during the run; profile data may be unreliable"), type, par);
+      break;
+    case COL_WARN_SMPLADJ:
+      text = dbe_sprintf (GTXT ("%s: Periodic sampling rate adjusted %s microseconds"), type, par);
+      break;
+    case COL_WARN_ITMROVR:
+      text = dbe_sprintf (GTXT ("%s: Application's attempt to set interval timer period to %s was ignored; its behavior may be changed"), type, par);
+      break;
+    case COL_WARN_ITMRREP:
+      text = dbe_sprintf (GTXT ("%s: Collection interval timer period was changed (%s); profile data may be unreliable"), type, par);
+      break;
+    case COL_WARN_SIGEMT:
+      text = dbe_sprintf (GTXT ("%s: SIGEMT handler was changed during the run; profile data may be unreliable"), type);
+      break;
+    case COL_WARN_CPCBLK:
+      text = dbe_sprintf (GTXT ("%s: libcpc access blocked for hardware counter profiling"), type);
+      break;
+    case COL_WARN_VFORK:
+      text = dbe_sprintf (GTXT ("%s: vfork(2) replaced by %s; execution may be affected"), type, par);
+      break;
+    case COL_WARN_EXECENV:
+      text = dbe_sprintf (GTXT ("%s: exec environment augmented with %s missing collection variables"), type, par);
+      break;
+    case COL_WARN_SAMPSIGUSED:
+      text = dbe_sprintf (GTXT ("%s: target installed handler for sample signal %s; samples may be lost"), type, par);
+      break;
+    case COL_WARN_PAUSESIGUSED:
+      text = dbe_sprintf (GTXT ("%s: target installed handler for pause/resume signal %s; data may be lost or unexpected"),
+                         type, par);
+      break;
+    case COL_WARN_CPCNOTRESERVED:
+      text = dbe_sprintf (GTXT ("%s: unable to reserve HW counters; data may be distorted by other users of the counters"), type);
+      break;
+    case COL_WARN_LIBTHREAD_T1: /* par contains the aslwpid... do we want to report it? */
+      text = dbe_sprintf (GTXT ("%s: application ran with a libthread version that may distort data; see collect(1) man page"), type);
+      break;
+    case COL_WARN_SIGMASK:
+      text = dbe_sprintf (GTXT ("%s: Blocking %s ignored while in use for collection"), type, par);
+      break;
+    case COL_WARN_NOFOLLOW:
+      text = dbe_sprintf (GTXT ("%s: Following disabled for uncollectable target (%s)"), type, par);
+      break;
+    case COL_WARN_RISKYFOLLOW:
+      text = dbe_sprintf (GTXT ("%s: Following unqualified target may be unreliable (%s)"), type, par);
+      break;
+    case COL_WARN_IDCHNG:
+      text = dbe_sprintf (GTXT ("%s: Imminent process ID change (%s) may result in an inconsistent experiment"), type, par);
+      break;
+    case COL_WARN_OLDJAVA:
+      text = dbe_sprintf (GTXT ("%s: Java profiling requires JVM version 1.4.2_02 or later"), type);
+      break;
+    case COL_WARN_ITMRPOVR:
+      text = dbe_sprintf (GTXT ("%s: Collector reset application's profile timer %s; application behavior may be changed"), type, par);
+      break;
+    case COL_WARN_NO_JAVA_HEAP:
+      text = dbe_sprintf (GTXT ("%s: Java heap profiling is not supported by JVMTI; disabled "), type);
+      break;
+    case COL_WARN_RDT_PAUSE_NOMEM:
+      text = dbe_sprintf (GTXT ("%s: Data race detection paused at %s because of running out of internal memory"), type, par);
+      break;
+    case COL_WARN_RDT_RESUME:
+      text = dbe_sprintf (GTXT ("%s: Data race detection resumed"), type);
+      break;
+    case COL_WARN_RDT_THROVER:
+      text = dbe_sprintf (GTXT ("%s: Too many concurrent/created threads;  accesses with thread IDs above limit are not checked"), type);
+      break;
+    case COL_WARN_THR_PAUSE_RESUME:
+      text = dbe_sprintf (GTXT ("%s: The collector_thread_pause/collector_thread_resume APIs are deprecated, and will be removed in a future release"), type);
+      break;
+    case COL_WARN_NOPROF_DATA:
+      text = dbe_sprintf (GTXT ("%s: No profile data recorded in experiment"), type);
+      break;
+    case COL_WARN_LONG_FSTAT:
+      text = dbe_sprintf (GTXT ("%s: Long fstat call -- %s"), type, par);
+      break;
+    case COL_WARN_LONG_READ:
+      text = dbe_sprintf (GTXT ("%s: Long read call -- %s"), type, par);
+      break;
+    case COL_WARN_LINUX_X86_APICID:
+      text = dbe_sprintf (GTXT ("%s: Linux libc sched_getcpu() not found; using x86 %s IDs rather than CPU IDs"), type, par);
+      break;
+
+    case COL_COMMENT_NONE:
+      text = dbe_sprintf (GTXT ("%s"), par);
+      break;
+    case COL_COMMENT_CWD:
+      text = dbe_sprintf (GTXT ("Initial execution directory `%s'"), par);
+      break;
+    case COL_COMMENT_ARGV:
+      text = dbe_sprintf (GTXT ("Argument list `%s'"), par);
+      break;
+    case COL_COMMENT_MAYASSNAP:
+      text = dbe_sprintf (GTXT ("Mayas snap file `%s'"), par);
+      break;
+
+    case COL_COMMENT_LINEFORK:
+      text = dbe_sprintf (GTXT ("Target fork: %s"), par);
+      break;
+    case COL_COMMENT_LINEEXEC:
+      text = dbe_sprintf (GTXT ("Target exec: %s"), par);
+      break;
+    case COL_COMMENT_LINECOMBO:
+      text = dbe_sprintf (GTXT ("Target fork/exec: %s"), par);
+      break;
+    case COL_COMMENT_FOXSNAP:
+      text = dbe_sprintf (GTXT ("Fox snap file `%s'"), par);
+      break;
+    case COL_COMMENT_ROCKSNAP:
+      text = dbe_sprintf (GTXT ("Rock simulator snap file `%s'"), par);
+      break;
+    case COL_COMMENT_BITINSTRDATA:
+      text = dbe_sprintf (GTXT ("Bit instrument data file `%s'"), par);
+      break;
+    case COL_COMMENT_BITSNAP:
+      text = dbe_sprintf (GTXT ("Bit snap file `%s'"), par);
+      break;
+    case COL_COMMENT_SIMDSPSNAP:
+      text = dbe_sprintf (GTXT ("Simulator dataspace profiling snap file `%s'"), par);
+      break;
+    case COL_COMMENT_HWCADJ:
+      text = dbe_sprintf (GTXT ("%s: HWC overflow interval adjusted: %s"), type, par);
+      break;
+    case COL_WARN_APP_NOT_READY:
+      text = dbe_sprintf (GTXT ("*** Collect: %s"), par);
+      break;
+    case COL_WARN_RDT_DL_TERMINATE:
+      text = dbe_sprintf (GTXT ("%s: Actual deadlock detected; process terminated"), type);
+      break;
+    case COL_WARN_RDT_DL_TERMINATE_CORE:
+      text = dbe_sprintf (GTXT ("%s: Actual deadlock detected; process terminated and core dumped"), type);
+      break;
+    case COL_WARN_RDT_DL_CONTINUE:
+      text = dbe_sprintf (GTXT ("%s: Actual deadlock detected; process allowed to continue"), type);
+      break;
+    default:
+      text = dbe_sprintf (GTXT ("%s: Number %d (\"%s\")"), type, flavor, par);
+      break;
+    };
+}
+
+Emsg::~Emsg ()
+{
+  free (par);
+  free (text);
+}
+
+// ----------------------- Message Queue --------------------
+Emsgqueue::Emsgqueue (char *_qname)
+{
+  first = NULL;
+  last = NULL;
+  qname = strdup (_qname);
+}
+
+Emsgqueue::~Emsgqueue ()
+{
+  free (qname);
+  clear ();
+}
+
+Emsg *
+Emsgqueue::find_msg (Cmsg_warn w, char *msg)
+{
+  for (Emsg *m = first; m; m = m->next)
+    if (m->get_warn () == w && strcmp (m->get_msg (), msg) == 0)
+      return m;
+  return NULL;
+}
+
+Emsg *
+Emsgqueue::append (Cmsg_warn w, char *msg)
+{
+  Emsg *m = find_msg (w, msg);
+  if (m)
+    return m;
+  m = new Emsg (w, msg);
+  append (m);
+  return m;
+}
+
+// Append a single message to a queue
+void
+Emsgqueue::append (Emsg* m)
+{
+  m->next = NULL;
+  if (last == NULL)
+    {
+      first = m;
+      last = m;
+    }
+  else
+    {
+      last->next = m;
+      last = m;
+    }
+}
+
+// Append a queue of messages to a queue
+void
+Emsgqueue::appendqueue (Emsgqueue* mq)
+{
+  Emsg *m = mq->first;
+  if (m == NULL)
+    return;
+  if (last == NULL)
+    first = m;
+  else
+    last->next = m;
+  // now find the new last
+  while (m->next != NULL)
+    m = m->next;
+  last = m;
+}
+
+Emsg *
+Emsgqueue::fetch (void)
+{
+  return first;
+}
+
+// Empty the queue, deleting all messages
+void
+Emsgqueue::clear (void)
+{
+  Emsg *pp;
+  Emsg *p = first;
+  while (p != NULL)
+    {
+      pp = p;
+      p = p->next;
+      delete pp;
+    }
+  first = NULL;
+  last = NULL;
+}
+
+// Mark the queue empty, without deleting the messages --
+//     used when the messages have been requeued somewhere else
+void
+Emsgqueue::mark_clear (void)
+{
+  first = NULL;
+  last = NULL;
+}
+
+DbeMessages::DbeMessages ()
+{
+  msgs = NULL;
+}
+
+DbeMessages::~DbeMessages ()
+{
+  if (msgs)
+    {
+      msgs->destroy ();
+      delete msgs;
+    }
+}
+
+Emsg *
+DbeMessages::get_error ()
+{
+  for (int i = msgs ? msgs->size () - 1 : -1; i >= 0; i--)
+    {
+      Emsg *msg = msgs->get (i);
+      if (msg->get_warn () == CMSG_ERROR)
+       return msg;
+    }
+  return NULL;
+}
+
+void
+DbeMessages::remove_msg (Emsg *msg)
+{
+  for (int i = 0, sz = msgs ? msgs->size () : 0; i < sz; i++)
+    if (msg == msgs->get (i))
+      {
+       msgs->remove (i);
+       delete msg;
+       return;
+      }
+}
+
+Emsg *
+DbeMessages::append_msg (Cmsg_warn w, const char *fmt, ...)
+{
+  char buffer[256];
+  size_t buf_size;
+  Emsg *msg;
+  va_list vp;
+
+  va_start (vp, fmt);
+  buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
+  va_end (vp);
+  if (buf_size < sizeof (buffer))
+    msg = new Emsg (w, buffer);
+  else
+    {
+      va_start (vp, fmt);
+      char *buf = (char *) malloc (buf_size);
+      vsnprintf (buf, buf_size, fmt, vp);
+      va_end (vp);
+      msg = new Emsg (w, buf);
+      free (buf);
+    }
+
+  if (msgs == NULL)
+    msgs = new Vector<Emsg*>();
+  msgs->append (msg);
+  Dprintf (DEBUG_ERR_MSG, NTXT ("Warning: %s\n"), msg->get_msg ());
+  return msg;
+}
+
+void
+DbeMessages::append_msgs (Vector<Emsg*> *lst)
+{
+  if (lst && (lst->size () != 0))
+    {
+      if (msgs == NULL)
+       msgs = new Vector<Emsg*>();
+      for (int i = 0, sz = lst->size (); i < sz; i++)
+       {
+         Emsg *m = lst->fetch (i);
+         msgs->append (new Emsg (m->get_warn (), m->get_msg ()));
+       }
+    }
+}
diff --git a/gprofng/src/Emsg.h b/gprofng/src/Emsg.h
new file mode 100644 (file)
index 0000000..f1d47c5
--- /dev/null
@@ -0,0 +1,112 @@
+/* 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 _EMSG_H
+#define _EMSG_H
+
+#include "Emsgnum.h"
+#include "vec.h"
+
+//
+// The Emsg, experiment message, has as objects I18N'd messages
+//     in a structure suitable for attaching to and fetching
+//     from a queue of such messages.  It is intended to
+//     be used for collector errors, collector warnings, parser
+//     errors, and er_archive errors that are encountered when
+//     reading an experiment
+
+class Emsg;
+class Emsgqueue;
+class StringBuilder;
+
+typedef enum
+{
+  CMSG_WARN = 0,
+  CMSG_ERROR,
+  CMSG_FATAL,
+  CMSG_COMMENT,
+  CMSG_PARSER,
+  CMSG_ARCHIVE
+} Cmsg_warn;
+
+class Emsg
+{
+public:
+  friend class Emsgqueue;
+
+  Emsg (Cmsg_warn w, const char *i18n_text);
+  Emsg (Cmsg_warn w, StringBuilder& sb);
+  Emsg (Cmsg_warn w, int f, const char *param);
+  ~Emsg ();
+
+  char *
+  get_msg ()
+  {
+    return text;
+  };
+
+  Cmsg_warn
+  get_warn ()
+  {
+    return warn;
+  };
+
+  Emsg *next;       // next message in a queue
+
+protected:
+  Cmsg_warn warn;   // error/warning/...
+  int flavor;       // the message flavor
+  char *par;        // the input parameter string
+  char *text;       // The I18N text of the message
+};
+
+class Emsgqueue
+{
+public:
+  Emsgqueue (char *);
+  ~Emsgqueue ();
+
+  void append (Emsg*);
+  Emsg *append (Cmsg_warn w, char *msg);
+  Emsg *find_msg (Cmsg_warn w, char *msg);
+  void appendqueue (Emsgqueue*);
+  Emsg *fetch (void);
+  void clear (void); // empty the queue
+  void mark_clear (void); // mark the queue empty, without touching messages
+
+protected:
+  Emsg *first;
+  Emsg *last;
+  char *qname;
+};
+
+class DbeMessages
+{
+public:
+  DbeMessages ();
+  ~DbeMessages ();
+  Vector<Emsg*> *msgs;
+  void remove_msg (Emsg *msg);
+  Emsg *get_error ();
+  Emsg *append_msg (Cmsg_warn w, const char *fmt, ...);
+  void append_msgs (Vector<Emsg*> *lst);
+};
+
+#endif  /* _EMSG_H */
diff --git a/gprofng/src/Emsgnum.h b/gprofng/src/Emsgnum.h
new file mode 100644 (file)
index 0000000..cef8332
--- /dev/null
@@ -0,0 +1,135 @@
+/* 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 _EMSGNUM_H
+#define _EMSGNUM_H
+
+// Define numerical codes for all messages and warnings
+
+#define COL_ERROR_NONE                 0       /* OK */
+#define COL_ERROR_ARGS2BIG             1       /* data descriptor too long */
+#define COL_ERROR_BADDIR               2       /* experiment directory error */
+#define COL_ERROR_ARGS                 3       /* data descriptor format error */
+#define COL_ERROR_PROFARGS             4       /* clock profile parameter error */
+#define COL_ERROR_SYNCARGS             5       /* synctrace parameter error */
+#define COL_ERROR_HWCARGS              6       /* HWC profile parameter error */
+#define COL_ERROR_DIRPERM              7       /* experiment directory not writable */
+#define COL_ERROR_NOMSACCT             8       /* failed to turn on microstate accounting */
+#define COL_ERROR_PROFINIT             9       /* failed to initialize profiling */
+#define COL_ERROR_SYNCINIT             10      /* failed to initialize synchronization tracing */
+#define COL_ERROR_HWCINIT              11      /* failed to initialize HWC profiling */
+#define COL_ERROR_HWCFAIL              12      /* HWC profiling failed during run */
+#define COL_ERROR_EXPOPEN              13      /* Experiment initialization failed */
+#define COL_ERROR_SIZELIM              14      /* Experiment exceeded size limit */
+#define COL_ERROR_SYSINFO              15      /* uname call failed */
+#define COL_ERROR_OVWOPEN              16      /* Opening the overview file failed */
+#define COL_ERROR_OVWWRITE             17      /* Writing the overview file failed */
+#define COL_ERROR_OVWREAD              18      /* Reading the overview data failed */
+#define COL_ERROR_NOZMEM               19      /* Unable to open /dev/zero */
+#define COL_ERROR_NOZMEMMAP            20      /* Unable to map /dev/zero */
+#define COL_ERROR_NOHNDL               21      /* No more handles available for data */
+#define COL_ERROR_FILEOPN              22      /* Unable to open file */
+#define COL_ERROR_FILETRNC             23      /* Unable to truncate file */
+#define COL_ERROR_FILEMAP              24      /* Unable to mmap file */
+#define COL_ERROR_HEAPINIT             25      /* Unable to install heap tracing */
+#define COL_ERROR_DISPINIT              26      /* Failed to install dispatcher */
+#define COL_ERROR_ITMRINIT              27      /* Failed to install interval timer */
+#define COL_ERROR_SMPLINIT              28      /* Failed to initialize periodic sampling */
+#define COL_ERROR_MPIINIT               29      /* Failed to initialize MPI tracing */
+#define COL_ERROR_JAVAINIT              30      /* Failed to initialize Java profiling */
+#define COL_ERROR_LINEINIT              31      /* Failed to initialize lineage tracing */
+#define COL_ERROR_NOSPACE               32      /* Ran out of disk space writing file */
+#define COL_ERROR_ITMRRST               33      /* Failed to reset interval timer */
+#define COL_ERROR_MKDIR                 34      /* Failed to create (sub)directory */
+#define COL_ERROR_JVM2NEW               35      /* JVM is too new for us to cope (JVMTI interface) */
+#define COL_ERROR_JVMNOTSUPP            36      /* JVM does not support profiling (no JVMTI interface) */
+#define COL_ERROR_JVMNOJSTACK           37      /* JVM does not support java stack unwind */
+#define COL_ERROR_DYNOPEN               38      /* Unable to open dyntext file */
+#define COL_ERROR_DYNWRITE              39      /* Unable to write dyntext file */
+#define COL_ERROR_MAPOPEN               40      /* Unable to open map file */
+#define COL_ERROR_MAPREAD               41      /* Unable to read map file */
+#define COL_ERROR_MAPWRITE              42      /* Unable to write map file */
+#define COL_ERROR_RESOLVE               43      /* Unable to resolve map file */
+#define COL_ERROR_OMPINIT               44      /* Failure to initialize OpenMP tracing */
+#define COL_ERROR_DURATION_INIT         45      /* Failure to initialize -t (duration) processing */
+#define COL_ERROR_RDTINIT              46      /* Unable to install RDT */
+#define COL_ERROR_GENERAL              47      /* General error */
+#define COL_ERROR_EXEC_FAIL            48      /* Can't exec the process */
+#define COL_ERROR_THR_MAX              49      /* More threads than are supported */
+#define COL_ERROR_IOINIT               50      /* failed to initialize IO tracing */
+#define COL_ERROR_NODATA               51      /* No data recorded in experiment */
+#define COL_ERROR_DTRACE_FATAL                 52      /* Fatal error from er_kernel DTrace code */
+#define COL_ERROR_MAPSEEK              53      /* Error on seek of map file */
+#define COL_ERROR_UNEXP_FOUNDER        54      /* Unexpected value for SP_COLLECTOR_FOUNDER */
+#define COL_ERROR_LOG_OPEN             55      /* Failure to open log.xml file */
+#define COL_ERROR_TSD_INIT             56      /* TSD could not be initialized */
+#define COL_ERROR_UTIL_INIT            57      /* libcol_util.c could not be initialized */
+#define COL_ERROR_MAPCACHE             58      /* Unable to cache mappings */
+
+#define COL_WARN_NONE                  200     /* just a note, not a real warning */
+#define COL_WARN_FSTYPE                        201     /* Writing to a potentially-distorting file system */
+#define COL_WARN_PROFRND               202     /* Profile interval rounded */
+#define COL_WARN_SIZELIM               203     /* Size limit specified */
+#define COL_WARN_SIGPROF               204     /* SIGPROF handler replaced */
+#define COL_WARN_SMPLADJ                205     /* Periodic sampling rate adjusted */
+#define COL_WARN_ITMROVR                206     /* Application interval timer resetting prevented */
+#define COL_WARN_ITMRREP                207     /* Collection interval timer found to have been overridden */
+#define COL_WARN_SIGEMT                 208    /* SIGEMT handler replaced */
+#define COL_WARN_CPCBLK                 209     /* libcpc access blocked */
+#define COL_WARN_VFORK                  210     /* vfork(2) switched to fork1(2) */
+#define COL_WARN_EXECENV                211     /* incomplete exec environment */
+#define COL_WARN_SAMPSIGUSED            212     /* target installed handler for sample signal */
+#define COL_WARN_PAUSESIGUSED           213     /* target installed handler for pause signal */
+#define COL_WARN_CPCNOTRESERVED         214     /* unable to reserve HW counters for kernel profiling */
+#define COL_WARN_LIBTHREAD_T1           215     /* collection with classic libthread */
+#define COL_WARN_SIGMASK                216     /* profiling signal masking overridden */
+#define COL_WARN_NOFOLLOW               217     /* descendant following disabled */
+#define COL_WARN_RISKYFOLLOW            218     /* descendant following unqualified */
+#define COL_WARN_IDCHNG                 219     /* process ID change requested */
+#define COL_WARN_OLDJAVA               220     /* Java profiling requires JVM version 1.4.2_02 or later */
+#define COL_WARN_ITMRPOVR              221     /* Overriding app-set interval timer */
+#define COL_WARN_NO_JAVA_HEAP          222     /* Java heap tracing not supported (JVM 1.5) */
+#define COL_WARN_RDT_PAUSE_NOMEM        223     /* RDT paused because of running out of memory */
+#define COL_WARN_RDT_RESUME             224     /* RDT resumed */
+#define COL_WARN_RDT_THROVER            225     /* RDT: too many threads */
+#define COL_WARN_THR_PAUSE_RESUME       226     /* use of thread pause/resume API is deprecateds */
+#define COL_WARN_APP_NOT_READY          227     /* Application is not instrumented for RDT */
+#define COL_WARN_RDT_DL_TERMINATE       228     /* RDT: terminate execution on actual deadlock */
+#define COL_WARN_RDT_DL_TERMINATE_CORE  229     /* RDT: dump core and terminate execution on actual deadlock */
+#define COL_WARN_RDT_DL_CONTINUE        230     /* RDT: continue execution on actual deadlock */
+#define COL_WARN_NOPROF_DATA           231     /* No profile data recorded in experiment */
+#define COL_WARN_LONG_FSTAT            232     /* fstat call on /proc/self/map took > 200 ms. */
+#define COL_WARN_LONG_READ             233     /* read call on /proc/self/map took > 200 ms. */
+#define COL_WARN_LINUX_X86_APICID      234     /* using x86 APIC IDs rather than Linux sched_getcpu() */
+
+#define COL_COMMENT_NONE                400     /* no comment */
+#define COL_COMMENT_CWD                        401     /* initial execution directory */
+#define COL_COMMENT_ARGV               402     /* arguments */
+#define COL_COMMENT_MAYASSNAP          403     /* Mayas snap file name */
+#define COL_COMMENT_LINEFORK            404     /* process fork'd */
+#define COL_COMMENT_LINEEXEC            405     /* process exec'd */
+#define COL_COMMENT_LINECOMBO           406     /* process combo fork/exec */
+#define COL_COMMENT_FOXSNAP            407     /* Fox snap file name */
+#define COL_COMMENT_ROCKSNAP           408     /* Rock simulator snap file name */
+#define COL_COMMENT_BITINSTRDATA       409     /* Bit instrdata file name */
+#define COL_COMMENT_BITSNAP            410     /* Bit snap file name */
+#define COL_COMMENT_SIMDSPSNAP         411     /* Simulator dataspace profiling snap file name */
+#define COL_COMMENT_HWCADJ             412     /* HWC overflow interval adjusted */
+#endif  /* _EMSGNUM_H */
diff --git a/gprofng/src/ExpGroup.cc b/gprofng/src/ExpGroup.cc
new file mode 100644 (file)
index 0000000..0ad269a
--- /dev/null
@@ -0,0 +1,163 @@
+/* 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 "util.h"
+#include "ExpGroup.h"
+#include "Experiment.h"
+#include "LoadObject.h"
+#include "DbeSession.h"
+
+//////////////////////////////////////////////////////////
+//  class ExpGroup
+
+int ExpGroup::phaseCompareIdx = 0;
+
+ExpGroup::ExpGroup (char *nm)
+{
+  name = dbe_strdup (nm);
+  canonical_path (name);
+  exps = new Vector<Experiment*>;
+  founder = NULL;
+  groupId = 0;
+  phaseCompareIdx++;
+  loadObjs = NULL;
+  loadObjsMap = NULL;
+}
+
+ExpGroup::~ExpGroup ()
+{
+  phaseCompareIdx++;
+  free (name);
+  delete exps;
+  delete loadObjs;
+  delete loadObjsMap;
+}
+
+void
+ExpGroup::append (Experiment *exp)
+{
+  for (int i = 0, sz = exps->size (); i < sz; i++)
+    {
+      Experiment *e = exps->fetch (i);
+      if (exp == e)
+       return;
+    }
+  exps->append (exp);
+  if (exps->size () == 1)
+    founder = exp;
+}
+
+void
+ExpGroup::drop_experiment (Experiment *exp)
+{
+  for (int i = 0, sz = exps->size (); i < sz; i++)
+    {
+      Experiment *e = exps->fetch (i);
+      if (exp == e)
+       {
+         exps->remove (i);
+         break;
+       }
+    }
+  if (founder == exp)
+    founder = NULL;
+}
+
+Vector<Experiment*> *
+ExpGroup::get_founders ()
+{
+  Vector<Experiment*> *expList = NULL;
+  for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+    {
+      Experiment *exp = exps->fetch (i);
+      if (exp->founder_exp == NULL)
+       {
+         if (expList == NULL)
+           expList = new Vector<Experiment*>;
+         expList->append (exp);
+       }
+    }
+  return expList;
+}
+
+void
+ExpGroup::create_list_of_loadObjects ()
+{
+  if (loadObjs == NULL)
+    {
+      loadObjs = new Vector<LoadObject*>();
+      loadObjsMap = new DefaultMap<LoadObject*, int>();
+      for (int i = 0, sz = exps ? exps->size () : 0; i < sz; i++)
+       {
+         Experiment *exp = exps->fetch (i);
+         for (int i1 = 0, sz1 = VecSize(exp->loadObjs); i1 < sz1; i1++)
+           {
+             LoadObject *lo = exp->loadObjs->fetch (i1);
+             if (!loadObjsMap->get (lo))
+               {
+                 loadObjs->append (lo);
+                 loadObjsMap->put (lo, loadObjs->size ());
+               }
+           }
+       }
+    }
+}
+
+LoadObject *
+ExpGroup::get_comparable_loadObject (LoadObject *lo)
+{
+  create_list_of_loadObjects ();
+  if (loadObjsMap->get (lo))
+    return lo;
+  if ((lo->flags & SEG_FLAG_EXE) != 0)
+    if (dbeSession->expGroups->size () == dbeSession->nexps ())
+      for (int i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
+       {
+         LoadObject *lobj = loadObjs->fetch (i);
+         if ((lobj->flags & SEG_FLAG_EXE) != 0)
+           return lobj;
+       }
+
+  long first_ind = -1;
+  char *bname = get_basename (lo->get_pathname ());
+  for (long i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
+    {
+      LoadObject *lobj = loadObjs->get (i);
+      if (lobj->comparable_objs == NULL
+         && strcmp (bname, get_basename (lobj->get_pathname ())) == 0)
+       {
+         if (lo->platform == lobj->platform)
+           {
+             if ((lo->flags & SEG_FLAG_DYNAMIC) != 0)
+               {
+                 if (dbe_strcmp (lo->firstExp->uarglist,
+                                 lobj->firstExp->uarglist) == 0)
+                   return lobj;
+               }
+             else
+               return lobj;
+           }
+         if (first_ind == -1)
+           first_ind = i;
+       }
+    }
+  return first_ind == -1 ? NULL : loadObjs->get (first_ind);
+}
diff --git a/gprofng/src/ExpGroup.h b/gprofng/src/ExpGroup.h
new file mode 100644 (file)
index 0000000..b3c9422
--- /dev/null
@@ -0,0 +1,50 @@
+/* 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 _EXPGROUP_H
+#define _EXPGROUP_H
+
+#include "vec.h"
+#include "Map.h"
+
+class Experiment;
+class LoadObject;
+
+class ExpGroup
+{
+public:
+  ExpGroup (char *nm);
+  ~ExpGroup ();
+  void append (Experiment *exp);
+  void drop_experiment (Experiment *exp);
+  Vector<Experiment*> *get_founders ();
+  void create_list_of_loadObjects ();
+  LoadObject *get_comparable_loadObject (LoadObject *lo);
+
+  Vector<Experiment*> *exps;
+  Vector<LoadObject*> *loadObjs;
+  Map <LoadObject*, int> *loadObjsMap;
+  Experiment *founder;
+  char *name;
+  int groupId;
+  static int phaseCompareIdx;
+};
+
+#endif  /* _EXPGROUP_H */
diff --git a/gprofng/src/Exp_Layout.cc b/gprofng/src/Exp_Layout.cc
new file mode 100644 (file)
index 0000000..dfe1432
--- /dev/null
@@ -0,0 +1,422 @@
+/* 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 "CallStack.h"
+#include "DbeSession.h"
+#include "Exp_Layout.h"
+#include "Experiment.h"
+#include "Function.h"
+#include "Table.h"
+#include "dbe_types.h"
+#include "util.h"
+
+/*
+ * PrUsage is a class which wraps access to the values of prusage
+ * system structure. It was expanded to 64 bit entities in 2.7
+ * (experiment version 6 & 7).
+ */
+PrUsage::PrUsage ()
+{
+  pr_tstamp = pr_create = pr_term = pr_rtime = (hrtime_t) 0;
+  pr_utime = pr_stime = pr_ttime = pr_tftime = pr_dftime = (hrtime_t) 0;
+  pr_kftime = pr_ltime = pr_slptime = pr_wtime = pr_stoptime = (hrtime_t) 0;
+
+  pr_minf = pr_majf = pr_nswap = pr_inblk = pr_oublk = 0;
+  pr_msnd = pr_mrcv = pr_sigs = pr_vctx = pr_ictx = pr_sysc = pr_ioch = 0;
+}
+
+/*
+ * Resource usage.  /proc/<pid>/usage /proc/<pid>/lwp/<lwpid>/lwpusage
+ */
+struct timestruc_32
+{ /* v8 timestruc_t */
+  uint32_t tv_sec;              /* seconds */
+  uint32_t tv_nsec;             /* and nanoseconds */
+};
+
+typedef struct ana_prusage
+{
+  id_t pr_lwpid;                /* lwp id.  0: process or defunct */
+  int pr_count;                 /* number of contributing lwps */
+  timestruc_32 pr_tstamp;       /* current time stamp */
+  timestruc_32 pr_create;       /* process/lwp creation time stamp */
+  timestruc_32 pr_term;         /* process/lwp termination time stamp */
+  timestruc_32 pr_rtime;        /* total lwp real (elapsed) time */
+  timestruc_32 pr_utime;        /* user level cpu time */
+  timestruc_32 pr_stime;        /* system call cpu time */
+  timestruc_32 pr_ttime;        /* other system trap cpu time */
+  timestruc_32 pr_tftime;       /* text page fault sleep time */
+  timestruc_32 pr_dftime;       /* data page fault sleep time */
+  timestruc_32 pr_kftime;       /* kernel page fault sleep time */
+  timestruc_32 pr_ltime;        /* user lock wait sleep time */
+  timestruc_32 pr_slptime;      /* all other sleep time */
+  timestruc_32 pr_wtime;        /* wait-cpu (latency) time */
+  timestruc_32 pr_stoptime;     /* stopped time */
+  timestruc_32 filltime[6];     /* filler for future expansion */
+  uint32_t pr_minf;             /* minor page faults */
+  uint32_t pr_majf;             /* major page faults */
+  uint32_t pr_nswap;            /* swaps */
+  uint32_t pr_inblk;            /* input blocks */
+  uint32_t pr_oublk;            /* output blocks */
+  uint32_t pr_msnd;             /* messages sent */
+  uint32_t pr_mrcv;             /* messages received */
+  uint32_t pr_sigs;             /* signals received */
+  uint32_t pr_vctx;             /* voluntary context switches */
+  uint32_t pr_ictx;             /* involuntary context switches */
+  uint32_t pr_sysc;             /* system calls */
+  uint32_t pr_ioch;             /* chars read and written */
+  uint32_t filler[10];          /* filler for future expansion */
+} raw_prusage_32;
+
+uint64_t
+PrUsage::bind32Size ()
+{
+  uint64_t bindSize = sizeof (raw_prusage_32);
+  return bindSize;
+}
+
+#define timestruc2hr(x) ((hrtime_t)(x).tv_sec*NANOSEC + (hrtime_t)(x).tv_nsec)
+
+PrUsage *
+PrUsage::bind32 (void *p, bool need_swap_endian)
+{
+  if (p == NULL)
+    return NULL;
+  raw_prusage_32 pu, *tmp = (raw_prusage_32*) p;
+  if (need_swap_endian)
+    {
+      pu = *tmp;
+      tmp = &pu;
+      SWAP_ENDIAN (pu.pr_tstamp.tv_sec);
+      SWAP_ENDIAN (pu.pr_tstamp.tv_nsec);
+      SWAP_ENDIAN (pu.pr_create.tv_sec);
+      SWAP_ENDIAN (pu.pr_create.tv_nsec);
+      SWAP_ENDIAN (pu.pr_term.tv_sec);
+      SWAP_ENDIAN (pu.pr_term.tv_nsec);
+      SWAP_ENDIAN (pu.pr_rtime.tv_sec);
+      SWAP_ENDIAN (pu.pr_rtime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_utime.tv_sec);
+      SWAP_ENDIAN (pu.pr_utime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_stime.tv_sec);
+      SWAP_ENDIAN (pu.pr_stime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_ttime.tv_sec);
+      SWAP_ENDIAN (pu.pr_ttime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_tftime.tv_sec);
+      SWAP_ENDIAN (pu.pr_tftime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_dftime.tv_sec);
+      SWAP_ENDIAN (pu.pr_dftime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_kftime.tv_sec);
+      SWAP_ENDIAN (pu.pr_kftime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_ltime.tv_sec);
+      SWAP_ENDIAN (pu.pr_ltime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_slptime.tv_sec);
+      SWAP_ENDIAN (pu.pr_slptime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_wtime.tv_sec);
+      SWAP_ENDIAN (pu.pr_wtime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_stoptime.tv_sec);
+      SWAP_ENDIAN (pu.pr_stoptime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_minf);
+      SWAP_ENDIAN (pu.pr_majf);
+      SWAP_ENDIAN (pu.pr_nswap);
+      SWAP_ENDIAN (pu.pr_inblk);
+      SWAP_ENDIAN (pu.pr_oublk);
+      SWAP_ENDIAN (pu.pr_msnd);
+      SWAP_ENDIAN (pu.pr_mrcv);
+      SWAP_ENDIAN (pu.pr_sigs);
+      SWAP_ENDIAN (pu.pr_vctx);
+      SWAP_ENDIAN (pu.pr_ictx);
+      SWAP_ENDIAN (pu.pr_sysc);
+      SWAP_ENDIAN (pu.pr_ioch);
+    }
+  pr_tstamp = timestruc2hr (tmp->pr_tstamp);
+  pr_create = timestruc2hr (tmp->pr_create);
+  pr_term = timestruc2hr (tmp->pr_term);
+  pr_rtime = timestruc2hr (tmp->pr_rtime);
+  pr_utime = timestruc2hr (tmp->pr_utime);
+  pr_stime = timestruc2hr (tmp->pr_stime);
+  pr_ttime = timestruc2hr (tmp->pr_ttime);
+  pr_tftime = timestruc2hr (tmp->pr_tftime);
+  pr_dftime = timestruc2hr (tmp->pr_dftime);
+  pr_kftime = timestruc2hr (tmp->pr_kftime);
+  pr_ltime = timestruc2hr (tmp->pr_ltime);
+  pr_slptime = timestruc2hr (tmp->pr_slptime);
+  pr_wtime = timestruc2hr (tmp->pr_wtime);
+  pr_stoptime = timestruc2hr (tmp->pr_stoptime);
+  pr_minf = tmp->pr_minf;
+  pr_majf = tmp->pr_majf;
+  pr_nswap = tmp->pr_nswap;
+  pr_inblk = tmp->pr_inblk;
+  pr_oublk = tmp->pr_oublk;
+  pr_msnd = tmp->pr_msnd;
+  pr_mrcv = tmp->pr_mrcv;
+  pr_sigs = tmp->pr_sigs;
+  pr_vctx = tmp->pr_vctx;
+  pr_ictx = tmp->pr_ictx;
+  pr_sysc = tmp->pr_sysc;
+  pr_ioch = tmp->pr_ioch;
+  return this;
+}
+
+struct timestruc_64
+{ /* 64-bit timestruc_t */
+  uint64_t tv_sec;          /* seconds */
+  uint64_t tv_nsec;         /* and nanoseconds */
+};
+
+typedef struct
+{
+  id_t pr_lwpid;            /* lwp id.  0: process or defunct */
+  int pr_count;             /* number of contributing lwps */
+  timestruc_64 pr_tstamp;   /* current time stamp */
+  timestruc_64 pr_create;   /* process/lwp creation time stamp */
+  timestruc_64 pr_term;     /* process/lwp termination time stamp */
+  timestruc_64 pr_rtime;    /* total lwp real (elapsed) time */
+  timestruc_64 pr_utime;    /* user level cpu time */
+  timestruc_64 pr_stime;    /* system call cpu time */
+  timestruc_64 pr_ttime;    /* other system trap cpu time */
+  timestruc_64 pr_tftime;   /* text page fault sleep time */
+  timestruc_64 pr_dftime;   /* data page fault sleep time */
+  timestruc_64 pr_kftime;   /* kernel page fault sleep time */
+  timestruc_64 pr_ltime;    /* user lock wait sleep time */
+  timestruc_64 pr_slptime;  /* all other sleep time */
+  timestruc_64 pr_wtime;    /* wait-cpu (latency) time */
+  timestruc_64 pr_stoptime; /* stopped time */
+  timestruc_64 filltime[6]; /* filler for future expansion */
+  uint64_t pr_minf;         /* minor page faults */
+  uint64_t pr_majf;         /* major page faults */
+  uint64_t pr_nswap;        /* swaps */
+  uint64_t pr_inblk;        /* input blocks */
+  uint64_t pr_oublk;        /* output blocks */
+  uint64_t pr_msnd;         /* messages sent */
+  uint64_t pr_mrcv;         /* messages received */
+  uint64_t pr_sigs;         /* signals received */
+  uint64_t pr_vctx;         /* voluntary context switches */
+  uint64_t pr_ictx;         /* involuntary context switches */
+  uint64_t pr_sysc;         /* system calls */
+  uint64_t pr_ioch;         /* chars read and written */
+  uint64_t filler[10];      /* filler for future expansion */
+} raw_prusage_64;
+
+uint64_t
+PrUsage::bind64Size ()
+{
+  uint64_t bindSize = sizeof (raw_prusage_64);
+  return bindSize;
+}
+
+PrUsage *
+PrUsage::bind64 (void *p, bool need_swap_endian)
+{
+  if (p == NULL)
+    {
+      return NULL;
+    }
+  raw_prusage_64 pu, *tmp = (raw_prusage_64*) p;
+  if (need_swap_endian)
+    {
+      pu = *tmp;
+      tmp = &pu;
+      SWAP_ENDIAN (pu.pr_tstamp.tv_sec);
+      SWAP_ENDIAN (pu.pr_tstamp.tv_nsec);
+      SWAP_ENDIAN (pu.pr_create.tv_sec);
+      SWAP_ENDIAN (pu.pr_create.tv_nsec);
+      SWAP_ENDIAN (pu.pr_term.tv_sec);
+      SWAP_ENDIAN (pu.pr_term.tv_nsec);
+      SWAP_ENDIAN (pu.pr_rtime.tv_sec);
+      SWAP_ENDIAN (pu.pr_rtime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_utime.tv_sec);
+      SWAP_ENDIAN (pu.pr_utime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_stime.tv_sec);
+      SWAP_ENDIAN (pu.pr_stime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_ttime.tv_sec);
+      SWAP_ENDIAN (pu.pr_ttime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_tftime.tv_sec);
+      SWAP_ENDIAN (pu.pr_tftime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_dftime.tv_sec);
+      SWAP_ENDIAN (pu.pr_dftime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_kftime.tv_sec);
+      SWAP_ENDIAN (pu.pr_kftime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_ltime.tv_sec);
+      SWAP_ENDIAN (pu.pr_ltime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_slptime.tv_sec);
+      SWAP_ENDIAN (pu.pr_slptime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_wtime.tv_sec);
+      SWAP_ENDIAN (pu.pr_wtime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_stoptime.tv_sec);
+      SWAP_ENDIAN (pu.pr_stoptime.tv_nsec);
+      SWAP_ENDIAN (pu.pr_minf);
+      SWAP_ENDIAN (pu.pr_majf);
+      SWAP_ENDIAN (pu.pr_nswap);
+      SWAP_ENDIAN (pu.pr_inblk);
+      SWAP_ENDIAN (pu.pr_oublk);
+      SWAP_ENDIAN (pu.pr_msnd);
+      SWAP_ENDIAN (pu.pr_mrcv);
+      SWAP_ENDIAN (pu.pr_sigs);
+      SWAP_ENDIAN (pu.pr_vctx);
+      SWAP_ENDIAN (pu.pr_ictx);
+      SWAP_ENDIAN (pu.pr_sysc);
+      SWAP_ENDIAN (pu.pr_ioch);
+    }
+
+  pr_tstamp = timestruc2hr (tmp->pr_tstamp);
+  pr_create = timestruc2hr (tmp->pr_create);
+  pr_term = timestruc2hr (tmp->pr_term);
+  pr_rtime = timestruc2hr (tmp->pr_rtime);
+  pr_utime = timestruc2hr (tmp->pr_utime);
+  pr_stime = timestruc2hr (tmp->pr_stime);
+  pr_ttime = timestruc2hr (tmp->pr_ttime);
+  pr_tftime = timestruc2hr (tmp->pr_tftime);
+  pr_dftime = timestruc2hr (tmp->pr_dftime);
+  pr_kftime = timestruc2hr (tmp->pr_kftime);
+  pr_ltime = timestruc2hr (tmp->pr_ltime);
+  pr_slptime = timestruc2hr (tmp->pr_slptime);
+  pr_wtime = timestruc2hr (tmp->pr_wtime);
+  pr_stoptime = timestruc2hr (tmp->pr_stoptime);
+  pr_minf = tmp->pr_minf;
+  pr_majf = tmp->pr_majf;
+  pr_nswap = tmp->pr_nswap;
+  pr_inblk = tmp->pr_inblk;
+  pr_oublk = tmp->pr_oublk;
+  pr_msnd = tmp->pr_msnd;
+  pr_mrcv = tmp->pr_mrcv;
+  pr_sigs = tmp->pr_sigs;
+  pr_vctx = tmp->pr_vctx;
+  pr_ictx = tmp->pr_ictx;
+  pr_sysc = tmp->pr_sysc;
+  pr_ioch = tmp->pr_ioch;
+  return this;
+}
+
+Vector<long long> *
+PrUsage::getMstateValues ()
+{
+  const PrUsage *prusage = this;
+  Vector<long long> *states = new Vector<long long>;
+  states->store (0, prusage->pr_utime);
+  states->store (1, prusage->pr_stime);
+  states->store (2, prusage->pr_ttime);
+  states->store (3, prusage->pr_tftime);
+  states->store (4, prusage->pr_dftime);
+  states->store (5, prusage->pr_kftime);
+  states->store (6, prusage->pr_ltime);
+  states->store (7, prusage->pr_slptime);
+  states->store (8, prusage->pr_wtime);
+  states->store (9, prusage->pr_stoptime);
+  assert (LMS_NUM_SOLARIS_MSTATES == states->size ());
+  return states;
+}
+
+void* CommonPacket::jvm_overhead = NULL;
+
+CommonPacket::CommonPacket ()
+{
+  for (int i = 0; i < NTAGS; i++)
+    tags[i] = 0;
+  tstamp = 0;
+  jthread_TBR = NULL;
+  frinfo = 0;
+  leafpc = 0;
+  nat_stack = NULL;
+  user_stack = NULL;
+}
+
+int
+CommonPacket::cmp (const void *a, const void *b)
+{
+  if ((*(CommonPacket **) a)->tstamp > (*(CommonPacket **) b)->tstamp)
+    return 1;
+  else if ((*(CommonPacket **) a)->tstamp < (*(CommonPacket **) b)->tstamp)
+    return -1;
+  else
+    return 0;
+}
+
+void *
+CommonPacket::getStack (VMode view_mode)
+{
+  if (view_mode == VMODE_MACHINE)
+    return nat_stack;
+  else if (view_mode == VMODE_USER)
+    {
+      if (jthread_TBR == JTHREAD_NONE || (jthread_TBR && jthread_TBR->is_system ()))
+       return jvm_overhead;
+    }
+  else if (view_mode == VMODE_EXPERT)
+    {
+      Histable *hist = CallStack::getStackPC (user_stack, 0);
+      if (hist->get_type () == Histable::INSTR)
+       {
+         DbeInstr *instr = (DbeInstr*) hist;
+         if (instr->func == dbeSession->get_JUnknown_Function ())
+           return nat_stack;
+       }
+      else if (hist->get_type () == Histable::LINE)
+       {
+         DbeLine *line = (DbeLine *) hist;
+         if (line->func == dbeSession->get_JUnknown_Function ())
+           return nat_stack;
+       }
+    }
+  return user_stack;
+}
+
+Histable *
+CommonPacket::getStackPC (int n, VMode view_mode)
+{
+  return CallStack::getStackPC (getStack (view_mode), n);
+}
+
+Vector<Histable*> *
+CommonPacket::getStackPCs (VMode view_mode)
+{
+  return CallStack::getStackPCs (getStack (view_mode));
+}
+
+void *
+getStack (VMode view_mode, DataView *dview, long idx)
+{
+  void *stack = NULL;
+  if (view_mode == VMODE_MACHINE)
+    stack = dview->getObjValue (PROP_MSTACK, idx);
+  else if (view_mode == VMODE_USER)
+    stack = dview->getObjValue (PROP_USTACK, idx);
+  else if (view_mode == VMODE_EXPERT)
+    stack = dview->getObjValue (PROP_XSTACK, idx);
+  return stack;
+}
+
+int
+stackSize (VMode view_mode, DataView *dview, long idx)
+{
+  return CallStack::stackSize (getStack (view_mode, dview, idx));
+}
+
+Histable *
+getStackPC (int n, VMode view_mode, DataView *dview, long idx)
+{
+  return CallStack::getStackPC (getStack (view_mode, dview, idx), n);
+}
+
+Vector<Histable*> *
+getStackPCs (VMode view_mode, DataView *dview, long idx)
+{
+  return CallStack::getStackPCs (getStack (view_mode, dview, idx));
+}
diff --git a/gprofng/src/Exp_Layout.h b/gprofng/src/Exp_Layout.h
new file mode 100644 (file)
index 0000000..c5fbe4c
--- /dev/null
@@ -0,0 +1,158 @@
+/* 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 _EXP_LAYOUT_H
+#define _EXP_LAYOUT_H
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#include "dbe_types.h"
+#include "gp-experiment.h"
+#include "data_pckts.h"
+#include "ABS.h"
+#include "Data_window.h"
+#include "Histable.h"
+#include "vec.h"
+
+class PrUsage
+{
+public:
+  PrUsage ();
+  PrUsage *bind32 (void *p, bool need_swap_endian);
+  PrUsage *bind64 (void *p, bool need_swap_endian);
+  static uint64_t bind32Size ();
+  static uint64_t bind64Size ();
+  Vector<long long> * getMstateValues ();
+
+  hrtime_t pr_tstamp;
+  hrtime_t pr_create;
+  hrtime_t pr_term;
+  hrtime_t pr_rtime;
+
+  // the following correspond to PROP_MSTATE LMS_* offsets; see newMstateVec()
+  hrtime_t pr_utime;
+  hrtime_t pr_stime;
+  hrtime_t pr_ttime;
+  hrtime_t pr_tftime;
+  hrtime_t pr_dftime;
+  hrtime_t pr_kftime;
+  hrtime_t pr_ltime;
+  hrtime_t pr_slptime;
+  hrtime_t pr_wtime;
+  hrtime_t pr_stoptime;
+
+  uint64_t pr_minf;
+  uint64_t pr_majf;
+  uint64_t pr_nswap;
+  uint64_t pr_inblk;
+  uint64_t pr_oublk;
+  uint64_t pr_msnd;
+  uint64_t pr_mrcv;
+  uint64_t pr_sigs;
+  uint64_t pr_vctx;
+  uint64_t pr_ictx;
+  uint64_t pr_sysc;
+  uint64_t pr_ioch;
+};
+
+class DataView;
+extern void *getStack (VMode, DataView*, long);
+extern int stackSize (VMode, DataView*, long);
+extern Histable *getStackPC (int, VMode, DataView*, long);
+extern Vector<Histable*> *getStackPCs (VMode, DataView*, long);
+
+class CommonPacket // use only for RacePacket, please
+{
+public:
+  CommonPacket ();
+  void *getStack (VMode);
+  Histable *getStackPC (int, VMode);
+  Vector<Histable*>*getStackPCs (VMode);
+  static int cmp (const void *a, const void *b);
+
+  enum Tag_type  { LWP, THR, CPU };
+  static const int NTAGS = 3;
+  uint32_t tags[NTAGS];         // lwp_id, thr_id, cpu_id
+  hrtime_t tstamp;
+  struct JThread *jthread_TBR;  // pointer to JThread or NULL
+  uint64_t frinfo;              // frame info
+  Vaddr leafpc;                 // raw leaf PC if availabe
+  void *nat_stack;              // native stack
+  void *user_stack;             // user stack (Java, OMP, etc.)
+  static void *jvm_overhead;
+};
+
+class FramePacket
+{
+public:
+  int
+  stackSize (bool java = false)
+  {
+    return java ? jstack->size () / 2 : stack->size ();
+  }
+
+  Vaddr
+  getFromStack (int n)
+  {
+    return stack->fetch (n);
+  }
+
+  Vaddr
+  getMthdFromStack (int n)
+  {
+    return jstack->fetch (2 * n + 1);
+  }
+
+  int
+  getBciFromStack (int n)
+  {
+    return (int) jstack->fetch (2 * n);
+  }
+
+  bool
+  isLeafMark (int n)
+  {
+    return stack->fetch (n) == (Vaddr) SP_LEAF_CHECK_MARKER;
+  }
+
+  bool
+  isTruncatedStack (bool java = false)
+  {
+    return java ? jtruncated : truncated == (Vaddr) SP_TRUNC_STACK_MARKER;
+  }
+
+  bool
+  isFailedUnwindStack ()
+  {
+    return truncated == (Vaddr) SP_FAILED_UNWIND_MARKER;
+  }
+  uint32_t omp_state; // OpenMP thread state
+  uint32_t mpi_state; // MPI state
+  uint64_t omp_cprid; // OpenMP parallel region id (omptrace)
+  Vector<Vaddr> *stack;
+  Vaddr truncated;
+  Vector<Vaddr> *jstack;
+  bool jtruncated;
+  Vector<Vaddr> *ompstack;
+  Vaddr omptruncated;
+};
+
+#endif /* _EXP_LAYOUT_H */
diff --git a/gprofng/src/Experiment.cc b/gprofng/src/Experiment.cc
new file mode 100644 (file)
index 0000000..a23c10c
--- /dev/null
@@ -0,0 +1,6961 @@
+/* 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 <errno.h>
+#include <utime.h>
+#include <alloca.h>
+#include <dirent.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <set>
+
+#include "util.h"
+#include "CacheMap.h"
+#include "DbeFile.h"
+#include "DbeCacheMap.h"
+#include "DefaultHandler.h"
+#include "DefaultMap2D.h"
+#include "Emsg.h"
+#include "Elf.h"
+#include "SAXParser.h"
+#include "SAXParserFactory.h"
+#include "StringBuilder.h"
+#include "DbeSession.h"
+#include "DbeThread.h"
+#include "Application.h"
+#include "CallStack.h"
+#include "Experiment.h"
+#include "Exp_Layout.h"
+#include "DataStream.h"
+#include "Expression.h"
+#include "Function.h"
+#include "HeapMap.h"
+#include "LoadObject.h"
+#include "Module.h"
+#include "Ovw_data.h"
+#include "PRBTree.h"
+#include "Sample.h"
+#include "SegMem.h"
+#include "StringMap.h"
+#include "UserLabel.h"
+#include "Table.h"
+#include "dbe_types.h"
+#include "FileData.h"
+#include "cc_libcollector.h"
+#include "ExpGroup.h"
+
+int nPush;
+int nPop;
+int pushCnt;
+int popCnt;
+int pushCnt3;
+int popCnt3;
+
+struct Experiment::UIDnode
+{
+  uint64_t uid;
+  uint64_t val;
+  UIDnode *next;
+};
+
+struct Experiment::RawFramePacket
+{
+  uint64_t uid;
+  UIDnode *uidn;
+  UIDnode *uidj;
+  UIDnode *omp_uid;
+  uint32_t omp_state;
+};
+
+static hrtime_t
+parseTStamp (const char *s)
+{
+  hrtime_t ts = (hrtime_t) 0;
+  ts = (hrtime_t) atoi (s) * NANOSEC;
+  s = strchr (s, '.');
+  if (s != NULL)
+    ts += (hrtime_t) atoi (s + 1);
+  return ts;
+}
+
+class Experiment::ExperimentFile
+{
+public:
+
+  enum
+  {
+    EF_NOT_OPENED,
+    EF_OPENED,
+    EF_CLOSED,
+    EF_FAILURE
+  };
+
+  ExperimentFile (Experiment *_exp, const char *_fname);
+  ~ExperimentFile ();
+
+  bool open (bool new_open = false);
+
+  char *
+  get_name ()
+  {
+    return fname;
+  }
+
+  inline int
+  get_status ()
+  {
+    return ef_status;
+  }
+
+  char *fgets ();
+  void close ();
+
+  FILE *fh;
+
+private:
+  Experiment *exp;
+  char *fname;
+  off64_t offset;
+  int bufsz, ef_status;
+  char *buffer;
+};
+
+class Experiment::ExperimentHandler : public DefaultHandler
+{
+public:
+
+  ExperimentHandler (Experiment *_exp);
+  ~ExperimentHandler ();
+
+  void
+  startDocument () { }
+  void endDocument ();
+  void startElement (char *uri, char *localName, char *qName, Attributes *attrs);
+  void endElement (char *uri, char *localName, char *qName);
+  void characters (char *ch, int start, int length);
+
+  void
+  ignorableWhitespace (char*, int, int) { }
+  void
+  error (SAXParseException *e);
+
+private:
+
+  enum Element
+  {
+    EL_NONE,
+    EL_EXPERIMENT,
+    EL_COLLECTOR,
+    EL_SETTING,
+    EL_PROCESS,
+    EL_SYSTEM,
+    EL_EVENT,
+    EL_PROFILE,
+    EL_DATAPTR,
+    EL_PROFDATA,
+    EL_PROFPCKT,
+    EL_FIELD,
+    EL_CPU,
+    EL_STATE,
+    EL_FREQUENCY,
+    EL_POWERM,
+    EL_DTRACEFATAL
+  };
+
+  static int toInt (Attributes *attrs, const char *atr);
+  static char*toStr (Attributes *attrs, const char *atr);
+  void pushElem (Element);
+  void popElem ();
+
+  Experiment *exp;
+  Element curElem;
+  Vector<Element> *stack;
+  Module *dynfuncModule;
+  DataDescriptor *dDscr;
+  PacketDescriptor *pDscr;
+  PropDescr *propDscr;
+  char *text;
+  Cmsg_warn mkind;
+  int mnum;
+  int mec;
+};
+
+
+// HTableSize is the size of smemHTable and instHTable
+// omazur: both HTableSize and the hash function haven't been tuned;
+static const int HTableSize = 8192;
+
+//-------------------------------------------------- Experiment file handler
+
+Experiment::ExperimentFile::ExperimentFile (Experiment *_exp, const char *_fname)
+{
+  exp = _exp;
+  fh = NULL;
+  bufsz = 0;
+  buffer = NULL;
+  ef_status = EF_NOT_OPENED;
+  offset = 0;
+  fname = dbe_sprintf (NTXT ("%s/%s"), exp->expt_name, _fname);
+}
+
+Experiment::ExperimentFile::~ExperimentFile ()
+{
+  close ();
+  free (buffer);
+  free (fname);
+}
+
+bool
+Experiment::ExperimentFile::open (bool new_open)
+{
+  if (fh == NULL)
+    {
+      fh = fopen64 (fname, NTXT ("r"));
+      if (fh == NULL)
+       {
+         ef_status = EF_FAILURE;
+         return false;
+       }
+      ef_status = EF_OPENED;
+      if (new_open)
+       offset = 0;
+      if (offset != 0)
+       fseeko64 (fh, offset, SEEK_SET);
+    }
+  return true;
+}
+
+char *
+Experiment::ExperimentFile::fgets ()
+{
+  if (bufsz == 0)
+    {
+      bufsz = 1024;
+      buffer = (char *) malloc (bufsz);
+      if (buffer == NULL)
+       return NULL;
+      buffer[bufsz - 1] = (char) 1; // sentinel
+    }
+  char *res = ::fgets (buffer, bufsz, fh);
+  if (res == NULL)
+    return NULL;
+  while (buffer[bufsz - 1] == (char) 0)
+    {
+      int newsz = bufsz + 1024;
+      char *newbuf = (char *) malloc (newsz);
+      if (newbuf == NULL)
+       return NULL;
+      memcpy (newbuf, buffer, bufsz);
+      free (buffer);
+      buffer = newbuf;
+      buffer[newsz - 1] = (char) 1; // sentinel
+      // we don't care about fgets result here
+      ::fgets (buffer + bufsz - 1, newsz - bufsz + 1, fh);
+      bufsz = newsz;
+    }
+  return buffer;
+}
+
+void
+Experiment::ExperimentFile::close ()
+{
+  if (fh)
+    {
+      offset = ftello64 (fh);
+      fclose (fh);
+      ef_status = EF_CLOSED;
+      fh = NULL;
+    }
+}
+
+
+//-------------------------------------------------- Experiment XML parser
+int
+Experiment::ExperimentHandler::toInt (Attributes *attrs, const char *atr)
+{
+  const char *str = attrs->getValue (atr);
+  return str ? atoi (str) : 0;
+}
+
+char *
+Experiment::ExperimentHandler::toStr (Attributes *attrs, const char *atr)
+{
+  const char *str = attrs->getValue (atr);
+  return dbe_strdup (str ? str : NTXT (""));
+}
+
+Experiment::ExperimentHandler::ExperimentHandler (Experiment *_exp)
+{
+  exp = _exp;
+  stack = new Vector<Element>;
+  pushElem (EL_NONE);
+  dynfuncModule = NULL;
+  dDscr = NULL;
+  pDscr = NULL;
+  propDscr = NULL;
+  text = NULL;
+  mkind = (Cmsg_warn) - 1; // CMSG_NONE
+  mnum = -1;
+  mec = -1;
+}
+
+Experiment::ExperimentHandler::~ExperimentHandler ()
+{
+  delete stack;
+  free (text);
+}
+
+void
+Experiment::ExperimentHandler::endDocument ()
+{
+  { // SP_TAG_STATE should be used to describe states, but it isn't
+    // let's do it here:
+    DataDescriptor *dd = exp->getDataDescriptor (DATA_HEAP);
+    if (dd != NULL)
+      {
+       PropDescr *prop = dd->getProp (PROP_HTYPE);
+       if (prop != NULL)
+         {
+           char * stateNames [HEAPTYPE_LAST] = HEAPTYPE_STATE_STRINGS;
+           char * stateUNames[HEAPTYPE_LAST] = HEAPTYPE_STATE_USTRINGS;
+           for (int ii = 0; ii < HEAPTYPE_LAST; ii++)
+             prop->addState (ii, stateNames[ii], stateUNames[ii]);
+         }
+      }
+    dd = exp->getDataDescriptor (DATA_IOTRACE);
+    if (dd != NULL)
+      {
+       PropDescr *prop = dd->getProp (PROP_IOTYPE);
+       if (prop != NULL)
+         {
+           char * stateNames [IOTRACETYPE_LAST] = IOTRACETYPE_STATE_STRINGS;
+           char * stateUNames[IOTRACETYPE_LAST] = IOTRACETYPE_STATE_USTRINGS;
+           for (int ii = 0; ii < IOTRACETYPE_LAST; ii++)
+             prop->addState (ii, stateNames[ii], stateUNames[ii]);
+         }
+      }
+  }
+}
+
+void
+Experiment::ExperimentHandler::pushElem (Element elem)
+{
+  curElem = elem;
+  stack->append (curElem);
+}
+
+void
+Experiment::ExperimentHandler::popElem ()
+{
+  stack->remove (stack->size () - 1);
+  curElem = stack->fetch (stack->size () - 1);
+}
+
+void
+Experiment::ExperimentHandler::startElement (char*, char*, char *qName, Attributes *attrs)
+{
+  DEBUG_CODE if (DEBUG_SAXPARSER) dump_startElement (qName, attrs);
+  if (strcmp (qName, SP_TAG_EXPERIMENT) == 0)
+    {
+      pushElem (EL_EXPERIMENT);
+      const char *str = attrs->getValue (NTXT ("version"));
+      if (str != NULL)
+       {
+         int major = atoi (str);
+         str = strchr (str, '.');
+         int minor = str ? atoi (str + 1) : 0;
+         exp->exp_maj_version = major;
+         exp->exp_min_version = minor;
+         if (major != SUNPERF_VERNUM || minor != SUNPERF_VERNUM_MINOR)
+           {
+             // not the current version, see if we support some earlier versions
+             if (major < 12)
+               {
+                 StringBuilder sb;
+                 sb.sprintf (GTXT ("*** Error: experiment %s version %d.%d is not supported;\nuse the version of the tools that recorded the experiment to read it"),
+                             exp->get_expt_name (), major, minor);
+                 // exp->errorq->append( new Emsg(CMSG_FATAL, sb) );
+                 exp->status = FAILURE;
+                 exp->obsolete = 1;
+                 throw new SAXException (sb.toString ());
+               }
+           }
+       }
+    }
+  else if (strcmp (qName, SP_TAG_COLLECTOR) == 0)
+    pushElem (EL_COLLECTOR);
+  else if (strcmp (qName, SP_TAG_SETTING) == 0)
+    {
+      int found = 0;
+      pushElem (EL_SETTING);
+      const char *str = attrs->getValue (SP_JCMD_LIMIT);
+      if (str != NULL)
+       {
+         found = 1;
+         exp->coll_params.limit = atoi (str);
+       }
+      str = attrs->getValue (SP_JCMD_BLKSZ);
+      if (str != NULL)
+       {
+         found = 1;
+         exp->blksz = strtol (str, NULL, 0);
+       }
+      str = attrs->getValue (SP_JCMD_STACKBASE);
+      if (str)
+       {
+         found = 1;
+         exp->stack_base = strtoull (str, NULL, 0);
+       }
+      str = attrs->getValue (SP_JCMD_HWC_DEFAULT);
+      if (str != NULL)
+       {
+         found = 1;
+         exp->hwc_default = true;
+       }
+      str = attrs->getValue (SP_JCMD_NOIDLE);
+      if (str != NULL)
+       {
+         found = 1;
+         exp->commentq->append (new Emsg (CMSG_COMMENT,
+                                          GTXT ("*** Note: experiment does not have events from idle CPUs")));
+       }
+      str = attrs->getValue (SP_JCMD_FAKETIME);
+      if (str != NULL)
+       {
+         found = 1;
+         exp->timelineavail = false;
+         exp->commentq->append (new Emsg (CMSG_COMMENT,
+                                          GTXT ("*** Note: experiment does not have timestamps; timeline unavailable")));
+       }
+      str = attrs->getValue (SP_JCMD_DELAYSTART);
+      if (str != NULL)
+       {
+         found = 1;
+         exp->coll_params.start_delay = strdup (str);
+       }
+      str = attrs->getValue (SP_JCMD_TERMINATE);
+      if (str != NULL)
+       {
+         found = 1;
+         exp->coll_params.terminate = strdup (str);
+       }
+      str = attrs->getValue (SP_JCMD_PAUSE_SIG);
+      if (str != NULL)
+       {
+         found = 1;
+         exp->coll_params.pause_sig = strdup (str);
+       }
+      str = attrs->getValue (SP_JCMD_SAMPLE_PERIOD);
+      if (str != NULL)
+       {
+         found = 1;
+         exp->coll_params.sample_periodic = 1;
+         exp->coll_params.sample_timer = atoi (str);
+       }
+      str = attrs->getValue (SP_JCMD_SAMPLE_SIG);
+      if (str != NULL)
+       {
+         found = 1;
+         exp->coll_params.sample_sig = str;
+       }
+      str = attrs->getValue (SP_JCMD_SRCHPATH);
+      if (str != NULL)
+       {
+         found = 1;
+         StringBuilder sb;
+         sb.sprintf (GTXT ("Search path: %s"), str);
+         exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
+         dbeSession->add_classpath ((char*) str);
+       }
+      str = attrs->getValue (SP_JCMD_LINETRACE);
+      if (str != NULL)
+       {
+         found = 1;
+         exp->coll_params.linetrace = strdup (str);
+       }
+
+      str = attrs->getValue (SP_JCMD_COLLENV);
+      if (str != NULL)
+       {
+         found = 1;
+         StringBuilder sb;
+         sb.sprintf (GTXT ("  Data collection environment variable: %s"), str);
+         exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
+       }
+      if (found == 0)
+       {
+         int nattr = attrs->getLength ();
+         if (nattr != 0)
+           {
+             fprintf (stderr, "XXX Unexpected setting found; %d attributes:\n",
+                      nattr);
+             for (int k = 0; k < nattr; k++)
+               {
+                 const char *qn = attrs->getQName (k);
+                 const char *vl = attrs->getValue (k);
+                 fprintf (stderr, "XXX      %s = %s\n", qn, vl);
+               }
+           }
+       }
+      // END OF CODE FOR "setting"
+    }
+  else if (strcmp (qName, SP_TAG_SYSTEM) == 0)
+    {
+      pushElem (EL_SYSTEM);
+      const char *str = attrs->getValue (NTXT ("hostname"));
+      if (str != NULL)
+       exp->hostname = strdup (str);
+      str = attrs->getValue (NTXT ("os"));
+      if (str != NULL)
+       {
+         exp->os_version = strdup (str);
+         /* For Linux experiments expect sparse thread ID's */
+         if (strncmp (str, NTXT ("SunOS"), 5) != 0)
+           exp->sparse_threads = true;
+       }
+      str = attrs->getValue (NTXT ("arch"));
+      if (str != NULL)
+       {
+         if (strcmp (str, "i86pc") == 0 || strcmp (str, "i686") == 0
+             || strcmp (str, "x86_64") == 0)
+           exp->platform = Intel;
+         else if (strcmp (str, "aarch64") == 0)
+           exp->platform = Aarch64;
+         else
+           exp->platform = Sparc;
+         exp->need_swap_endian = (DbeSession::platform == Sparc) ?
+                 (exp->platform != Sparc) : (exp->platform == Sparc);
+         exp->architecture = strdup (str);
+       }
+      str = attrs->getValue (NTXT ("pagesz"));
+      if (str != NULL)
+       exp->page_size = atoi (str);
+      str = attrs->getValue (NTXT ("npages"));
+      if (str != NULL)
+       exp->npages = atoi (str);
+    }
+  else if (strcmp (qName, SP_TAG_POWERM) == 0)
+    pushElem (EL_POWERM);
+  else if (strcmp (qName, SP_TAG_FREQUENCY) == 0)
+    {
+      pushElem (EL_FREQUENCY);
+      const char *str = attrs->getValue (NTXT ("clk"));
+      if (str != NULL)
+       exp->set_clock (atoi (str));
+      // check for frequency_scaling or turbo_mode recorded from libcollector under dbx
+      str = attrs->getValue (NTXT ("frequency_scaling"));
+      const char *str2 = attrs->getValue (NTXT ("turbo_mode"));
+      if (str != NULL || str2 != NULL)
+       exp->varclock = 1;
+    }
+  else if (strcmp (qName, SP_TAG_CPU) == 0)
+    {
+      pushElem (EL_CPU);
+      exp->ncpus++;
+      const char *str = attrs->getValue (NTXT ("clk"));
+      if (str != NULL)
+       {
+         int clk = atoi (str);
+         if (exp->maxclock == 0)
+           {
+             exp->minclock = clk;
+             exp->maxclock = clk;
+           }
+         else
+           {
+             if (clk < exp->minclock)
+               exp->minclock = clk;
+             if (clk > exp->maxclock)
+               exp->maxclock = clk;
+           }
+         exp->clock = clk;
+       }
+      // check for frequency_scaling or turbo_mode
+      str = attrs->getValue (NTXT ("frequency_scaling"));
+      const char *str2 = attrs->getValue (NTXT ("turbo_mode"));
+      if (str != NULL || str2 != NULL)
+       exp->varclock = 1;
+    }
+  else if (strcmp (qName, SP_TAG_PROCESS) == 0)
+    {
+      pushElem (EL_PROCESS);
+      const char *str = attrs->getValue (NTXT ("wsize"));
+      if (str != NULL)
+       {
+         int wsz = atoi (str);
+         if (wsz == 32)
+           exp->wsize = W32;
+         else if (wsz == 64)
+           exp->wsize = W64;
+       }
+      str = attrs->getValue (NTXT ("pid"));
+      if (str != NULL)
+       exp->pid = atoi (str);
+      str = attrs->getValue (NTXT ("ppid"));
+      if (str != NULL)
+       exp->ppid = atoi (str);
+      str = attrs->getValue (NTXT ("pgrp"));
+      if (str != NULL)
+       exp->pgrp = atoi (str);
+      str = attrs->getValue (NTXT ("sid"));
+      if (str != NULL)
+       exp->sid = atoi (str);
+      str = attrs->getValue (NTXT ("cwd"));
+      if (str != NULL)
+       exp->ucwd = strdup (str);
+      str = attrs->getValue (NTXT ("pagesz"));
+      if (str != NULL)
+       exp->page_size = atoi (str);
+    }
+  else if (strcmp (qName, SP_TAG_EVENT) == 0)
+    { // Start code for event
+      pushElem (EL_EVENT);
+      hrtime_t ts = (hrtime_t) 0;
+      const char *str = attrs->getValue (NTXT ("tstamp"));
+      if (str != NULL)
+       ts = parseTStamp (str);
+      str = attrs->getValue (NTXT ("kind"));
+      if (str != NULL)
+       {
+         if (strcmp (str, SP_JCMD_RUN) == 0)
+           {
+             exp->broken = 0;
+             exp->exp_start_time = ts;
+             str = attrs->getValue (NTXT ("time"));
+             if (str != NULL)
+               exp->start_sec = atol (str);
+             str = attrs->getValue (NTXT ("pid"));
+             if (str != NULL)
+               exp->pid = atoi (str);
+             str = attrs->getValue (NTXT ("ppid"));
+             if (str != NULL)
+               exp->ppid = atoi (str);
+             str = attrs->getValue (NTXT ("pgrp"));
+             if (str != NULL)
+               exp->pgrp = atoi (str);
+             str = attrs->getValue (NTXT ("sid"));
+             if (str != NULL)
+               exp->sid = atoi (str);
+             exp->status = Experiment::INCOMPLETE;
+           }
+         else if (strcmp (str, SP_JCMD_ARCHIVE) == 0)
+           {
+             StringBuilder sb;
+             sb.sprintf (GTXT ("er_archive run: XXXXXXX"));
+             exp->pprocq->append (new Emsg (CMSG_WARN, sb));
+           }
+         else if (strcmp (str, SP_JCMD_SAMPLE) == 0)
+           {
+             exp->update_last_event (exp->exp_start_time + ts); // ts is 0-based
+             str = attrs->getValue (NTXT ("id"));
+             int id = str ? atoi (str) : -1;
+             char *label = dbe_strdup (attrs->getValue (NTXT ("label")));
+             exp->process_sample_cmd (NULL, ts, id, label);
+           }
+         else if (strcmp (str, SP_JCMD_EXIT) == 0)
+           {
+             // don't treat EXIT as an event w.r.t. last_event and non_paused_time
+             exp->status = Experiment::SUCCESS;
+           }
+         else if (strcmp (str, SP_JCMD_CERROR) == 0)
+           {
+             mkind = CMSG_ERROR;
+             str = attrs->getValue (NTXT ("id"));
+             if (str != NULL)
+               {
+                 mnum = atoi (str);
+               }
+             str = attrs->getValue (NTXT ("ec"));
+             if (str != NULL)
+               {
+                 mec = atoi (str);
+               }
+           }
+         else if (strcmp (str, SP_JCMD_CWARN) == 0)
+           {
+             mkind = CMSG_WARN;
+             str = attrs->getValue (NTXT ("id"));
+             if (str != NULL)
+               mnum = atoi (str);
+           }
+         else if (strcmp (str, SP_JCMD_COMMENT) == 0)
+           {
+             mkind = CMSG_COMMENT;
+             str = attrs->getValue (NTXT ("id"));
+             if (str != NULL)
+               mnum = atoi (str);
+             str = attrs->getValue (NTXT ("text"));
+             if (str != NULL)
+               {
+                 StringBuilder sb;
+                 sb.sprintf (GTXT ("*** Note: %s"), str);
+                 exp->commentq->append (new Emsg (CMSG_COMMENT, sb));
+               }
+           }
+         else if (strcmp (str, SP_JCMD_DESC_START) == 0)
+           {
+             char *variant = toStr (attrs, NTXT ("variant"));
+             char *lineage = toStr (attrs, NTXT ("lineage"));
+             int follow = toInt (attrs, NTXT ("follow"));
+             char *msg = toStr (attrs, NTXT ("msg"));
+             exp->process_desc_start_cmd (NULL, ts, variant, lineage, follow, msg);
+           }
+         else if (strcmp (str, SP_JCMD_DESC_STARTED) == 0)
+           {
+             char *variant = toStr (attrs, NTXT ("variant"));
+             char *lineage = toStr (attrs, NTXT ("lineage"));
+             int follow = toInt (attrs, NTXT ("follow"));
+             char *msg = toStr (attrs, NTXT ("msg"));
+             exp->process_desc_started_cmd (NULL, ts, variant, lineage, follow, msg);
+           }
+         else if (strcmp (str, SP_JCMD_EXEC_START) == 0)
+           {
+             // if successful, acts like experiment termination - no "exit" entry will follow
+             exp->update_last_event (exp->exp_start_time + ts); // ts is 0-based
+             char *variant = toStr (attrs, NTXT ("variant"));
+             char *lineage = toStr (attrs, NTXT ("lineage"));
+             int follow = toInt (attrs, NTXT ("follow"));
+             char *msg = toStr (attrs, NTXT ("msg"));
+             exp->process_desc_start_cmd (NULL, ts, variant, lineage, follow, msg);
+             exp->exec_started = true;
+           }
+         else if (strcmp (str, SP_JCMD_EXEC_ERROR) == 0)
+           {
+             exp->update_last_event (exp->exp_start_time + ts); // ts is 0-based
+             char *variant = toStr (attrs, NTXT ("variant"));
+             char *lineage = toStr (attrs, NTXT ("lineage"));
+             int follow = toInt (attrs, NTXT ("follow"));
+             char *msg = toStr (attrs, NTXT ("msg"));
+             exp->process_desc_started_cmd (NULL, ts, variant, lineage, follow, msg);
+             exp->exec_started = false;
+           }
+         else if (strcmp (str, SP_JCMD_JTHRSTART) == 0)
+           {
+             char *name = dbe_strdup (attrs->getValue (NTXT ("name")));
+             char *grpname = dbe_strdup (attrs->getValue (NTXT ("grpname")));
+             char *prntname = dbe_strdup (attrs->getValue (NTXT ("prntname")));
+             str = attrs->getValue (NTXT ("tid"));
+             uint64_t tid = str ? strtoull (str, NULL, 0) : 0;
+             str = attrs->getValue (NTXT ("jthr"));
+             Vaddr jthr = str ? strtoull (str, NULL, 0) : 0;
+             str = attrs->getValue (NTXT ("jenv"));
+             Vaddr jenv = str ? strtoull (str, NULL, 0) : 0;
+             exp->process_jthr_start_cmd (NULL, name, grpname, prntname, tid, jthr, jenv, ts);
+           }
+         else if (strcmp (str, SP_JCMD_JTHREND) == 0)
+           {
+             str = attrs->getValue (NTXT ("tid"));
+             uint64_t tid = str ? strtoull (str, NULL, 0) : 0;
+             str = attrs->getValue (NTXT ("jthr"));
+             Vaddr jthr = str ? strtoull (str, NULL, 0) : 0;
+             str = attrs->getValue (NTXT ("jenv"));
+             Vaddr jenv = str ? strtoull (str, NULL, 0) : 0;
+             exp->process_jthr_end_cmd (NULL, tid, jthr, jenv, ts);
+           }
+         else if (strcmp (str, SP_JCMD_GCEND) == 0)
+           {
+             if (exp->getDataDescriptor (DATA_GCEVENT) == NULL)
+               exp->newDataDescriptor (DATA_GCEVENT);
+             exp->process_gc_end_cmd (ts);
+           }
+         else if (strcmp (str, SP_JCMD_GCSTART) == 0)
+           {
+             if (exp->getDataDescriptor (DATA_GCEVENT) == NULL)
+               exp->newDataDescriptor (DATA_GCEVENT);
+             exp->process_gc_start_cmd (ts);
+           }
+         else if (strcmp (str, SP_JCMD_PAUSE) == 0)
+           {
+             if (exp->resume_ts != MAX_TIME)
+               {
+                 // data collection was active
+                 hrtime_t delta = ts - exp->resume_ts;
+                 exp->non_paused_time += delta;
+                 exp->resume_ts = MAX_TIME; // collection is paused
+               }
+             StringBuilder sb;
+             str = attrs->getValue (NTXT ("name"));
+             if (str == NULL)
+               sb.sprintf (GTXT ("Pause: %ld.%09ld"), (long) (ts / NANOSEC),
+                           (long) (ts % NANOSEC));
+             else
+               sb.sprintf (GTXT ("Pause (%s): %ld.%09ld"), str,
+                           (long) (ts / NANOSEC), (long) (ts % NANOSEC));
+             exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
+           }
+         else if (strcmp (str, SP_JCMD_RESUME) == 0)
+           {
+             if (exp->resume_ts == MAX_TIME)
+               // data collection was paused
+               exp->resume_ts = ts; // remember start time
+             StringBuilder sb;
+             sb.sprintf (GTXT ("Resume: %ld.%09ld"), (long) (ts / NANOSEC), (long) (ts % NANOSEC));
+             exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
+             if (exp->exp_start_time == ZERO_TIME)
+               exp->exp_start_time = ts;
+           }
+         else if (strcmp (str, SP_JCMD_THREAD_PAUSE) == 0)
+           {
+             str = attrs->getValue (NTXT ("tid"));
+             uint64_t tid = str ? strtoull (str, NULL, 0) : 0;
+             StringBuilder sb;
+             sb.sprintf (GTXT ("Thread %llu pause: %ld.%09ld"), (unsigned long long) tid,
+                         (long) (ts / NANOSEC), (long) (ts % NANOSEC));
+             exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
+           }
+         else if (strcmp (str, SP_JCMD_THREAD_RESUME) == 0)
+           {
+             str = attrs->getValue (NTXT ("tid"));
+             uint64_t tid = str ? strtoull (str, NULL, 0) : 0;
+             StringBuilder sb;
+             sb.sprintf (GTXT ("Thread %llu resume: %ld.%09ld"), (unsigned long long) tid,
+                         (long) (ts / NANOSEC), (long) (ts % NANOSEC));
+             exp->runlogq->append (new Emsg (CMSG_COMMENT, sb));
+           }
+         else if (strcmp (str, NTXT ("map")) == 0)
+           {
+             ts += exp->exp_start_time;
+             str = attrs->getValue (NTXT ("vaddr"));
+             Vaddr vaddr = str ? strtoull (str, NULL, 0) : 0;
+             str = attrs->getValue (NTXT ("size"));
+             int msize = str ? atoi (str) : 0;
+             str = attrs->getValue (NTXT ("foffset"));
+             int64_t offset = str ? strtoll (str, NULL, 0) : 0;
+             str = attrs->getValue (NTXT ("modes"));
+             int64_t modes = str ? strtoll (str, NULL, 0) : 0;
+             str = attrs->getValue (NTXT ("chksum"));
+             int64_t chksum = 0;
+             if (str)
+               chksum = Elf::normalize_checksum (strtoll (str, NULL, 0));
+             char *name = (char *) attrs->getValue (NTXT ("name"));
+             str = attrs->getValue (NTXT ("object"));
+             if (strcmp (str, NTXT ("segment")) == 0)
+               {
+                 if (strcmp (name, NTXT ("LinuxKernel")) == 0)
+                   exp->process_Linux_kernel_cmd (ts);
+                 else
+                   exp->process_seg_map_cmd (NULL, ts, vaddr, msize, 0,
+                                             offset, modes, chksum, name);
+               }
+             else if (strcmp (str, NTXT ("function")) == 0)
+               {
+                 exp->process_fn_load_cmd (dynfuncModule, name, vaddr, msize, ts);
+                 dynfuncModule = NULL;
+               }
+             else if (strcmp (str, NTXT ("dynfunc")) == 0)
+               {
+                 if (dynfuncModule == NULL)
+                   {
+                     dynfuncModule = dbeSession->createModule (exp->get_dynfunc_lo (DYNFUNC_SEGMENT), name);
+                     dynfuncModule->flags |= MOD_FLAG_UNKNOWN;
+                     dynfuncModule->set_file_name (dbe_strdup (dynfuncModule->getMainSrc ()->get_name ()));
+                   }
+                 (void) exp->create_dynfunc (dynfuncModule,
+                                             (char*) attrs->getValue (NTXT ("funcname")), vaddr, msize);
+               }
+             else if (strcmp (str, NTXT ("jcm")) == 0)
+               {
+                 str = attrs->getValue (NTXT ("methodId"));
+                 Vaddr mid = str ? strtoull (str, NULL, 0) : 0;
+                 exp->process_jcm_load_cmd (NULL, mid, vaddr, msize, ts);
+               }
+           }
+         else if (strcmp (str, NTXT ("unmap")) == 0)
+           {
+             ts += exp->exp_start_time;
+             str = attrs->getValue (NTXT ("vaddr"));
+             Vaddr vaddr = str ? strtoull (str, NULL, 0) : 0;
+             exp->process_seg_unmap_cmd (NULL, ts, vaddr);
+           }
+       }
+      // end of code for event
+    }
+  else if (strcmp (qName, SP_TAG_PROFILE) == 0)
+    {
+      pushElem (EL_PROFILE);
+      const char *str = attrs->getValue (NTXT ("name"));
+      if (str == NULL)
+       return;
+      if (strcmp (str, NTXT ("profile")) == 0)
+       {
+         exp->coll_params.profile_mode = 1;
+         str = attrs->getValue (NTXT ("numstates"));
+         if (str != NULL)
+           exp->coll_params.lms_magic_id = atoi (str);
+         str = attrs->getValue (NTXT ("ptimer"));
+         if (str != NULL)
+           exp->coll_params.ptimer_usec = atoi (str); // microseconds
+
+         PropDescr *mstate_prop = NULL;
+         char * stateNames [/*LMS_NUM_STATES*/] = LMS_STATE_STRINGS;
+         char * stateUNames[/*LMS_NUM_STATES*/] = LMS_STATE_USTRINGS;
+         {
+           dDscr = exp->newDataDescriptor (DATA_CLOCK);
+           PropDescr *prop = new PropDescr (PROP_MSTATE, NTXT ("MSTATE"));
+           prop->uname = dbe_strdup (GTXT ("Thread state"));
+           prop->vtype = TYPE_UINT32;
+           // (states added below)
+           dDscr->addProperty (prop);
+           mstate_prop = prop;
+
+           prop = new PropDescr (PROP_NTICK, NTXT ("NTICK"));
+           prop->uname = dbe_strdup (GTXT ("Number of Profiling Ticks"));
+           prop->vtype = TYPE_UINT32;
+           dDscr->addProperty (prop);
+         }
+
+         switch (exp->coll_params.lms_magic_id)
+           {
+           case LMS_MAGIC_ID_SOLARIS:
+             exp->register_metric (Metric::CP_TOTAL);
+             exp->register_metric (Metric::CP_TOTAL_CPU);
+             exp->register_metric (Metric::CP_LMS_USER);
+             exp->register_metric (Metric::CP_LMS_SYSTEM);
+             exp->register_metric (Metric::CP_LMS_TRAP);
+             exp->register_metric (Metric::CP_LMS_DFAULT);
+             exp->register_metric (Metric::CP_LMS_TFAULT);
+             exp->register_metric (Metric::CP_LMS_KFAULT);
+             exp->register_metric (Metric::CP_LMS_STOPPED);
+             exp->register_metric (Metric::CP_LMS_WAIT_CPU);
+             exp->register_metric (Metric::CP_LMS_SLEEP);
+             exp->register_metric (Metric::CP_LMS_USER_LOCK);
+             for (int ii = 0; ii < LMS_NUM_SOLARIS_MSTATES; ii++)
+               mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
+             break;
+           case LMS_MAGIC_ID_ERKERNEL_KERNEL:
+             exp->register_metric (Metric::CP_KERNEL_CPU);
+             {
+               int ii = LMS_KERNEL_CPU;
+               mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
+             }
+             break;
+           case LMS_MAGIC_ID_ERKERNEL_USER:
+             exp->register_metric (Metric::CP_TOTAL_CPU);
+             exp->register_metric (Metric::CP_LMS_USER);
+             exp->register_metric (Metric::CP_LMS_SYSTEM);
+             {
+               int ii = LMS_KERNEL_CPU;
+               mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
+               ii = LMS_USER;
+               mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
+               ii = LMS_SYSTEM;
+               mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
+             }
+             break;
+           case LMS_MAGIC_ID_LINUX:
+             exp->register_metric (Metric::CP_TOTAL_CPU);
+             {
+               int ii = LMS_LINUX_CPU;
+               mstate_prop->addState (ii, stateNames[ii], stateUNames[ii]);
+             }
+             break;
+           default:
+             // odd
+             break;
+           }
+       }
+      else if (strcmp (str, NTXT ("heaptrace")) == 0)
+       {
+         exp->coll_params.heap_mode = 1;
+         exp->leaklistavail = true;
+         exp->heapdataavail = true;
+         exp->register_metric (Metric::HEAP_ALLOC_BYTES);
+         exp->register_metric (Metric::HEAP_ALLOC_CNT);
+         exp->register_metric (Metric::HEAP_LEAK_BYTES);
+         exp->register_metric (Metric::HEAP_LEAK_CNT);
+         dDscr = exp->newDataDescriptor (DATA_HEAP);
+       }
+      else if (strcmp (str, NTXT ("iotrace")) == 0)
+       {
+         exp->coll_params.io_mode = 1;
+         exp->iodataavail = true;
+         exp->register_metric (Metric::IO_READ_TIME);
+         exp->register_metric (Metric::IO_READ_BYTES);
+         exp->register_metric (Metric::IO_READ_CNT);
+         exp->register_metric (Metric::IO_WRITE_TIME);
+         exp->register_metric (Metric::IO_WRITE_BYTES);
+         exp->register_metric (Metric::IO_WRITE_CNT);
+         exp->register_metric (Metric::IO_OTHER_TIME);
+         exp->register_metric (Metric::IO_OTHER_CNT);
+         exp->register_metric (Metric::IO_ERROR_TIME);
+         exp->register_metric (Metric::IO_ERROR_CNT);
+         dDscr = exp->newDataDescriptor (DATA_IOTRACE);
+       }
+      else if (strcmp (str, NTXT ("synctrace")) == 0)
+       {
+         exp->coll_params.sync_mode = 1;
+         str = attrs->getValue (NTXT ("threshold"));
+         if (str != NULL)
+           exp->coll_params.sync_threshold = atoi (str);
+         str = attrs->getValue (NTXT ("scope"));
+         if (str != NULL)
+           exp->coll_params.sync_scope = atoi (str);
+         else  // Should only happen with old experiments; use the old default
+           exp->coll_params.sync_scope = SYNCSCOPE_NATIVE | SYNCSCOPE_JAVA;
+         exp->register_metric (Metric::SYNC_WAIT_TIME);
+         exp->register_metric (Metric::SYNC_WAIT_COUNT);
+         dDscr = exp->newDataDescriptor (DATA_SYNCH);
+       }
+      else if (strcmp (str, NTXT ("omptrace")) == 0)
+       {
+         exp->coll_params.omp_mode = 1;
+         dDscr = exp->newDataDescriptor (DATA_OMP, DDFLAG_NOSHOW);
+       }
+      else if (strcmp (str, NTXT ("hwcounter")) == 0)
+       {
+         str = attrs->getValue (NTXT ("cpuver"));
+         int cpuver = str ? atoi (str) : 0;
+         char *counter = dbe_strdup (attrs->getValue (NTXT ("hwcname")));
+         char *int_name = dbe_strdup (attrs->getValue (NTXT ("int_name"))); // may not be present
+         str = attrs->getValue (NTXT ("interval"));
+         int interval = str ? atoi (str) : 0;
+         str = attrs->getValue (NTXT ("tag"));
+         int tag = str ? atoi (str) : 0;
+         str = attrs->getValue (NTXT ("memop"));
+         int i_tpc = str ? atoi (str) : 0;
+         char *modstr = dbe_strdup (attrs->getValue (NTXT ("modstr")));
+         exp->process_hwcounter_cmd (NULL, cpuver, counter, int_name, interval, tag, i_tpc, modstr);
+         dDscr = exp->newDataDescriptor (DATA_HWC);
+       }
+      else if (strcmp (str, NTXT ("hwsimctr")) == 0)
+       {
+         int cpuver = toInt (attrs, NTXT ("cpuver"));
+         char *hwcname = dbe_strdup (attrs->getValue (NTXT ("hwcname")));
+         char *int_name = dbe_strdup (attrs->getValue (NTXT ("int_name")));
+         char *metric = dbe_strdup (attrs->getValue (NTXT ("metric")));
+         int reg = toInt (attrs, NTXT ("reg_num"));
+         int interval = toInt (attrs, NTXT ("interval"));
+         int timecvt = toInt (attrs, NTXT ("timecvt"));
+         int i_tpc = toInt (attrs, NTXT ("memop"));
+         int tag = toInt (attrs, NTXT ("tag"));
+         exp->process_hwsimctr_cmd (NULL, cpuver, hwcname, int_name, metric, reg,
+                                    interval, timecvt, i_tpc, tag);
+         dDscr = exp->newDataDescriptor (DATA_HWC);
+       }
+      else if (strcmp (str, NTXT ("dversion")) == 0)
+       exp->dversion = dbe_strdup (attrs->getValue (NTXT ("version")));
+      else if (strcmp (str, NTXT ("jprofile")) == 0)
+       {
+         exp->has_java = true;
+         str = attrs->getValue (NTXT ("jversion"));
+         if (str != NULL)
+           exp->jversion = strdup (str);
+       }
+      else if (strcmp (str, NTXT ("datarace")) == 0)
+       {
+         exp->coll_params.race_mode = 1;
+         exp->racelistavail = true;
+         str = attrs->getValue (NTXT ("scheme"));
+         exp->coll_params.race_stack = str ? atoi (str) : 0;
+         exp->register_metric (Metric::RACCESS);
+         dDscr = exp->newDataDescriptor (DATA_RACE);
+       }
+      else if (strcmp (str, NTXT ("deadlock")) == 0)
+       {
+         exp->coll_params.deadlock_mode = 1;
+         exp->deadlocklistavail = true;
+         exp->register_metric (Metric::DEADLOCKS);
+         dDscr = exp->newDataDescriptor (DATA_DLCK);
+       }
+    }
+    /* XXX -- obsolete tag, but is still written to experiments */
+  else if (strcmp (qName, SP_TAG_DATAPTR) == 0)
+    {
+      pushElem (EL_DATAPTR);
+      return;
+    }
+  else if (strcmp (qName, SP_TAG_PROFDATA) == 0)
+    {
+      pushElem (EL_PROFDATA);
+      // SS12 HWC experiments are not well structured
+      const char *fname = attrs->getValue (NTXT ("fname"));
+      if (fname && strcmp (fname, SP_HWCNTR_FILE) == 0)
+       dDscr = exp->newDataDescriptor (DATA_HWC);
+    }
+  else if (strcmp (qName, SP_TAG_PROFPCKT) == 0)
+    {
+      pushElem (EL_PROFPCKT);
+      const char *str = attrs->getValue (NTXT ("kind")); // see Pckt_type
+      int kind = str ? atoi (str) : -1;
+      if (kind < 0)
+       return;
+      if (exp->coll_params.omp_mode == 1)
+       {
+         if (kind == OMP_PCKT)
+           dDscr = exp->newDataDescriptor (DATA_OMP, DDFLAG_NOSHOW);
+         else if (kind == OMP2_PCKT)
+           dDscr = exp->newDataDescriptor (DATA_OMP2, DDFLAG_NOSHOW);
+         else if (kind == OMP3_PCKT)
+           dDscr = exp->newDataDescriptor (DATA_OMP3, DDFLAG_NOSHOW);
+         else if (kind == OMP4_PCKT)
+           dDscr = exp->newDataDescriptor (DATA_OMP4, DDFLAG_NOSHOW);
+         else if (kind == OMP5_PCKT)
+           dDscr = exp->newDataDescriptor (DATA_OMP5, DDFLAG_NOSHOW);
+       }
+      pDscr = exp->newPacketDescriptor (kind, dDscr);
+      return;
+    }
+  else if (strcmp (qName, SP_TAG_FIELD) == 0)
+    {
+      pushElem (EL_FIELD);
+      if (pDscr != NULL)
+       {
+         const char *name = attrs->getValue (NTXT ("name"));
+         if (name == NULL)
+           return;
+         int propID = dbeSession->registerPropertyName (name);
+         propDscr = new PropDescr (propID, name);
+         FieldDescr *fldDscr = new FieldDescr (propID, name);
+
+         const char *str = attrs->getValue (NTXT ("type"));
+         if (str)
+           {
+             if (strcmp (str, NTXT ("INT32")) == 0)
+               fldDscr->vtype = TYPE_INT32;
+             else if (strcmp (str, NTXT ("UINT32")) == 0)
+               fldDscr->vtype = TYPE_UINT32;
+             else if (strcmp (str, NTXT ("INT64")) == 0)
+               fldDscr->vtype = TYPE_INT64;
+             else if (strcmp (str, NTXT ("UINT64")) == 0)
+               fldDscr->vtype = TYPE_UINT64;
+             else if (strcmp (str, NTXT ("STRING")) == 0)
+               fldDscr->vtype = TYPE_STRING;
+             else if (strcmp (str, NTXT ("DOUBLE")) == 0)
+               fldDscr->vtype = TYPE_DOUBLE;
+             else if (strcmp (str, NTXT ("DATE")) == 0)
+               {
+                 fldDscr->vtype = TYPE_DATE;
+                 const char *fmt = attrs->getValue (NTXT ("format"));
+                 fldDscr->format = strdup (fmt ? fmt : "");
+               }
+           }
+         propDscr->vtype = fldDscr->vtype;
+
+         // TYPE_DATE is converted to TYPE_UINT64 in propDscr
+         if (fldDscr->vtype == TYPE_DATE)
+           propDscr->vtype = TYPE_UINT64;
+
+         // Fix some types until they are fixed in libcollector
+         if (propID == PROP_VIRTPC || propID == PROP_PHYSPC)
+           {
+             if (fldDscr->vtype == TYPE_INT32)
+               propDscr->vtype = TYPE_UINT32;
+             else if (fldDscr->vtype == TYPE_INT64)
+               propDscr->vtype = TYPE_UINT64;
+           }
+
+         // The following props get mapped to 32-bit values in readPacket
+         if (propID == PROP_CPUID || propID == PROP_THRID
+             || propID == PROP_LWPID)
+           propDscr->vtype = TYPE_UINT32; // override experiment property
+
+         str = attrs->getValue (NTXT ("uname"));
+         if (str)
+           propDscr->uname = strdup (PTXT ((char*) str));
+         str = attrs->getValue (NTXT ("noshow"));
+         if (str && atoi (str) != 0)
+           propDscr->flags |= PRFLAG_NOSHOW;
+
+         if (dDscr == NULL)
+           {
+             StringBuilder sb;
+             sb.sprintf (GTXT ("*** Error: data parsing failed. Log file is corrupted."));
+             exp->warnq->append (new Emsg (CMSG_ERROR, sb));
+             throw new SAXException (sb.toString ());
+           }
+
+         dDscr->addProperty (propDscr);
+         str = attrs->getValue (NTXT ("offset"));
+         if (str)
+           fldDscr->offset = atoi (str);
+         pDscr->addField (fldDscr);
+       }
+    }
+  else if (strcmp (qName, SP_TAG_STATE) == 0)
+    {
+      pushElem (EL_STATE);
+      if (propDscr != NULL)
+       {
+         const char *str = attrs->getValue (NTXT ("value"));
+         int value = str ? atoi (str) : -1;
+         str = attrs->getValue (NTXT ("name"));
+         const char *ustr = attrs->getValue (NTXT ("uname"));
+         propDscr->addState (value, str, ustr);
+       }
+    }
+  else if (strcmp (qName, SP_TAG_DTRACEFATAL) == 0)
+    pushElem (EL_DTRACEFATAL);
+  else
+    {
+      StringBuilder sb;
+      sb.sprintf (GTXT ("*** Warning: unrecognized element %s"), qName);
+      exp->warnq->append (new Emsg (CMSG_WARN, sb));
+      pushElem (EL_NONE);
+    }
+}
+
+void
+Experiment::ExperimentHandler::characters (char *ch, int start, int length)
+{
+  switch (curElem)
+    {
+    case EL_COLLECTOR:
+      exp->cversion = dbe_strndup (ch + start, length);
+      break;
+    case EL_PROCESS:
+      exp->process_arglist_cmd (NULL, dbe_strndup (ch + start, length));
+      break;
+    case EL_EVENT:
+      free (text);
+      text = dbe_strndup (ch + start, length);
+      break;
+    default:
+      break;
+    }
+}
+
+void
+Experiment::ExperimentHandler::endElement (char*, char*, char*)
+{
+  if (curElem == EL_EVENT && mkind >= 0 && mnum >= 0)
+    {
+      char *str;
+      if (mec > 0)
+       str = dbe_sprintf ("%s -- %s", text != NULL ? text : "", strerror (mec));
+      else
+       str = dbe_sprintf ("%s", text != NULL ? text : "");
+      Emsg *msg = new Emsg (mkind, mnum, str);
+      if (mkind == CMSG_WARN)
+       {
+         if (mnum != COL_WARN_FSTYPE
+             || dbeSession->check_ignore_fs_warn () == false)
+           exp->warnq->append (msg);
+         else
+           exp->commentq->append (msg);
+       }
+      else if (mkind == CMSG_ERROR || mkind == CMSG_FATAL)
+       exp->errorq->append (msg);
+      else if (mkind == CMSG_COMMENT)
+       exp->commentq->append (msg);
+      else
+       delete msg;
+      mkind = (Cmsg_warn) - 1;
+      mnum = -1;
+      mec = -1;
+    }
+  else if (curElem == EL_PROFILE)
+    dDscr = NULL;
+  else if (curElem == EL_PROFPCKT)
+    pDscr = NULL;
+  else if (curElem == EL_FIELD)
+    propDscr = NULL;
+  free (text);
+  text = NULL;
+  popElem ();
+}
+
+void
+Experiment::ExperimentHandler::error (SAXParseException *e)
+{
+  StringBuilder sb;
+  sb.sprintf (GTXT ("%s at line %d, column %d"),
+             e->getMessage (), e->getLineNumber (), e->getColumnNumber ());
+  char *msg = sb.toString ();
+  SAXException *e1 = new SAXException (msg);
+  free (msg);
+  throw ( e1);
+}
+
+//-------------------------------------------------- Experiment
+
+Experiment::Experiment ()
+{
+  groupId = 0;
+  userExpId = expIdx = -1;
+  founder_exp = NULL;
+  baseFounder = NULL;
+  children_exps = new Vector<Experiment*>;
+  loadObjs = new Vector<LoadObject*>;
+  loadObjMap = new StringMap<LoadObject*>(128, 128);
+  sourcesMap = NULL;
+
+  // Initialize configuration information.
+  status = FAILURE;
+  start_sec = 0;
+  mtime = 0;
+  hostname = NULL;
+  username = NULL;
+  architecture = NULL;
+  os_version = NULL;
+  uarglist = NULL;
+  utargname = NULL;
+  ucwd = NULL;
+  cversion = NULL;
+  dversion = NULL;
+  jversion = NULL;
+  exp_maj_version = 0;
+  exp_min_version = 0;
+  platform = Unknown;
+  wsize = Wnone;
+  page_size = 4096;
+  npages = 0;
+  stack_base = 0xf0000000;
+  broken = 1;
+  obsolete = 0;
+  hwc_bogus = 0;
+  hwc_lost_int = 0;
+  hwc_scanned = 0;
+  hwc_default = false;
+  invalid_packet = 0;
+
+  // clear HWC event stats
+  dsevents = 0;
+  dsnoxhwcevents = 0;
+
+  memset (&coll_params, 0, sizeof (coll_params));
+  ncpus = 0;
+  minclock = 0;
+  maxclock = 0;
+  clock = 0;
+  varclock = 0;
+  exec_started = false;
+  timelineavail = true;
+  leaklistavail = false;
+  heapdataavail = false;
+  iodataavail = false;
+  dataspaceavail = false;
+  ifreqavail = false;
+  racelistavail = false;
+  deadlocklistavail = false;
+  ompavail = false;
+  tiny_threshold = -1;
+  pid = 0;
+  ppid = 0;
+  pgrp = 0;
+  sid = 0;
+
+  gc_duration = ZERO_TIME;
+  exp_start_time = ZERO_TIME; // not known.  Wall-clock hrtime (not zero based)
+  last_event = ZERO_TIME; // not known.  Wall-clock hrtime (not zero based)
+  non_paused_time = 0; // 0 non-paused time (will sum as experiment is processed)
+  resume_ts = 0; // by default, collection is "resumed" (not paused) from time=0
+  need_swap_endian = false;
+  exp_rel_start_time_set = false;
+  exp_rel_start_time = ZERO_TIME;
+  has_java = false;
+  hex_field_width = 8;
+  hw_cpuver = CPUVER_UNDEFINED;
+  machinemodel = NULL;
+  expt_name = NULL;
+  arch_name = NULL;
+  fndr_arch_name = NULL;
+  logFile = NULL;
+
+  dataDscrs = new Vector<DataDescriptor*>;
+  for (int i = 0; i < DATA_LAST; ++i)
+    dataDscrs->append (NULL);
+
+  pcktDscrs = new Vector<PacketDescriptor*>;
+  blksz = PROFILE_BUFFER_CHUNK;
+  jthreads = new Vector<JThread*>;
+  jthreads_idx = new Vector<JThread*>;
+  gcevents = new Vector<GCEvent*>;
+  gcevent_last_used = (GCEvent *) NULL;
+  heapUnmapEvents = new Vector<UnmapChunk*>;
+  cstack = NULL;
+  cstackShowHide = NULL;
+  frmpckts = new Vector<RawFramePacket*>;
+  typedef DefaultMap2D<uint32_t, hrtime_t, uint64_t> OmpMap0;
+  mapPRid = new OmpMap0 (OmpMap0::Interval);
+  typedef DefaultMap2D<uint32_t, hrtime_t, void*> OmpMap;
+  mapPReg = new OmpMap (OmpMap::Interval);
+  mapTask = new OmpMap (OmpMap::Interval);
+  openMPdata = NULL;
+  archiveMap = NULL;
+  nnodes = 0;
+  nchunks = 0;
+  chunks = 0;
+  uidHTable = NULL;
+  uidnodes = new Vector<UIDnode*>;
+  mrecs = new Vector<MapRecord*>;
+  samples = new Vector<Sample*>;
+  sample_last_used = (Sample *) NULL;
+  first_sample_label = (char*) NULL;
+  fDataMap = NULL;
+  vFdMap = NULL;
+  resolveFrameInfo = true;
+  discardTiny = false;
+  init ();
+}
+
+Experiment::~Experiment ()
+{
+  fini ();
+  free (coll_params.linetrace);
+  for (int i = 0; i < MAX_HWCOUNT; i++)
+    {
+      free (coll_params.hw_aux_name[i]);
+      free (coll_params.hw_username[i]);
+    }
+  free (hostname);
+  free (username);
+  free (architecture);
+  free (os_version);
+  free (uarglist);
+  free (utargname);
+  free (ucwd);
+  free (cversion);
+  free (dversion);
+  free (jversion);
+  delete logFile;
+  free (expt_name);
+  free (arch_name);
+  free (fndr_arch_name);
+  delete jthreads_idx;
+  delete cstack;
+  delete cstackShowHide;
+  delete mapPRid;
+  delete mapPReg;
+  delete mapTask;
+  delete openMPdata;
+  destroy_map (DbeFile *, archiveMap);
+  delete[] uidHTable;
+  delete uidnodes;
+  delete mrecs;
+  delete children_exps;
+  delete loadObjs;
+  delete loadObjMap;
+  delete sourcesMap;
+  free (first_sample_label);
+  free (machinemodel);
+
+  dataDscrs->destroy ();
+  delete dataDscrs;
+  pcktDscrs->destroy ();
+  delete pcktDscrs;
+  jthreads->destroy ();
+  delete jthreads;
+  gcevents->destroy ();
+  delete gcevents;
+  heapUnmapEvents->destroy ();
+  delete heapUnmapEvents;
+  frmpckts->destroy ();
+  delete frmpckts;
+  samples->destroy ();
+  delete samples;
+  delete fDataMap;
+  delete vFdMap;
+
+  for (long i = 0; i < nchunks; i++)
+    delete[] chunks[i];
+  delete[] chunks;
+}
+
+void
+Experiment::init_cache ()
+{
+  if (smemHTable)
+    return;
+  smemHTable = new SegMem*[HTableSize];
+  instHTable = new DbeInstr*[HTableSize];
+  for (int i = 0; i < HTableSize; i++)
+    {
+      smemHTable[i] = NULL;
+      instHTable[i] = NULL;
+    }
+  uidHTable = new UIDnode*[HTableSize];
+  for (int i = 0; i < HTableSize; i++)
+    uidHTable[i] = NULL;
+
+  cstack = CallStack::getInstance (this);
+  cstackShowHide = CallStack::getInstance (this);
+}
+
+void
+Experiment::init ()
+{
+  userLabels = NULL;
+  seg_items = new Vector<SegMem*>;
+  maps = new PRBTree ();
+  jmaps = NULL; // used by JAVA_CLASSES only
+  jmidHTable = NULL;
+  smemHTable = NULL;
+  instHTable = NULL;
+  min_thread = (uint64_t) - 1;
+  max_thread = 0;
+  thread_cnt = 0;
+  min_lwp = (uint64_t) - 1;
+  max_lwp = 0;
+  lwp_cnt = 0;
+  min_cpu = (uint64_t) - 1;
+  max_cpu = 0;
+  cpu_cnt = 0;
+
+  commentq = new Emsgqueue (NTXT ("commentq"));
+  runlogq = new Emsgqueue (NTXT ("runlogq"));
+  errorq = new Emsgqueue (NTXT ("errorq"));
+  warnq = new Emsgqueue (NTXT ("warnq"));
+  notesq = new Emsgqueue (NTXT ("notesq"));
+  pprocq = new Emsgqueue (NTXT ("pprocq"));
+  ifreqq = NULL;
+
+  metrics = new Vector<BaseMetric*>;
+  tagObjs = new Vector<Vector<Histable*>*>;
+  tagObjs->store (PROP_THRID, new Vector<Histable*>);
+  tagObjs->store (PROP_LWPID, new Vector<Histable*>);
+  tagObjs->store (PROP_CPUID, new Vector<Histable*>);
+  tagObjs->store (PROP_EXPID, new Vector<Histable*>);
+  sparse_threads = false;
+}
+
+void
+Experiment::fini ()
+{
+  seg_items->destroy ();
+  delete seg_items;
+  delete maps;
+  delete jmaps;
+  delete[] smemHTable;
+  delete[] instHTable;
+  delete jmidHTable;
+  delete commentq;
+  delete runlogq;
+  delete errorq;
+  delete warnq;
+  delete notesq;
+  delete pprocq;
+  if (ifreqq != NULL)
+    {
+      delete ifreqq;
+      ifreqq = NULL;
+    }
+
+  int index;
+  BaseMetric *mtr;
+  Vec_loop (BaseMetric*, metrics, index, mtr)
+  {
+    dbeSession->drop_metric (mtr);
+  }
+  delete metrics;
+  tagObjs->fetch (PROP_THRID)->destroy ();
+  tagObjs->fetch (PROP_LWPID)->destroy ();
+  tagObjs->fetch (PROP_CPUID)->destroy ();
+  tagObjs->fetch (PROP_EXPID)->destroy ();
+  tagObjs->destroy ();
+  delete tagObjs;
+}
+
+// These are the data files which can be read in parallel
+// for multiple sub-experiments.
+// Postpone calling resolve_frame_info()
+void
+Experiment::read_experiment_data (bool read_ahead)
+{
+
+  read_frameinfo_file ();
+  if (read_ahead)
+    {
+      resolveFrameInfo = false;
+      (void) get_profile_events ();
+      resolveFrameInfo = true;
+    }
+}
+
+Experiment::Exp_status
+Experiment::open_epilogue ()
+{
+
+  // set up mapping for tagObj(PROP_EXPID)
+  (void) mapTagValue (PROP_EXPID, userExpId);
+
+  post_process ();
+  if (last_event != ZERO_TIME)
+    { // if last_event is known
+      StringBuilder sb;
+      hrtime_t ts = last_event - exp_start_time;
+      sb.sprintf (GTXT ("Experiment Ended: %ld.%09ld\nData Collection Duration: %ld.%09ld"),
+                 (long) (ts / NANOSEC), (long) (ts % NANOSEC),
+                 (long) (non_paused_time / NANOSEC),
+                 (long) (non_paused_time % NANOSEC));
+      runlogq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+
+  // Check for incomplete experiment, and inform the user
+  if (status == INCOMPLETE)
+    {
+      if (exec_started == true)
+       // experiment ended with the exec, not abnormally
+       status = SUCCESS;
+      else
+       {
+         char * cmnt = GTXT ("*** Note: experiment was not closed");
+         commentq->append (new Emsg (CMSG_COMMENT, cmnt));
+         // runlogq->append(new Emsg(CMSG_COMMENT, cmnt));
+       }
+    }
+  // write a descriptive header for the experiment
+  write_header ();
+  return status;
+}
+
+Experiment::Exp_status
+Experiment::open (char *path)
+{
+
+  // Find experiment directory
+  if (find_expdir (path) != SUCCESS)
+    // message will have been queued and status set
+    return status;
+
+  // Get creation time for experiment
+  struct stat64 st;
+  if (dbe_stat (path, &st) == 0)
+    mtime = st.st_mtime;
+
+  // Read the warnings file
+  read_warn_file ();
+
+  // Open the log file
+  read_log_file ();
+  if (status == SUCCESS && last_event // last event is initialized
+      && (last_event - exp_start_time) / 1000000 < tiny_threshold)
+    {
+      // Process "tiny_threshold" (SP_ANALYZER_DISCARD_TINY_EXPERIMENTS)
+      // At this point, we've only processed log.xml.
+      // Note: if an experiment terminated abnormally, last_event will not yet
+      //   represent events from clock profiling and other metrics.
+      //   Other events will often have timestamps after the last log.xml entry.
+      discardTiny = true;
+      return status;
+    }
+  if (status == FAILURE)
+    {
+      if (logFile->get_status () == ExperimentFile::EF_FAILURE)
+       {
+         Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log file in experiment cannot be read"));
+         errorq->append (m);
+       }
+      else if (fetch_errors () == NULL)
+       {
+         if (broken == 1)
+           {
+             Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log does not show target starting"));
+             errorq->append (m);
+           }
+         else
+           {
+             Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: log file in experiment could not be parsed"));
+             errorq->append (m);
+           }
+       }
+      return status;
+    }
+  init_cache ();
+  if (varclock != 0)
+    {
+      StringBuilder sb;
+      sb.sprintf (
+                 GTXT ("*** Warning: system has variable clock frequency, which may cause variable execution times and inaccurate conversions of cycle counts into time."));
+      warnq->append (new Emsg (CMSG_WARN, sb));
+    }
+
+  // Read the notes file
+  read_notes_file ();
+  read_labels_file ();
+  read_archives ();
+
+  // The log file shows experiment started
+  read_java_classes_file ();
+
+  read_map_file ();
+
+  // Dyntext file has to be processed after loadobjects file
+  // as we need to be able to map (vaddr,ts) to dynamic functions.
+  read_dyntext_file ();
+
+  // Read the overview file and create samples.
+  // Profiling data hasn't been read yet so we may have
+  // events after the last recorded sample.
+  // We'll create a fake sample to cover all those
+  // events later.
+  read_overview_file ();
+
+  // Check if instruction frequency data is available
+  read_ifreq_file ();
+
+  // Check if OMP data is available
+  read_omp_file ();
+
+  return status;
+}
+
+/* XXX -- update() is a no-op now, but may be needed for auto-update */
+Experiment::Exp_status
+Experiment::update ()
+{
+  return status;
+}
+
+void
+Experiment::append (LoadObject *lo)
+{
+  loadObjs->append (lo);
+  char *obj_name = lo->get_pathname ();
+  char *bname = get_basename (obj_name);
+  loadObjMap->put (obj_name, lo);
+  loadObjMap->put (bname, lo);
+  if (lo->flags & SEG_FLAG_EXE)
+    loadObjMap->put (COMP_EXE_NAME, lo);
+}
+
+void
+Experiment::read_notes_file ()
+{
+  Emsg *m;
+
+  // Open log file:
+  char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE);
+  FILE *f = fopen (fname, NTXT ("r"));
+  free (fname);
+  if (f == NULL)
+    return;
+  if (!dbeSession->is_interactive ())
+    {
+      m = new Emsg (CMSG_COMMENT, NTXT ("Notes:"));
+      notesq->append (m);
+    }
+
+  while (1)
+    {
+      char str[MAXPATHLEN];
+      char *e = fgets (str, ((int) sizeof (str)) - 1, f);
+      if (e == NULL)
+       {
+         if (!dbeSession->is_interactive ())
+           {
+             m = new Emsg (CMSG_COMMENT,
+                           "============================================================");
+             notesq->append (m);
+           }
+         break;
+       }
+      size_t i = strlen (str);
+      if (i > 0 && str[i - 1] == '\n')
+       // remove trailing nl
+       str[i - 1] = 0;
+      m = new Emsg (CMSG_COMMENT, str);
+      notesq->append (m);
+    }
+  (void) fclose (f);
+}
+
+int
+Experiment::save_notes (char* text, bool handle_file)
+{
+  if (handle_file)
+    {
+      FILE *fnotes;
+      char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE);
+      fnotes = fopen (fname, NTXT ("w"));
+      free (fname);
+      if (fnotes != NULL)
+       {
+         (void) fprintf (fnotes, NTXT ("%s"), text);
+         fclose (fnotes);
+       }
+      else
+       return 1; // Cannot write file
+    }
+  notesq->clear ();
+  Emsg *m = new Emsg (CMSG_COMMENT, text);
+  notesq->append (m);
+
+  return 0;
+}
+
+int
+Experiment::delete_notes (bool handle_file)
+{
+  if (handle_file)
+    {
+      char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_NOTES_FILE);
+      if (unlink (fname) != 0)
+       {
+         free (fname);
+         return 1; // Cannot delete file
+       }
+      free (fname);
+    }
+  notesq->clear ();
+  return 0;
+}
+
+int
+Experiment::read_warn_file ()
+{
+  int local_status = SUCCESS;
+
+  ExperimentFile *warnFile = new ExperimentFile (this, SP_WARN_FILE);
+  if (warnFile == NULL)
+    return FAILURE;
+  if (!warnFile->open ())
+    {
+      delete warnFile;
+      return FAILURE;
+    }
+  SAXParserFactory *factory = SAXParserFactory::newInstance ();
+  SAXParser *saxParser = factory->newSAXParser ();
+  DefaultHandler *dh = new ExperimentHandler (this);
+  try
+    {
+      saxParser->parse ((File*) warnFile->fh, dh);
+    }
+  catch (SAXException *e)
+    {
+      // Fatal error in the parser
+      StringBuilder sb;
+      sb.sprintf (NTXT ("%s: %s"), SP_WARN_FILE, e->getMessage ());
+      char *str = sb.toString ();
+      Emsg *m = new Emsg (CMSG_FATAL, str);
+      errorq->append (m);
+      local_status = FAILURE;
+      delete e;
+    }
+  delete warnFile;
+  delete dh;
+  delete saxParser;
+  delete factory;
+
+  return local_status;
+}
+
+int
+Experiment::read_log_file ()
+{
+  if (logFile == NULL)
+    logFile = new ExperimentFile (this, SP_LOG_FILE);
+  if (!logFile->open ())
+    {
+      status = FAILURE;
+      return status;
+    }
+
+  SAXParserFactory *factory = SAXParserFactory::newInstance ();
+  SAXParser *saxParser = factory->newSAXParser ();
+  DefaultHandler *dh = new ExperimentHandler (this);
+  try
+    {
+      saxParser->parse ((File*) logFile->fh, dh);
+    }
+  catch (SAXException *e)
+    {
+      // Fatal error in the parser
+      StringBuilder sb;
+      if (obsolete == 1)
+       sb.sprintf (NTXT ("%s"), e->getMessage ());
+      else
+       sb.sprintf (NTXT ("%s: %s"), SP_LOG_FILE, e->getMessage ());
+      char *str = sb.toString ();
+      Emsg *m = new Emsg (CMSG_FATAL, str);
+      errorq->append (m);
+      status = FAILURE;
+      delete e;
+    }
+  logFile->close ();
+  dbeSession->register_metric (GTXT ("IPC"), GTXT ("Instructions Per Cycle"),
+                              NTXT ("insts/cycles"));
+  dbeSession->register_metric (GTXT ("CPI"), GTXT ("Cycles Per Instruction"),
+                              NTXT ("cycles/insts"));
+  dbeSession->register_metric (GTXT ("K_IPC"),
+                              GTXT ("Kernel Instructions Per Cycle"),
+                              NTXT ("K_insts/K_cycles"));
+  dbeSession->register_metric (GTXT ("K_CPI"),
+                              GTXT ("Kernel Cycles Per Instruction"),
+                              NTXT ("K_cycles/K_insts"));
+
+  delete dh;
+  delete saxParser;
+  delete factory;
+
+  return status;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//  class Experiment::ExperimentLabelsHandler
+//
+
+class Experiment::ExperimentLabelsHandler : public DefaultHandler
+{
+public:
+
+  ExperimentLabelsHandler (Experiment *_exp)
+  {
+    exp = _exp;
+  }
+
+  ~ExperimentLabelsHandler () { };
+  void startDocument () { }
+  void endDocument () { }
+  void endElement (char * /*uri*/, char * /*localName*/, char * /*qName*/) { }
+  void characters (char * /*ch*/, int /*start*/, int /*length*/) { }
+  void ignorableWhitespace (char*, int, int) { }
+  void error (SAXParseException * /*e*/) { }
+
+  void startElement (char *uri, char *localName, char *qName, Attributes *attrs);
+
+private:
+
+  inline const char *
+  s2s (const char *s)
+  {
+    return s ? s : "NULL";
+  }
+
+  Experiment *exp;
+  char *hostname;
+  hrtime_t time, tstamp;
+};
+
+void
+Experiment::ExperimentLabelsHandler::startElement (char*, char*, char *qName,
+                                                  Attributes *attrs)
+{
+  DEBUG_CODE if (DEBUG_SAXPARSER) dump_startElement (qName, attrs);
+  if (qName == NULL || strcmp (qName, NTXT ("id")) != 0)
+    return;
+  char *name = NULL, *all_times = NULL, *comment = NULL, *hostName = NULL;
+  long startSec = 0;
+  //    long tm_zone = 0;
+  hrtime_t startHrtime = (hrtime_t) 0;
+  long long lbl_ts = 0;
+  int relative = 0;
+  timeval start_tv;
+  start_tv.tv_usec = start_tv.tv_sec = 0;
+  for (int i = 0, sz = attrs ? attrs->getLength () : 0; i < sz; i++)
+    {
+      const char *qn = attrs->getQName (i);
+      const char *vl = attrs->getValue (i);
+      if (strcmp (qn, NTXT ("name")) == 0)
+       name = dbe_xml2str (vl);
+      else if (strcmp (qn, NTXT ("cmd")) == 0)
+       all_times = dbe_xml2str (vl);
+      else if (strcmp (qn, NTXT ("comment")) == 0)
+       comment = dbe_xml2str (vl);
+      else if (strcmp (qn, NTXT ("relative")) == 0)
+       relative = atoi (vl);
+      else if (strcmp (qn, NTXT ("hostname")) == 0)
+       hostName = dbe_xml2str (vl);
+      else if (strcmp (qn, NTXT ("time")) == 0)
+       startSec = atol (vl);
+      else if (strcmp (qn, NTXT ("tstamp")) == 0)
+       startHrtime = parseTStamp (vl);
+      else if (strcmp (qn, NTXT ("lbl_ts")) == 0)
+       {
+         if (*vl == '-')
+           lbl_ts = -parseTStamp (vl + 1);
+         else
+           lbl_ts = parseTStamp (vl);
+       }
+    }
+  if (name == NULL || hostName == NULL || (all_times == NULL && comment == NULL))
+    {
+      free (name);
+      free (hostName);
+      free (all_times);
+      free (comment);
+      return;
+    }
+  UserLabel *lbl = new UserLabel (name);
+  lbl->comment = comment;
+  lbl->hostname = hostName;
+  lbl->start_sec = startSec;
+  lbl->start_hrtime = startHrtime;
+  exp->userLabels->append (lbl);
+  if (all_times)
+    {
+      lbl->all_times = all_times;
+      lbl->start_tv = start_tv;
+      lbl->relative = relative;
+      if (relative == UserLabel::REL_TIME)
+       lbl->atime = lbl_ts;
+      else
+       { // relative == UserLabel::CUR_TIME
+         long long delta = 0;
+         if (exp->hostname && strcmp (lbl->hostname, exp->hostname) == 0)
+           delta = lbl_ts + (lbl->start_hrtime - exp->exp_start_time);
+         else
+           for (int i = 0; i < exp->userLabels->size (); i++)
+             {
+               UserLabel *firstLbl = exp->userLabels->fetch (i);
+               if (strcmp (lbl->hostname, firstLbl->hostname) == 0)
+                 {
+                   delta = lbl_ts + (lbl->start_hrtime - firstLbl->start_hrtime) +
+                           ((long long) (firstLbl->start_sec - exp->start_sec)) * NANOSEC;
+                   break;
+                 }
+             }
+         lbl->atime = delta > 0 ? delta : 0;
+       }
+    }
+}
+
+static int
+sortUserLabels (const void *a, const void *b)
+{
+  UserLabel *l1 = *((UserLabel **) a);
+  UserLabel *l2 = *((UserLabel **) b);
+  int v = dbe_strcmp (l1->name, l2->name);
+  if (v != 0)
+    return v;
+  if (l1->atime < l2->atime)
+    return -1;
+  else if (l1->atime > l2->atime)
+    return 1;
+  if (l1->id < l2->id)
+    return -1;
+  else if (l1->id > l2->id)
+    return 1;
+  return 0;
+}
+
+static char *
+append_string (char *s, char *str)
+{
+  if (s == NULL)
+    return dbe_strdup (str);
+  char *new_s = dbe_sprintf (NTXT ("%s %s"), s, str);
+  free (s);
+  return new_s;
+}
+
+void
+Experiment::read_labels_file ()
+{
+  ExperimentFile *fp = new ExperimentFile (this, SP_LABELS_FILE);
+  if (!fp->open ())
+    {
+      delete fp;
+      return;
+    }
+  userLabels = new Vector<UserLabel*>();
+  SAXParserFactory *factory = SAXParserFactory::newInstance ();
+  SAXParser *saxParser = factory->newSAXParser ();
+  DefaultHandler *dh = new ExperimentLabelsHandler (this);
+  try
+    {
+      saxParser->parse ((File*) fp->fh, dh);
+    }
+  catch (SAXException *e)
+    {
+      // Fatal error in the parser
+      StringBuilder sb;
+      sb.sprintf (NTXT ("%s: %s"), SP_LABELS_FILE, e->getMessage ());
+      char *str = sb.toString ();
+      Emsg *m = new Emsg (CMSG_FATAL, str);
+      errorq->append (m);
+      delete e;
+    }
+  fp->close ();
+  delete fp;
+  delete dh;
+  delete saxParser;
+  delete factory;
+
+  userLabels->sort (sortUserLabels);
+  UserLabel::dump ("After sortUserLabels:", userLabels);
+  UserLabel *ulbl = NULL;
+  for (int i = 0, sz = userLabels->size (); i < sz; i++)
+    {
+      UserLabel *lbl = userLabels->fetch (i);
+      if (ulbl == NULL)
+       ulbl = new UserLabel (lbl->name);
+      else if (dbe_strcmp (lbl->name, ulbl->name) != 0)
+       { // new Label
+         ulbl->register_user_label (groupId);
+         if (ulbl->expr == NULL)
+           delete ulbl;
+         ulbl = new UserLabel (lbl->name);
+       }
+      if (lbl->all_times)
+       {
+         if (strncmp (lbl->all_times, NTXT ("start"), 5) == 0)
+           {
+             if (!ulbl->start_f)
+               {
+                 ulbl->start_f = true;
+                 ulbl->timeStart = lbl->atime;
+               }
+           }
+         else
+           { // stop
+             if (!ulbl->start_f)
+               continue;
+             ulbl->all_times = append_string (ulbl->all_times, lbl->all_times);
+             ulbl->stop_f = true;
+             ulbl->timeStop = lbl->atime;
+             ulbl->gen_expr ();
+           }
+       }
+      if (lbl->comment != NULL)
+       ulbl->comment = append_string (ulbl->comment, lbl->comment);
+    }
+  if (ulbl)
+    {
+      ulbl->register_user_label (groupId);
+      if (ulbl->expr == NULL)
+       delete ulbl;
+    }
+  Destroy (userLabels);
+}
+
+void
+Experiment::read_archives ()
+{
+  if (founder_exp)
+    return;
+  char *allocated_str = NULL;
+  char *nm = get_arch_name ();
+  DIR *exp_dir = opendir (nm);
+  if (exp_dir == NULL)
+    {
+      if (founder_exp == NULL)
+       {
+         // Check if the user uses a subexperiment only
+         nm = dbe_sprintf (NTXT ("%s/../%s"), expt_name, SP_ARCHIVES_DIR);
+         exp_dir = opendir (nm);
+         if (exp_dir == NULL)
+           {
+             free (nm);
+             return;
+           }
+         allocated_str = nm;
+       }
+      else
+       return;
+    }
+
+  StringBuilder sb;
+  sb.append (nm);
+  sb.append ('/');
+  int dlen = sb.length ();
+  free (allocated_str);
+  archiveMap = new StringMap<DbeFile *>();
+
+  struct dirent *entry = NULL;
+  while ((entry = readdir (exp_dir)) != NULL)
+    {
+      char *dname = entry->d_name;
+      if (dname[0] == '.'
+         && (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0')))
+       // skip links to ./ or ../
+       continue;
+      sb.setLength (dlen);
+      sb.append (dname);
+      char *fnm = sb.toString ();
+      DbeFile *df = new DbeFile (fnm);
+      df->set_location (fnm);
+      df->filetype |= DbeFile::F_FILE;
+      df->inArchive = true;
+      df->experiment = this;
+      archiveMap->put (dname, df);
+      free (fnm);
+    }
+  closedir (exp_dir);
+}
+
+static char *
+gen_file_name (const char *packet_name, const char *src_name)
+{
+  char *fnm, *bname = get_basename (packet_name);
+  if (bname == packet_name)
+    fnm = dbe_strdup (src_name);
+  else
+    fnm = dbe_sprintf ("%.*s%s", (int) (bname - packet_name),
+                      packet_name, src_name);
+
+  // convert "java.lang.Object/Integer.java" => "java/lang/Object/Integer.java"
+  bname = get_basename (fnm);
+  for (char *s = fnm; s < bname; s++)
+    if (*s == '.')
+      *s = '/';
+  return fnm;
+}
+
+static char *
+get_jlass_name (const char *nm)
+{
+  // Convert "Ljava/lang/Object;" => "java/lang/Object.class"
+  if (*nm == 'L')
+    {
+      size_t len = strlen (nm);
+      if (nm[len - 1] == ';')
+       return dbe_sprintf ("%.*s.class", (int) (len - 2), nm + 1);
+    }
+  return dbe_strdup (nm);
+}
+
+static char *
+get_jmodule_name (const char *nm)
+{
+  // convert "Ljava/lang/Object;" => "java.lang.Object"
+  if (*nm == 'L')
+    {
+      size_t len = strlen (nm);
+      if (nm[len - 1] == ';')
+       {
+         char *mname = dbe_sprintf (NTXT ("%.*s"), (int) (len - 2), nm + 1);
+         for (char *s = mname; *s; s++)
+           if (*s == '/')
+             *s = '.';
+         return mname;
+       }
+    }
+  return dbe_strdup (nm);
+}
+
+LoadObject *
+Experiment::get_j_lo (const char *className, const char *fileName)
+{
+  char *class_name = get_jlass_name (className);
+  Dprintf (DUMP_JCLASS_READER,
+       "Experiment::get_j_lo: className='%s' class_name='%s' fileName='%s'\n",
+          STR (className), STR (class_name), STR (fileName));
+  LoadObject *lo = loadObjMap->get (class_name);
+  if (lo == NULL)
+    {
+      lo = createLoadObject (class_name, fileName);
+      lo->type = LoadObject::SEG_TEXT;
+      lo->mtime = (time_t) 0;
+      lo->size = 0;
+      lo->set_platform (Java, wsize);
+      lo->dbeFile->filetype |= DbeFile::F_FILE | DbeFile::F_JAVACLASS;
+      append (lo);
+      Dprintf (DUMP_JCLASS_READER,
+              "Experiment::get_j_lo: creates '%s' location='%s'\n",
+              STR (lo->get_name ()), STR (lo->dbeFile->get_location (false)));
+    }
+  free (class_name);
+  return lo;
+}
+
+Module *
+Experiment::get_jclass (const char *className, const char *fileName)
+{
+  LoadObject *lo = get_j_lo (className, NULL);
+  char *mod_name = get_jmodule_name (className);
+  Module *mod = lo->find_module (mod_name);
+  if (mod == NULL)
+    {
+      mod = dbeSession->createClassFile (mod_name);
+      mod->loadobject = lo;
+      if (strcmp (fileName, NTXT ("<Unknown>")) != 0)
+       mod->set_file_name (gen_file_name (lo->get_pathname (), fileName));
+      else
+       mod->set_file_name (dbe_strdup (fileName));
+      lo->append_module (mod);
+      mod_name = NULL;
+    }
+  else if (mod->file_name && (strcmp (mod->file_name, "<Unknown>") == 0)
+          && strcmp (fileName, "<Unknown>") != 0)
+    mod->set_file_name (gen_file_name (lo->get_pathname (), fileName));
+  Dprintf (DUMP_JCLASS_READER,
+       "Experiment::get_jclass: class_name='%s' mod_name='%s' fileName='%s'\n",
+          mod->loadobject->get_pathname (), mod->get_name (), mod->file_name);
+  free (mod_name);
+  return mod;
+}
+
+#define ARCH_STRLEN(s) ( ( strlen(s) + 4 ) & ~0x3 )
+
+int
+Experiment::read_java_classes_file ()
+{
+  char *data_file_name = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_JCLASSES_FILE);
+  Data_window *dwin = new Data_window (data_file_name);
+  free (data_file_name);
+  if (dwin->not_opened ())
+    {
+      delete dwin;
+      return INCOMPLETE;
+    }
+  dwin->need_swap_endian = need_swap_endian;
+  jmaps = new PRBTree ();
+  jmidHTable = new DbeCacheMap<unsigned long long, JMethod>;
+
+  hrtime_t cur_loaded = 0;
+  Module *cur_mod = NULL;
+  for (int64_t offset = 0;;)
+    {
+      CM_Packet *cpkt = (CM_Packet*) dwin->bind (offset, sizeof (CM_Packet));
+      if (cpkt == NULL)
+       break;
+      uint16_t v16 = (uint16_t) cpkt->tsize;
+      size_t cpktsize = dwin->decode (v16);
+      cpkt = (CM_Packet*) dwin->bind (offset, cpktsize);
+      if ((cpkt == NULL) || (cpktsize == 0))
+       {
+         char *buf = dbe_sprintf (GTXT ("archive file malformed %s"),
+                                  arch_name);
+         errorq->append (new Emsg (CMSG_ERROR, buf));
+         free (buf);
+         break;
+       }
+      v16 = (uint16_t) cpkt->type;
+      v16 = dwin->decode (v16);
+      switch (v16)
+       {
+       case ARCH_JCLASS:
+         {
+           ARCH_jclass *ajcl = (ARCH_jclass*) cpkt;
+           uint64_t class_id = dwin->decode (ajcl->class_id);
+           char *className = ((char*) ajcl) + sizeof (*ajcl);
+           char *fileName = className + ARCH_STRLEN (className);
+           Dprintf (DUMP_JCLASS_READER,
+                    "read_java_classes_file: ARCH_JCLASS(Ox%x)"
+                    "class_id=Ox%llx className='%s' fileName='%s' \n",
+                    (int) v16, (long long) class_id, className, fileName);
+           cur_mod = NULL;
+           if (*className == 'L')
+             { // Old libcollector generated '[' (one array dimension).
+               cur_mod = get_jclass (className, fileName);
+               cur_loaded = dwin->decode (ajcl->tstamp);
+               jmaps->insert (class_id, cur_loaded, cur_mod);
+             }
+           break;
+         }
+       case ARCH_JCLASS_LOCATION:
+         {
+           ARCH_jclass_location *ajcl = (ARCH_jclass_location *) cpkt;
+           uint64_t class_id = dwin->decode (ajcl->class_id);
+           char *className = ((char*) ajcl) + sizeof (*ajcl);
+           char *fileName = className + ARCH_STRLEN (className);
+           Dprintf (DUMP_JCLASS_READER,
+                    "read_java_classes_file: ARCH_JCLASS_LOCATION(Ox%x)"
+                    "class_id=Ox%llx className='%s' fileName='%s' \n",
+                    (int) v16, (long long) class_id, className, fileName);
+           get_j_lo (className, fileName);
+           break;
+         }
+       case ARCH_JMETHOD:
+         {
+           if (cur_mod == NULL)
+             break;
+           ARCH_jmethod *ajmt = (ARCH_jmethod*) cpkt;
+           uint64_t method_id = dwin->decode (ajmt->method_id);
+           char *s_name = ((char*) ajmt) + sizeof (*ajmt);
+           char *s_signature = s_name + ARCH_STRLEN (s_name);
+           char *fullname = dbe_sprintf ("%s.%s", cur_mod->get_name (), s_name);
+           Dprintf (DUMP_JCLASS_READER,
+                    "read_java_classes_file: ARCH_JMETHOD(Ox%x) "
+                    "method_id=Ox%llx name='%s' signature='%s' fullname='%s'\n",
+                    (int) v16, (long long) method_id, s_name,
+                    s_signature, fullname);
+           JMethod *jmthd = cur_mod->find_jmethod (fullname, s_signature);
+           if (jmthd == NULL)
+             {
+               jmthd = dbeSession->createJMethod ();
+               jmthd->size = (unsigned) - 1; // unknown until later (maybe)
+               jmthd->module = cur_mod;
+               jmthd->set_signature (s_signature);
+               jmthd->set_name (fullname);
+               cur_mod->functions->append (jmthd);
+               cur_mod->loadobject->functions->append (jmthd);
+               Dprintf (DUMP_JCLASS_READER,
+                   "read_java_classes_file: ARCH_JMETHOD CREATE fullname=%s\n",
+                        fullname);
+             }
+           jmaps->insert (method_id, cur_loaded, jmthd);
+           free (fullname);
+           break;
+         }
+       default:
+         Dprintf (DUMP_JCLASS_READER,
+                  "read_java_classes_file: type=Ox%x (%d) cpktsize=%d\n",
+                  (int) v16, (int) v16, (int) cpktsize);
+         break; // ignore unknown packets
+       }
+      offset += cpktsize;
+    }
+  delete dwin;
+  return SUCCESS;
+}
+
+void
+Experiment::read_map_file ()
+{
+  ExperimentFile *mapFile = new ExperimentFile (this, SP_MAP_FILE);
+  if (!mapFile->open ())
+    {
+      delete mapFile;
+      return;
+    }
+
+  SAXParserFactory *factory = SAXParserFactory::newInstance ();
+  SAXParser *saxParser = factory->newSAXParser ();
+  DefaultHandler *dh = new ExperimentHandler (this);
+  try
+    {
+      saxParser->parse ((File*) mapFile->fh, dh);
+    }
+  catch (SAXException *e)
+    {
+      // Fatal error in the parser
+      StringBuilder sb;
+      sb.sprintf (NTXT ("%s: %s"), SP_MAP_FILE, e->getMessage ());
+      char *str = sb.toString ();
+      Emsg *m = new Emsg (CMSG_FATAL, str);
+      errorq->append (m);
+      status = FAILURE;
+      free (str);
+      delete e;
+    }
+  delete mapFile;
+  delete dh;
+  delete saxParser;
+  delete factory;
+
+  for (int i = 0, sz = mrecs ? mrecs->size () : 0; i < sz; i++)
+    {
+      MapRecord *mrec = mrecs->fetch (i);
+      SegMem *smem, *sm_lo, *sm_hi;
+      switch (mrec->kind)
+       {
+       case MapRecord::LOAD:
+         smem = new SegMem;
+         smem->base = mrec->base;
+         smem->size = mrec->size;
+         smem->load_time = mrec->ts;
+         smem->unload_time = MAX_TIME;
+         smem->obj = mrec->obj;
+         smem->set_file_offset (mrec->foff);
+         seg_items->append (smem); // add to the master list
+
+         // Check if the new segment overlaps other active segments
+         sm_lo = (SegMem*) maps->locate (smem->base, smem->load_time);
+         if (sm_lo && sm_lo->base + sm_lo->size > smem->base)
+           {
+             // check to see if it is a duplicate record: same address and size, and
+             if ((smem->base == sm_lo->base) && (smem->size == sm_lo->size))
+               {
+                 // addresses and sizes match, check name
+                 if (strstr (smem->obj->get_name (), sm_lo->obj->get_name ()) != NULL
+                     || strstr (sm_lo->obj->get_name (), smem->obj->get_name ()) != NULL)
+                   // this is a duplicate; just move on the the next map record
+                   continue;
+                 fprintf (stderr,
+                          GTXT ("*** Warning: Segment `%s' loaded with same address, size as `%s' [0x%llx-0x%llx]\n"),
+                          smem->obj->get_name (), sm_lo->obj->get_name (),
+                          sm_lo->base, sm_lo->base + sm_lo->size);
+               }
+
+             // Not a duplicate; implicitly unload the old one
+             //     Note: implicit unloading causes high <Unknown>
+             //           when such overlapping is bogus
+             StringBuilder sb;
+             sb.sprintf (GTXT ("*** Warning: Segment %s [0x%llx-0x%llx] overlaps %s [0x%llx-0x%llx], which has been implicitly unloaded"),
+                         smem->obj->get_name (), smem->base, smem->base + smem->size,
+                         sm_lo->obj->get_name (), sm_lo->base, sm_lo->base + sm_lo->size);
+             warnq->append (new Emsg (CMSG_WARN, sb));
+           }
+
+         // now look for other segments with which this might overlap
+         sm_hi = (SegMem*) maps->locate_up (smem->base, smem->load_time);
+         while (sm_hi && sm_hi->base < smem->base + smem->size)
+           {
+
+             // Note: implicit unloading causes high <Unknown> when such overlapping is bogus
+             // maps->remove( sm_hi->base, smem->load_time );
+             StringBuilder sb;
+             sb.sprintf (GTXT ("*** Warning: Segment %s [0x%llx-0x%llx] overlaps %s [0x%llx-0x%llx], which has been implicitly unloaded"),
+                         smem->obj->get_name (), smem->base,
+                         smem->base + smem->size, sm_hi->obj->get_name (),
+                         sm_hi->base, sm_hi->base + sm_hi->size);
+             warnq->append (new Emsg (CMSG_WARN, sb));
+             sm_hi = (SegMem*) maps->locate_up (sm_hi->base + sm_hi->size,
+                                                smem->load_time);
+           }
+
+         maps->insert (smem->base, smem->load_time, smem);
+         break;
+       case MapRecord::UNLOAD:
+         smem = (SegMem*) maps->locate (mrec->base, mrec->ts);
+         if (smem && smem->base == mrec->base)
+           {
+             smem->unload_time = mrec->ts;
+             maps->remove (mrec->base, mrec->ts);
+           }
+         break;
+       }
+    }
+  mrecs->destroy ();
+
+  // See if there are comments or warnings for a load object;
+  // if so, queue them to Experiment
+  for (long i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
+    {
+      LoadObject *lo = loadObjs->get (i);
+      for (Emsg *m = lo->fetch_warnings (); m; m = m->next)
+       warnq->append (m->get_warn (), m->get_msg ());
+      for (Emsg *m = lo->fetch_comments (); m; m = m->next)
+       commentq->append (m->get_warn (), m->get_msg ());
+    }
+}
+
+void
+Experiment::read_frameinfo_file ()
+{
+  init_cache ();
+  char *base_name = get_basename (expt_name);
+  char *msg = dbe_sprintf (GTXT ("Loading CallStack Data: %s"), base_name);
+  read_data_file ("data." SP_FRINFO_FILE, msg);
+  free (msg);
+  frmpckts->sort (frUidCmp);
+  uidnodes->sort (uidNodeCmp);
+}
+
+void
+Experiment::read_omp_preg ()
+{
+  // Parallel region descriptions
+  DataDescriptor *pregDdscr = getDataDescriptor (DATA_OMP4);
+  if (pregDdscr == NULL)
+    return;
+  DataView *pregData = pregDdscr->createView ();
+  pregData->sort (PROP_CPRID); // omptrace PROP_CPRID
+
+  // OpenMP enter parreg events
+  DataDescriptor *dDscr = getDataDescriptor (DATA_OMP2);
+  if (dDscr == NULL || dDscr->getSize () == 0)
+    {
+      delete pregData;
+      return;
+    }
+
+  char *idxname = NTXT ("OMP_preg");
+  delete dbeSession->indxobj_define (idxname, GTXT ("OpenMP Parallel Region"),
+                                    NTXT ("CPRID"), NULL, NULL);
+  int idxtype = dbeSession->findIndexSpaceByName (idxname);
+  if (idxtype < 0)
+    {
+      delete pregData;
+      return;
+    }
+  ompavail = true;
+
+  // Pre-create parallel region with id == 0
+  Histable *preg0 = dbeSession->createIndexObject (idxtype, (int64_t) 0);
+  preg0->set_name (dbe_strdup (GTXT ("Implicit OpenMP Parallel Region")));
+
+  // Take care of the progress bar
+  char *msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
+  get_basename (expt_name));
+  theApplication->set_progress (0, msg);
+  free (msg);
+  long deltaReport = 1000;
+  long nextReport = 0;
+  long errors_found = 0;
+  Vector<Histable*> pregs;
+
+  long size = dDscr->getSize ();
+  for (long i = 0; i < size; ++i)
+    {
+      if (i == nextReport)
+       {
+         int percent = (int) (i * 100 / size);
+         if (percent > 0)
+           theApplication->set_progress (percent, NULL);
+         nextReport += deltaReport;
+       }
+
+      uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
+      hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
+      uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); // omptrace CPRID
+      mapPRid->put (thrid, tstamp, cprid);
+
+      pregs.reset ();
+      /*
+       * We will use 2 pointers to make sure there is no loop.
+       * First pointer "curpreg" goes to the next element,
+       * second pointer "curpreg_loop_control" goes to the next->next element.
+       * If these pointers have the same value - there is a loop.
+       */
+      uint64_t curpreg_loop_control = cprid;
+      Datum tval_loop_control;
+      if (curpreg_loop_control != 0)
+       {
+         tval_loop_control.setUINT64 (curpreg_loop_control);
+         long idx = pregData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
+         if (idx < 0)
+           curpreg_loop_control = 0;
+         else
+           curpreg_loop_control = pregData->getLongValue (PROP_PPRID, idx);
+       }
+      for (uint64_t curpreg = cprid; curpreg != 0;)
+       {
+         Histable *val = NULL;
+         Datum tval;
+         tval.setUINT64 (curpreg);
+         long idx = pregData->getIdxByVals (&tval, DataView::REL_EQ);
+         if (idx < 0)
+           break;
+         /*
+          * Check if there is a loop
+          */
+         if (0 != curpreg_loop_control)
+           {
+             if (curpreg == curpreg_loop_control)
+               {
+                 errors_found++;
+                 if (1 == errors_found)
+                   {
+                     Emsg *m = new Emsg (CMSG_WARN, GTXT ("*** Warning: circular links in OMP regions; data may not be correct."));
+                     warnq->append (m);
+                   }
+                 break;
+               }
+           }
+         uint64_t pragmapc = pregData->getLongValue (PROP_PRPC, idx);
+         DbeInstr *instr = map_Vaddr_to_PC (pragmapc, tstamp);
+         if (instr == NULL)
+           {
+             break;
+           }
+         val = instr;
+         DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE);
+         if (dbeline->lineno > 0)
+           {
+             if (instr->func->usrfunc)
+               dbeline = dbeline->sourceFile->find_dbeline
+                       (instr->func->usrfunc, dbeline->lineno);
+             dbeline->set_flag (DbeLine::OMPPRAGMA);
+             val = dbeline;
+           }
+         val = dbeSession->createIndexObject (idxtype, val);
+         pregs.append (val);
+
+         curpreg = pregData->getLongValue (PROP_PPRID, idx);
+         /*
+          * Update curpreg_loop_control
+          */
+         if (0 != curpreg_loop_control)
+           {
+             tval_loop_control.setUINT64 (curpreg_loop_control);
+             idx = pregData->getIdxByVals
+                     (&tval_loop_control, DataView::REL_EQ);
+             if (idx < 0)
+               curpreg_loop_control = 0;
+             else
+               {
+                 curpreg_loop_control = pregData->getLongValue
+                         (PROP_PPRID, idx);
+                 tval_loop_control.setUINT64 (curpreg_loop_control);
+                 idx = pregData->getIdxByVals
+                         (&tval_loop_control, DataView::REL_EQ);
+                 if (idx < 0)
+                   curpreg_loop_control = 0;
+                 else
+                   curpreg_loop_control = pregData->getLongValue
+                           (PROP_PPRID, idx);
+               }
+           }
+       }
+      pregs.append (preg0);
+      void *prstack = cstack->add_stack (&pregs);
+      mapPReg->put (thrid, tstamp, prstack);
+    }
+  theApplication->set_progress (0, NTXT (""));
+  delete pregData;
+}
+
+void
+Experiment::read_omp_task ()
+{
+  // Task description
+  DataDescriptor *taskDataDdscr = getDataDescriptor (DATA_OMP5);
+  if (taskDataDdscr == NULL)
+    return;
+
+  //7035272: previously, DataView was global; now it's local...is this OK?
+  DataView *taskData = taskDataDdscr->createView ();
+  taskData->sort (PROP_TSKID); // omptrace PROP_TSKID
+
+  // OpenMP enter task events
+  DataDescriptor *dDscr = getDataDescriptor (DATA_OMP3);
+  if (dDscr == NULL || dDscr->getSize () == 0)
+    {
+      delete taskData;
+      return;
+    }
+
+  char *idxname = NTXT ("OMP_task");
+  // delete a possible error message. Ugly.
+  delete dbeSession->indxobj_define (idxname, GTXT ("OpenMP Task"), NTXT ("TSKID"), NULL, NULL);
+  int idxtype = dbeSession->findIndexSpaceByName (idxname);
+  if (idxtype < 0)
+    {
+      delete taskData;
+      return;
+    }
+  ompavail = true;
+
+  // Pre-create task with id == 0
+  Histable *task0 = dbeSession->createIndexObject (idxtype, (int64_t) 0);
+  task0->set_name (dbe_strdup (GTXT ("OpenMP Task from Implicit Parallel Region")));
+
+  // Take care of the progress bar
+  char *msg = dbe_sprintf (GTXT ("Processing OpenMP Task Data: %s"), get_basename (expt_name));
+  theApplication->set_progress (0, msg);
+  free (msg);
+  long deltaReport = 1000;
+  long nextReport = 0;
+
+  Vector<Histable*> tasks;
+  long size = dDscr->getSize ();
+  long errors_found = 0;
+  for (long i = 0; i < size; ++i)
+    {
+      if (i == nextReport)
+       {
+         int percent = (int) (i * 100 / size);
+         if (percent > 0)
+           theApplication->set_progress (percent, NULL);
+         nextReport += deltaReport;
+       }
+
+      uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
+      hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
+      uint64_t tskid = dDscr->getLongValue (PROP_TSKID, i); //omptrace TSKID
+      tasks.reset ();
+      /*
+       * We will use 2 pointers to make sure there is no loop.
+       * First pointer "curtsk" goes to the next element,
+       * second pointer "curtsk_loop_control" goes to the next->next element.
+       * If these pointers have the same value - there is a loop.
+       */
+      uint64_t curtsk_loop_control = tskid;
+      Datum tval_loop_control;
+      if (curtsk_loop_control != 0)
+       {
+         tval_loop_control.setUINT64 (curtsk_loop_control);
+         long idx = taskData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
+         if (idx < 0)
+           curtsk_loop_control = 0;
+         else
+           curtsk_loop_control = taskData->getLongValue (PROP_PTSKID, idx);
+       }
+      for (uint64_t curtsk = tskid; curtsk != 0;)
+       {
+         Histable *val = NULL;
+
+         Datum tval;
+         tval.setUINT64 (curtsk);
+         long idx = taskData->getIdxByVals (&tval, DataView::REL_EQ);
+         if (idx < 0)
+           break;
+         /*
+          * Check if there is a loop
+          */
+         if (0 != curtsk_loop_control)
+           {
+             if (curtsk == curtsk_loop_control)
+               {
+                 errors_found++;
+                 if (1 == errors_found)
+                   {
+                     Emsg *m = new Emsg (CMSG_WARN, GTXT ("*** Warning: circular links in OMP tasks; data may not be correct."));
+                     warnq->append (m);
+                   }
+                 break;
+               }
+           }
+         uint64_t pragmapc = taskData->getLongValue (PROP_PRPC, idx);
+         DbeInstr *instr = map_Vaddr_to_PC (pragmapc, tstamp);
+         if (instr == NULL)
+           break;
+         val = instr;
+         DbeLine *dbeline = (DbeLine*) instr->convertto (Histable::LINE);
+         if (dbeline->lineno > 0)
+           {
+             if (instr->func->usrfunc)
+               dbeline = dbeline->sourceFile->find_dbeline
+                       (instr->func->usrfunc, dbeline->lineno);
+             dbeline->set_flag (DbeLine::OMPPRAGMA);
+             val = dbeline;
+           }
+         val = dbeSession->createIndexObject (idxtype, val);
+         tasks.append (val);
+
+         curtsk = taskData->getLongValue (PROP_PTSKID, idx);
+         /*
+          * Update curtsk_loop_control
+          */
+         if (0 != curtsk_loop_control)
+           {
+             tval_loop_control.setUINT64 (curtsk_loop_control);
+             idx = taskData->getIdxByVals (&tval_loop_control, DataView::REL_EQ);
+             if (idx < 0)
+               curtsk_loop_control = 0;
+             else
+               {
+                 curtsk_loop_control = taskData->getLongValue (PROP_PTSKID, idx);
+                 tval_loop_control.setUINT64 (curtsk_loop_control);
+                 idx = taskData->getIdxByVals (&tval_loop_control,
+                                               DataView::REL_EQ);
+                 if (idx < 0)
+                   curtsk_loop_control = 0;
+                 else
+                   curtsk_loop_control = taskData->getLongValue (PROP_PTSKID,
+                                                                 idx);
+               }
+           }
+       }
+      tasks.append (task0);
+      void *tskstack = cstack->add_stack (&tasks);
+      mapTask->put (thrid, tstamp, tskstack);
+    }
+  theApplication->set_progress (0, NTXT (""));
+  delete taskData;
+}
+
+void
+Experiment::read_omp_file ()
+{
+  // DATA_OMP2 table is common between OpenMP 2.5 and 3.0 profiling
+  DataDescriptor *dDscr = getDataDescriptor (DATA_OMP2);
+  if (dDscr == NULL)
+    return;
+  if (dDscr->getSize () == 0)
+    {
+      char *base_name = get_basename (expt_name);
+      char *msg = dbe_sprintf (GTXT ("Loading OpenMP Data: %s"), base_name);
+      read_data_file (SP_OMPTRACE_FILE, msg);
+      free (msg);
+
+      // OpenMP fork events
+      dDscr = getDataDescriptor (DATA_OMP);
+      long sz = dDscr->getSize ();
+      if (sz > 0)
+       {
+         // progress bar
+         msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
+                            base_name);
+         theApplication->set_progress (0, msg);
+         free (msg);
+         long deltaReport = 5000;
+         long nextReport = 0;
+         for (int i = 0; i < sz; ++i)
+           {
+             if (i == nextReport)
+               {
+                 int percent = (int) (i * 100 / sz);
+                 if (percent > 0)
+                   theApplication->set_progress (percent, NULL);
+                 nextReport += deltaReport;
+               }
+             uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
+             hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
+             uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); //omptrace
+             mapPRid->put (thrid, tstamp, cprid);
+           }
+         theApplication->set_progress (0, NTXT (""));
+
+         ompavail = true;
+         openMPdata = dDscr->createView ();
+         openMPdata->sort (PROP_CPRID); // omptrace PROP_CPRID
+
+         // thread enters parreg events
+         dDscr = getDataDescriptor (DATA_OMP2);
+         sz = dDscr->getSize ();
+
+         // progress bar
+         msg = dbe_sprintf (GTXT ("Processing OpenMP Parallel Region Data: %s"),
+                            base_name);
+         theApplication->set_progress (0, msg);
+         free (msg);
+         deltaReport = 5000;
+         nextReport = 0;
+
+         for (int i = 0; i < sz; ++i)
+           {
+             if (i == nextReport)
+               {
+                 int percent = (int) (i * 100 / sz);
+                 if (percent > 0)
+                   theApplication->set_progress (percent, NULL);
+                 nextReport += deltaReport;
+               }
+             uint32_t thrid = dDscr->getIntValue (PROP_THRID, i);
+             hrtime_t tstamp = dDscr->getLongValue (PROP_TSTAMP, i);
+             uint64_t cprid = dDscr->getLongValue (PROP_CPRID, i); //omptrace
+             mapPRid->put (thrid, tstamp, cprid);
+           }
+         theApplication->set_progress (0, NTXT (""));
+       }
+      else
+       {
+         read_omp_preg ();
+         read_omp_task ();
+       }
+      if (ompavail && coll_params.profile_mode)
+       {
+         dbeSession->status_ompavail = 1;
+         register_metric (Metric::OMP_WORK);
+         register_metric (Metric::OMP_WAIT);
+         register_metric (Metric::OMP_OVHD);
+         if (coll_params.lms_magic_id == LMS_MAGIC_ID_SOLARIS)
+           register_metric (Metric::OMP_MASTER_THREAD);
+       }
+    }
+}
+
+void
+Experiment::read_ifreq_file ()
+{
+  char *fname = dbe_sprintf (NTXT ("%s/%s"), expt_name, SP_IFREQ_FILE);
+  FILE *f = fopen (fname, NTXT ("r"));
+  free (fname);
+  if (f == NULL)
+    {
+      ifreqavail = false;
+      return;
+    }
+  ifreqavail = true;
+  ifreqq = new Emsgqueue (NTXT ("ifreqq"));
+
+  while (1)
+    {
+      Emsg *m;
+      char str[MAXPATHLEN];
+      char *e = fgets (str, ((int) sizeof (str)) - 1, f);
+      if (e == NULL)
+       {
+         // end the list from the experiment
+         m = new Emsg (CMSG_COMMENT,
+                       GTXT ("============================================================"));
+         ifreqq->append (m);
+         break;
+       }
+      // get the string
+      size_t i = strlen (str);
+      if (i > 0 && str[i - 1] == '\n')
+       // remove trailing nl
+       str[i - 1] = 0;
+      // and append it
+      m = new Emsg (CMSG_COMMENT, str);
+      ifreqq->append (m);
+    }
+  (void) fclose (f);
+}
+
+Experiment *
+Experiment::getBaseFounder ()
+{
+  if (baseFounder)
+    return baseFounder;
+  Experiment *founder = this;
+  Experiment *parent = founder->founder_exp;
+  while (parent)
+    {
+      founder = parent;
+      parent = founder->founder_exp;
+    }
+  baseFounder = founder;
+  return baseFounder;
+}
+
+hrtime_t
+Experiment::getRelativeStartTime ()
+{
+  if (exp_rel_start_time_set)
+    return exp_rel_start_time;
+  Experiment *founder = getBaseFounder ();
+  hrtime_t child_start = this->getStartTime ();
+  hrtime_t founder_start = founder->getStartTime ();
+  exp_rel_start_time = child_start - founder_start;
+  if (child_start == 0 && founder_start)
+    exp_rel_start_time = 0;     // when descendents have incomplete log.xml
+  exp_rel_start_time_set = true;
+  return exp_rel_start_time;
+}
+
+DataDescriptor *
+Experiment::get_raw_events (int data_id)
+{
+  DataDescriptor *dDscr;
+  switch (data_id)
+    {
+    case DATA_CLOCK:
+      dDscr = get_profile_events ();
+      break;
+    case DATA_SYNCH:
+      dDscr = get_sync_events ();
+      break;
+    case DATA_HWC:
+      dDscr = get_hwc_events ();
+      break;
+    case DATA_HEAP:
+      dDscr = get_heap_events ();
+      break;
+    case DATA_HEAPSZ:
+      dDscr = get_heapsz_events ();
+      break;
+    case DATA_IOTRACE:
+      dDscr = get_iotrace_events ();
+      break;
+    case DATA_RACE:
+      dDscr = get_race_events ();
+      break;
+    case DATA_DLCK:
+      dDscr = get_deadlock_events ();
+      break;
+    case DATA_SAMPLE:
+      dDscr = get_sample_events ();
+      break;
+    case DATA_GCEVENT:
+      dDscr = get_gc_events ();
+      break;
+    default:
+      dDscr = NULL;
+      break;
+    }
+  return dDscr;
+}
+
+int
+Experiment::base_data_id (int data_id)
+{
+  switch (data_id)
+    {
+    case DATA_HEAPSZ:
+      return DATA_HEAP; // DATA_HEAPSZ DataView is based on DATA_HEAP's DataView
+    default:
+      break;
+    }
+  return data_id;
+}
+
+DataView *
+Experiment::create_derived_data_view (int data_id, DataView *dview)
+{
+  // dview contains filtered packets
+  switch (data_id)
+    {
+    case DATA_HEAPSZ:
+      return create_heapsz_data_view (dview);
+    default:
+      break;
+    }
+  return NULL;
+}
+
+DataDescriptor *
+Experiment::get_profile_events ()
+{
+  DataDescriptor *dDscr = getDataDescriptor (DATA_CLOCK);
+  if (dDscr == NULL)
+    return NULL;
+  if (dDscr->getSize () == 0)
+    {
+      char *base_name = get_basename (expt_name);
+      char *msg = dbe_sprintf (GTXT ("Loading Profile Data: %s"), base_name);
+      read_data_file (SP_PROFILE_FILE, msg);
+      free (msg);
+      add_evt_time_to_profile_events (dDscr);
+      resolve_frame_info (dDscr);
+    }
+  else if (!dDscr->isResolveFrInfoDone ())
+    resolve_frame_info (dDscr);
+  return dDscr;
+}
+
+void
+Experiment::add_evt_time_to_profile_events (DataDescriptor *dDscr)
+{
+  if (coll_params.lms_magic_id != LMS_MAGIC_ID_SOLARIS)
+    return;
+
+  DataView *dview = dDscr->createView ();
+  dview->sort (PROP_THRID, PROP_TSTAMP);
+
+  // add PROP_EVT_TIME
+  PropDescr* tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
+  tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
+  tmp_propDscr->vtype = TYPE_INT64;
+  dDscr->addProperty (tmp_propDscr);
+
+  long sz = dview->getSize ();
+  long long ptimer_usec = get_params ()->ptimer_usec;
+  for (long i = 0; i < sz; i++)
+    {
+      int next_sample;
+      int jj;
+      {
+       hrtime_t this_tstamp = dview->getLongValue (PROP_TSTAMP, i);
+       long this_thrid = dview->getLongValue (PROP_THRID, i);
+       for (jj = i + 1; jj < sz; jj++)
+         {
+           hrtime_t tmp_tstamp = dview->getLongValue (PROP_TSTAMP, jj);
+           if (tmp_tstamp != this_tstamp)
+             break;
+           long tmp_thrid = dview->getLongValue (PROP_THRID, jj);
+           if (tmp_thrid != this_thrid)
+             break;
+         }
+       next_sample = jj;
+      }
+
+      long nticks = 0;
+      for (jj = i; jj < next_sample; jj++)
+       nticks += dview->getLongValue (PROP_NTICK, jj);
+      if (nticks <= 1)
+       continue; // no duration
+
+      nticks--;
+      hrtime_t duration = ptimer_usec * 1000LL * nticks; // nanoseconds
+      for (jj = i; jj < next_sample; jj++)
+       dview->setValue (PROP_EVT_TIME, jj, duration);
+      i = jj - 1;
+    }
+  delete dview;
+}
+
+DataDescriptor *
+Experiment::get_sync_events ()
+{
+  DataDescriptor *dDscr = getDataDescriptor (DATA_SYNCH);
+  if (dDscr == NULL)
+    return NULL;
+  if (dDscr->getSize () > 0)
+    return dDscr;
+
+  // fetch data
+  {
+    char *base_name = get_basename (expt_name);
+    char *msg = dbe_sprintf (GTXT ("Loading Synctrace Data: %s"), base_name);
+    read_data_file (SP_SYNCTRACE_FILE, msg);
+    free (msg);
+    resolve_frame_info (dDscr);
+  }
+
+  // check for PROP_EVT_TIME
+  PropDescr *tmp_propDscr = dDscr->getProp (PROP_EVT_TIME);
+  if (tmp_propDscr)
+    return dDscr;
+
+  // add PROP_EVT_TIME
+  tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
+  tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
+  tmp_propDscr->vtype = TYPE_INT64;
+  dDscr->addProperty (tmp_propDscr);
+
+  long sz = dDscr->getSize ();
+  for (long i = 0; i < sz; i++)
+    {
+      uint64_t event_duration = dDscr->getLongValue (PROP_TSTAMP, i);
+      event_duration -= dDscr->getLongValue (PROP_SRQST, i);
+      dDscr->setValue (PROP_EVT_TIME, i, event_duration);
+    }
+  return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_hwc_events ()
+{
+  DataDescriptor *dDscr = getDataDescriptor (DATA_HWC);
+  if (dDscr == NULL)
+    return NULL;
+  if (dDscr->getSize () == 0)
+    {
+      char *base_name = get_basename (expt_name);
+      char *msg = dbe_sprintf (GTXT ("Loading HW Profile Data: %s"), base_name);
+
+      // clear HWC event stats
+      dsevents = 0;
+      dsnoxhwcevents = 0;
+      read_data_file (SP_HWCNTR_FILE, msg);
+      free (msg);
+      resolve_frame_info (dDscr);
+
+      // describe the HW counters in PropDescr
+      PropDescr *prop = dDscr->getProp (PROP_HWCTAG);
+      if (prop)
+       {
+         Collection_params *cparam = get_params ();
+         if (cparam->hw_mode != 0)
+           for (int aux = 0; aux < MAX_HWCOUNT; aux++)
+             if (cparam->hw_aux_name[aux])
+               {
+                 const char* cmdname = cparam->hw_aux_name[aux];
+                 const char* uname = cparam->hw_username[aux];
+                 prop->addState (aux, cmdname, uname);
+               }
+       }
+      else
+       assert (0);
+
+      double dserrrate = 100.0 * ((double) dsnoxhwcevents) / ((double) dsevents);
+      if ((dsevents > 0) && (dserrrate > 10.0))
+       {
+         // warn the user that rate is high
+         StringBuilder sb;
+         if (dbeSession->check_ignore_no_xhwcprof ())
+           sb.sprintf (
+                       GTXT ("Warning: experiment %s has %.1f%%%% (%lld of %lld) dataspace events that were accepted\n  without verification; data may be incorrect or misleading\n  recompile with -xhwcprof and rerecord to get better data\n"),
+                       base_name, dserrrate, (long long) dsnoxhwcevents,
+                       (long long) dsevents);
+         else
+           sb.sprintf (
+                       GTXT ("Warning: experiment %s has %.1f%%%% (%lld of %lld) dataspace events that could not be verified\n  recompile with -xhwcprof and rerecord to get better data\n"),
+                       base_name, dserrrate, (long long) dsnoxhwcevents,
+                       (long long) dsevents);
+         errorq->append (new Emsg (CMSG_WARN, sb));
+       }
+
+      // see if we've scanned the data
+      if (hwc_scanned == 0)
+       {
+         // no, scan the packets to see how many are bogus, or represent lost interrupts
+         long hwc_cnt = 0;
+
+         // loop over the packets, counting the bad ones
+         if (hwc_bogus != 0 || hwc_lost_int != 0)
+           {
+             // hwc counter data had bogus packets and/or packets reflecting lost interrupts
+             double bogus_rate = 100. * (double) hwc_bogus / (double) hwc_cnt;
+             if (bogus_rate > 5.)
+               {
+                 StringBuilder sb;
+                 sb.sprintf (
+                             GTXT ("WARNING: Too many invalid HW counter profile events (%ld/%ld = %3.2f%%) in experiment %d (`%s'); data may be unreliable"),
+                             (long) hwc_bogus, (long) hwc_cnt, bogus_rate,
+                             (int) userExpId, base_name);
+                 Emsg *m = new Emsg (CMSG_WARN, sb);
+                 warnq->append (m);
+               }
+             hwc_scanned = 1;
+           }
+       }
+    }
+  return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_iotrace_events ()
+{
+  DataDescriptor *dDscr = getDataDescriptor (DATA_IOTRACE);
+  if (dDscr == NULL)
+    return NULL;
+
+  if (dDscr->getSize () > 0)
+    return dDscr;
+
+  char *base_name = get_basename (expt_name);
+  char *msg = dbe_sprintf (GTXT ("Loading IO Trace Data: %s"), base_name);
+  read_data_file (SP_IOTRACE_FILE, msg);
+  free (msg);
+
+  if (dDscr->getSize () == 0)
+    return dDscr;
+  resolve_frame_info (dDscr);
+
+  // check for PROP_EVT_TIME
+  PropDescr *tmp_propDscr = dDscr->getProp (PROP_EVT_TIME);
+  if (tmp_propDscr)
+    return dDscr;
+
+  // add PROP_EVT_TIME
+  tmp_propDscr = new PropDescr (PROP_EVT_TIME, "EVT_TIME");
+  tmp_propDscr->uname = dbe_strdup (GTXT ("Event duration"));
+  tmp_propDscr->vtype = TYPE_INT64;
+  dDscr->addProperty (tmp_propDscr);
+
+  // add PROP_IOVFD
+  tmp_propDscr = new PropDescr (PROP_IOVFD, "IOVFD");
+  tmp_propDscr->uname = dbe_strdup (GTXT ("Virtual File Descriptor"));
+  tmp_propDscr->vtype = TYPE_INT64;
+  dDscr->addProperty (tmp_propDscr);
+
+  delete fDataMap;
+  fDataMap = new DefaultMap<int64_t, FileData*>;
+
+  delete vFdMap;
+  vFdMap = new DefaultMap<int, int64_t>;
+
+  static int64_t virtualFd = 0;
+
+  FileData *fData;
+  virtualFd += 10;
+  fData = fDataMap->get (VIRTUAL_FD_STDIN);
+  if (fData == NULL)
+    {
+      fData = new FileData (STDIN_FILENAME);
+      fData->setVirtualFd (VIRTUAL_FD_STDIN);
+      fData->id = VIRTUAL_FD_STDIN;
+      fData->setFileDes (STDIN_FD);
+      fDataMap->put (VIRTUAL_FD_STDIN, fData);
+      vFdMap->put (STDIN_FD, VIRTUAL_FD_STDIN);
+    }
+
+  fData = fDataMap->get (VIRTUAL_FD_STDOUT);
+  if (fData == NULL)
+    {
+      fData = new FileData (STDOUT_FILENAME);
+      fData->setVirtualFd (VIRTUAL_FD_STDOUT);
+      fData->id = VIRTUAL_FD_STDOUT;
+      fData->setFileDes (STDOUT_FD);
+      fDataMap->put (VIRTUAL_FD_STDOUT, fData);
+      vFdMap->put (STDOUT_FD, VIRTUAL_FD_STDOUT);
+    }
+
+  fData = fDataMap->get (VIRTUAL_FD_STDERR);
+  if (fData == NULL)
+    {
+      fData = new FileData (STDERR_FILENAME);
+      fData->setVirtualFd (VIRTUAL_FD_STDERR);
+      fData->id = VIRTUAL_FD_STDERR;
+      fData->setFileDes (STDERR_FD);
+      fDataMap->put (VIRTUAL_FD_STDERR, fData);
+      vFdMap->put (STDERR_FD, VIRTUAL_FD_STDERR);
+    }
+
+  fData = fDataMap->get (VIRTUAL_FD_OTHERIO);
+  if (fData == NULL)
+    {
+      fData = new FileData (OTHERIO_FILENAME);
+      fData->setVirtualFd (VIRTUAL_FD_OTHERIO);
+      fData->id = VIRTUAL_FD_OTHERIO;
+      fData->setFileDes (OTHERIO_FD);
+      fDataMap->put (VIRTUAL_FD_OTHERIO, fData);
+    }
+
+  DataView *dview = dDscr->createView ();
+  dview->sort (PROP_TSTAMP);
+  long sz = dview->getSize ();
+  for (long i = 0; i < sz; i++)
+    {
+      hrtime_t event_duration = dview->getLongValue (PROP_TSTAMP, i);
+      hrtime_t event_start = dview->getLongValue (PROP_IORQST, i);
+      if (event_start > 0)
+       event_duration -= event_start;
+      else
+       event_duration = 0;
+      dview->setValue (PROP_EVT_TIME, i, event_duration);
+
+      int32_t fd = -1;
+      int64_t vFd = VIRTUAL_FD_NONE;
+      char *fName = NULL;
+      int32_t origFd = -1;
+      StringBuilder *sb = NULL;
+      FileData *fDataOrig = NULL;
+      FileSystem_type fsType;
+
+      IOTrace_type ioType = (IOTrace_type) dview->getIntValue (PROP_IOTYPE, i);
+      switch (ioType)
+       {
+       case READ_TRACE:
+       case WRITE_TRACE:
+       case READ_TRACE_ERROR:
+       case WRITE_TRACE_ERROR:
+         fd = dview->getIntValue (PROP_IOFD, i);
+         vFd = vFdMap->get (fd);
+         if (vFd == 0 || vFd == VIRTUAL_FD_NONE
+             || (fData = fDataMap->get (vFd)) == NULL)
+           {
+             fData = new FileData (UNKNOWNFD_FILENAME);
+             fData->setVirtualFd (virtualFd);
+             fData->setFsType ("N/A");
+             fData->setFileDes (fd);
+             fDataMap->put (virtualFd, fData);
+             vFdMap->put (fd, virtualFd);
+             vFd = virtualFd;
+             virtualFd++;
+           }
+         dview->setValue (PROP_IOVFD, i, vFd);
+         break;
+       case OPEN_TRACE:
+         fName = NULL;
+         sb = (StringBuilder*) dview->getObjValue (PROP_IOFNAME, i);
+         if (sb != NULL && sb->length () > 0)
+           fName = sb->toString ();
+         fd = dview->getIntValue (PROP_IOFD, i);
+         origFd = dview->getIntValue (PROP_IOOFD, i);
+         fsType = (FileSystem_type) dview->getIntValue (PROP_IOFSTYPE, i);
+
+         if (fName != NULL)
+           {
+             fData = new FileData (fName);
+             fDataMap->put (virtualFd, fData);
+             vFdMap->put (fd, virtualFd);
+             fData->setFileDes (fd);
+             fData->setFsType (fsType);
+             fData->setVirtualFd (virtualFd);
+             vFd = virtualFd;
+             virtualFd++;
+           }
+         else if (origFd > 0)
+           {
+             vFd = vFdMap->get (origFd);
+             if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
+               {
+                 Dprintf (DEBUG_IO,
+                          "*** Error I/O tracing: (open) cannot get the virtual file descriptor, fd=%d  origFd=%d\n",
+                          fd, origFd);
+                 continue;
+               }
+             else if ((fDataOrig = fDataMap->get (vFd)) == NULL)
+               {
+                 Dprintf (DEBUG_IO,
+                          "*** Error IO tracing: (open) cannot get original FileData object, fd=%d  origFd=%d\n",
+                          fd, origFd);
+                 continue;
+               }
+             else
+               {
+                 fName = fDataOrig->getFileName ();
+                 fData = new FileData (fName);
+                 fData->setFileDes (fd);
+                 fData->setFsType (fDataOrig->getFsType ());
+                 fData->setVirtualFd (virtualFd);
+                 fDataMap->put (virtualFd, fData);
+                 vFdMap->put (fd, virtualFd);
+                 vFd = virtualFd;
+                 virtualFd++;
+               }
+           }
+         else if (fd >= 0)
+           {
+             vFd = vFdMap->get (fd);
+             if (vFd == 0 || vFd == VIRTUAL_FD_NONE
+                 || (fData = fDataMap->get (vFd)) == NULL)
+               {
+                 fData = new FileData (UNKNOWNFD_FILENAME);
+                 fData->setVirtualFd (virtualFd);
+                 fData->setFsType ("N/A");
+                 fData->setFileDes (fd);
+                 fDataMap->put (virtualFd, fData);
+                 vFdMap->put (fd, virtualFd);
+                 vFd = virtualFd;
+                 virtualFd++;
+               }
+           }
+         else
+           {
+             Dprintf (DEBUG_IO,
+                      NTXT ("*** Error IO tracing: (open) unknown open IO type, fd=%d  origFd=%d\n"), fd, origFd);
+             continue;
+           }
+
+         dview->setValue (PROP_IOVFD, i, vFd);
+         break;
+
+       case OPEN_TRACE_ERROR:
+         fName = NULL;
+
+         sb = (StringBuilder*) dview->getObjValue (PROP_IOFNAME, i);
+         if (sb != NULL && sb->length () > 0)
+           fName = sb->toString ();
+         fd = dview->getIntValue (PROP_IOFD, i);
+         origFd = dview->getIntValue (PROP_IOOFD, i);
+         fsType = (FileSystem_type) dview->getIntValue (PROP_IOFSTYPE, i);
+
+         if (fName != NULL)
+           {
+             fData = new FileData (fName);
+             fDataMap->put (virtualFd, fData);
+             fData->setFileDes (fd);
+             fData->setFsType (fsType);
+             fData->setVirtualFd (virtualFd);
+             vFd = virtualFd;
+             virtualFd++;
+           }
+         else if (origFd > 0)
+           {
+             vFd = vFdMap->get (origFd);
+             if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
+               {
+                 Dprintf (DEBUG_IO,
+                          "*** Error IO tracing: (open error) cannot get the virtual file descriptor, fd=%d  origFd=%d\n",
+                          fd, origFd);
+                 continue;
+               }
+             else if ((fDataOrig = fDataMap->get (vFd)) == NULL)
+               {
+                 Dprintf (DEBUG_IO,
+                          "*** Error IO tracing: (open error) cannot get original FileData object, fd=%d  origFd=%d\n",
+                          fd, origFd);
+                 continue;
+               }
+             else
+               {
+                 fName = fDataOrig->getFileName ();
+                 fData = new FileData (fName);
+                 fData->setFileDes (fd);
+                 fData->setFsType (fDataOrig->getFsType ());
+                 fData->setVirtualFd (virtualFd);
+                 fDataMap->put (virtualFd, fData);
+                 vFd = virtualFd;
+                 virtualFd++;
+               }
+           }
+
+         dview->setValue (PROP_IOVFD, i, vFd);
+         break;
+
+       case CLOSE_TRACE:
+       case CLOSE_TRACE_ERROR:
+         fd = dview->getIntValue (PROP_IOFD, i);
+         vFd = vFdMap->get (fd);
+         if (vFd == 0 || vFd == VIRTUAL_FD_NONE)
+           {
+             Dprintf (DEBUG_IO,
+                      "*** Error IO tracing: (close) cannot get the virtual file descriptor, fd=%d\n",
+                      fd);
+             continue;
+           }
+         fData = fDataMap->get (vFd);
+         if (fData == NULL)
+           {
+             Dprintf (DEBUG_IO,
+                      "*** Error IO tracing: (close) cannot get the FileData object, fd=%d\n",
+                      fd);
+             continue;
+           }
+
+         vFdMap->put (fd, VIRTUAL_FD_NONE);
+         dview->setValue (PROP_IOVFD, i, vFd);
+         break;
+
+       case OTHERIO_TRACE:
+       case OTHERIO_TRACE_ERROR:
+         vFd = VIRTUAL_FD_OTHERIO;
+         fData = fDataMap->get (vFd);
+         if (fData == NULL)
+           {
+             Dprintf (DEBUG_IO,
+                      "*** Error IO tracing: (other IO) cannot get the FileData object\n");
+             continue;
+           }
+
+         dview->setValue (PROP_IOVFD, i, vFd);
+         break;
+       case IOTRACETYPE_LAST:
+         break;
+       }
+    }
+
+  delete dview;
+
+  return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_heap_events ()
+{
+  DataDescriptor *dDscr = getDataDescriptor (DATA_HEAP);
+  if (dDscr == NULL)
+    return NULL;
+  if (dDscr->getSize () > 0)
+    return dDscr;
+
+  char *base_name = get_basename (expt_name);
+  char *msg = dbe_sprintf (GTXT ("Loading Heap Trace Data: %s"), base_name);
+  read_data_file (SP_HEAPTRACE_FILE, msg);
+  free (msg);
+
+  if (dDscr->getSize () == 0)
+    return dDscr;
+  resolve_frame_info (dDscr);
+
+  // Match FREE to MALLOC
+  PropDescr *prop = new PropDescr (PROP_HLEAKED, NTXT ("HLEAKED"));
+  prop->uname = dbe_strdup (GTXT ("Bytes Leaked"));
+  prop->vtype = TYPE_UINT64;
+  dDscr->addProperty (prop);
+
+  prop = new PropDescr (PROP_HMEM_USAGE, NTXT ("HMEM_USAGE"));
+  prop->uname = dbe_strdup (GTXT ("Heap Memory Usage"));
+  prop->vtype = TYPE_UINT64;
+  dDscr->addProperty (prop);
+
+  prop = new PropDescr (PROP_HFREED, NTXT ("HFREED"));
+  prop->uname = dbe_strdup (GTXT ("Bytes Freed"));
+  prop->vtype = TYPE_UINT64;
+  dDscr->addProperty (prop);
+
+  prop = new PropDescr (PROP_HCUR_ALLOCS, NTXT ("HCUR_ALLOCS"));
+  prop->uname = dbe_strdup (GTXT ("Net Bytes Allocated"));
+  prop->vtype = TYPE_INT64;
+  dDscr->addProperty (prop);
+
+  prop = new PropDescr (PROP_HCUR_LEAKS, NTXT ("HCUR_LEAKS"));
+  prop->uname = dbe_strdup (GTXT ("Net Bytes Leaked"));
+  prop->vtype = TYPE_UINT64;
+  dDscr->addProperty (prop);
+
+  prop = new PropDescr (PROP_HCUR_NET_ALLOC, NTXT ("HCUR_NET_ALLOC"));
+  prop->vtype = TYPE_INT64;
+  prop->flags = DDFLAG_NOSHOW;
+  dDscr->addProperty (prop);
+
+  prop = new PropDescr (PROP_DDSCR_LNK, NTXT ("DDSCR_LNK"));
+  prop->vtype = TYPE_UINT64;
+  prop->flags = DDFLAG_NOSHOW;
+  dDscr->addProperty (prop);
+
+  prop = new PropDescr (PROP_VOIDP_OBJ, NTXT ("VOIDP_OBJ"));
+  prop->vtype = TYPE_OBJ;
+  prop->flags = DDFLAG_NOSHOW;
+  dDscr->addProperty (prop);
+
+  prop = new PropDescr (PROP_TSTAMP2, NTXT ("TSTAMP2"));
+  prop->uname = dbe_strdup (GTXT ("End Timestamp (nanoseconds)"));
+  prop->vtype = TYPE_UINT64;
+  prop->flags = DDFLAG_NOSHOW;
+  dDscr->addProperty (prop);
+
+  DataView *dview = dDscr->createView ();
+  dview->sort (PROP_TSTAMP);
+
+  // Keep track of memory usage
+  Size memoryUsage = 0;
+
+  HeapMap *heapmap = new HeapMap ();
+  long sz = dview->getSize ();
+  for (long i = 0; i < sz; i++)
+    {
+
+      Heap_type mtype = (Heap_type) dview->getIntValue (PROP_HTYPE, i);
+      Vaddr vaddr = dview->getULongValue (PROP_HVADDR, i);
+      Vaddr ovaddr = dview->getULongValue (PROP_HOVADDR, i);
+      Size hsize = dview->getULongValue (PROP_HSIZE, i);
+      hrtime_t tstamp = dview->getLongValue (PROP_TSTAMP, i);
+
+      switch (mtype)
+       {
+       case MALLOC_TRACE:
+         dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
+         if (vaddr)
+           {
+             dview->setValue (PROP_HLEAKED, i, hsize);
+             heapmap->allocate (vaddr, i + 1);
+
+             // Increase heap size
+             memoryUsage += hsize;
+             dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
+           }
+         break;
+
+       case FREE_TRACE:
+         if (vaddr)
+           {
+             long idx = heapmap->deallocate (vaddr) - 1;
+             if (idx >= 0)
+               {
+                 // Decrease heap size
+                 Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
+                 memoryUsage -= leaked;
+                 dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
+
+                 Size alloc = dview->getLongValue (PROP_HSIZE, idx);
+                 // update allocation
+                 dview->setValue (PROP_HLEAKED, idx, (uint64_t) 0);
+                 dview->setValue (PROP_TSTAMP2, idx, tstamp);
+                 dview->setValue (PROP_DDSCR_LNK, idx, dview->getIdByIdx (i) + 1);
+                 // update this event
+                 dview->setValue (PROP_HFREED, i, alloc);
+               }
+           }
+         break;
+
+       case REALLOC_TRACE:
+         dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
+         if (ovaddr)
+           {
+             long idx = heapmap->deallocate (ovaddr) - 1;
+             if (idx >= 0)
+               {
+                 // Decrease heap size
+                 Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
+                 memoryUsage -= leaked;
+                 dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
+
+                 Size alloc = dview->getLongValue (PROP_HSIZE, idx);
+                 // update allocation
+                 dview->setValue (PROP_HLEAKED, idx, (uint64_t) 0);
+                 dview->setValue (PROP_TSTAMP2, idx, tstamp);
+                 dview->setValue (PROP_DDSCR_LNK, idx, dview->getIdByIdx (i) + 1);
+                 // update this event
+                 dview->setValue (PROP_HFREED, i, alloc);
+               }
+           }
+         if (vaddr)
+           {
+             dview->setValue (PROP_HLEAKED, i, hsize);
+             heapmap->allocate (vaddr, i + 1);
+
+             // Increase heap size
+             memoryUsage += hsize;
+             dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
+           }
+         break;
+       case MMAP_TRACE:
+       case MUNMAP_TRACE:
+         // Adjust the size to be multiple of page_size
+         //hsize = (( hsize - 1 ) / page_size + 1 ) * page_size;
+         if (vaddr)
+           {
+             UnmapChunk *list;
+             if (mtype == MMAP_TRACE)
+               {
+                 dview->setValue (PROP_TSTAMP2, i, (uint64_t) MAX_TIME);
+                 dview->setValue (PROP_HLEAKED, i, hsize);
+                 list = heapmap->mmap (vaddr, hsize, i);
+
+                 // Increase heap size
+                 memoryUsage += hsize;
+                 dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
+               }
+             else
+               { // MUNMAP_TRACE
+                 list = heapmap->munmap (vaddr, hsize);
+
+                 // Set allocation size to zero
+                 // Note: We're currently reusing PROP_HSIZE to mean allocation size
+                 // If we ever need to save the original HSIZE, we'll need to
+                 // create a new PROP_* to represent event allocation size
+                 //
+                 //    For now, tuck the original size away as HOVADDR
+                 dview->setValue (PROP_HOVADDR, i, (uint64_t) hsize);
+                 dview->setValue (PROP_HSIZE, i, (uint64_t) 0);
+               }
+             Size total_freed = 0;
+             while (list)
+               {
+                 long idx = list->val;
+                 total_freed += list->size;
+                 Size leaked = dview->getLongValue (PROP_HLEAKED, idx);
+
+                 // Decrease heap size
+                 memoryUsage -= list->size;
+                 dview->setValue (PROP_HMEM_USAGE, i, memoryUsage);
+
+                 Size leak_update = leaked - list->size;
+                 // update allocation
+                 dview->setValue (PROP_HLEAKED, idx, leak_update);
+                 // update allocation's list of frees
+                 {
+                   UnmapChunk *copy = new UnmapChunk;
+                   heapUnmapEvents->append (copy);
+                   copy->val = dview->getIdByIdx (i);
+                   copy->size = list->size;
+                   copy->next = (UnmapChunk *) dview->getObjValue (PROP_VOIDP_OBJ, idx);
+                   dview->setObjValue (PROP_VOIDP_OBJ, idx, copy);
+                 }
+                 if (leak_update <= 0)
+                   if (leak_update == 0)
+                     dview->setValue (PROP_TSTAMP2, idx, tstamp);
+                 UnmapChunk *t = list;
+                 list = list->next;
+                 delete t;
+               }
+             // update this event
+             if (total_freed)
+               // only need to write value if it is non-zero
+               dview->setValue (PROP_HFREED, i, total_freed);
+           }
+         break;
+         // ignoring HEAPTYPE_LAST, which will never be recorded
+       case HEAPTYPE_LAST:
+         break;
+       }
+    }
+  delete heapmap;
+  delete dview;
+
+  return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_heapsz_events ()
+{
+  DataDescriptor *dDscr = getDataDescriptor (DATA_HEAPSZ);
+  if (dDscr)
+    return dDscr;
+  dDscr = get_heap_events (); // derived from DATA_HEAP
+  if (dDscr == NULL)
+    return NULL;
+  dDscr = newDataDescriptor (DATA_HEAPSZ, 0, dDscr);
+  return dDscr;
+}
+
+static void
+update_heapsz_packet (std::set<long> &pkt_id_set, DataView *dview,
+                     long alloc_pkt_id, int64_t net_alloc, uint64_t leaks)
+{
+  // pkt_id_set: set is updated to include packet
+  // alloc_pkt_id: data descriptor id (NOT dview idx)
+  // net_alloc: adjustment to net allocation for this packet (note: signed value)
+  // leaks: leak bytes to attribute to alloc_pkt_id
+  std::pair < std::set<long>::iterator, bool> ret;
+  ret = pkt_id_set.insert (alloc_pkt_id); // add to set
+  bool new_to_set = ret.second; // was not in set
+  if (!new_to_set)
+    {
+      // Has been seen before, update values
+      net_alloc += dview->getDataDescriptorValue (PROP_HCUR_NET_ALLOC, alloc_pkt_id);
+      if (leaks)
+       {
+         uint64_t old = dview->getDataDescriptorValue (PROP_HCUR_LEAKS, alloc_pkt_id);
+         if (old != 0)
+           leaks = old;
+       }
+    }
+  dview->setDataDescriptorValue (PROP_HCUR_NET_ALLOC, alloc_pkt_id, net_alloc);
+  dview->setDataDescriptorValue (PROP_HCUR_LEAKS, alloc_pkt_id, leaks);
+}
+
+DataView *
+Experiment::create_heapsz_data_view (DataView *heap_dview)
+{
+  // heap_dview has DATA_HEAP _filtered_ packets.
+  // This creates, populates, and returns DATA_HEAPSZ DataView
+  DataDescriptor *dDscr = get_heapsz_events ();
+  if (dDscr == NULL)
+    return NULL;
+  std::set<long> pkt_id_set;
+  DataView *dview = heap_dview;
+  long sz = dview->getSize ();
+  for (long i = 0; i < sz; i++)
+    {
+      int64_t hsize = (int64_t) dview->getULongValue (PROP_HSIZE, i);
+      uint64_t leaks = dview->getULongValue (PROP_HLEAKED, i);
+      long alloc_pkt_id = dview->getIdByIdx (i);
+      update_heapsz_packet (pkt_id_set, dview, alloc_pkt_id, hsize, leaks);
+
+      // linked free
+      UnmapChunk *mmap_frees = (UnmapChunk *) dview->getObjValue (PROP_VOIDP_OBJ, i); // mmap metadata
+      if (mmap_frees)
+       {
+         // mmap: all frees associated with this packet
+         while (mmap_frees)
+           {
+             long free_pkt_id = mmap_frees->val;
+             int64_t free_sz = mmap_frees->size;
+             update_heapsz_packet (pkt_id_set, dview, free_pkt_id, -free_sz, 0);
+             mmap_frees = mmap_frees->next;
+           }
+       }
+      else
+       {
+         // malloc: check for associated free
+         long free_pkt_id = dview->getLongValue (PROP_DDSCR_LNK, i) - 1;
+         if (free_pkt_id >= 0)
+           update_heapsz_packet (pkt_id_set, dview, free_pkt_id, -hsize, 0);
+       }
+    }
+
+  // create a new DataView based on the filtered-in and associated free events
+  std::set<long>::iterator it;
+  DataView *heapsz_dview = dDscr->createExtManagedView ();
+  for (it = pkt_id_set.begin (); it != pkt_id_set.end (); ++it)
+    {
+      long ddscr_pkt_id = *it;
+      heapsz_dview->appendDataDescriptorId (ddscr_pkt_id);
+    }
+  compute_heapsz_data_view (heapsz_dview);
+  return heapsz_dview;
+}
+
+void
+Experiment::compute_heapsz_data_view (DataView *heapsz_dview)
+{
+  DataView *dview = heapsz_dview;
+
+  // Keep track of memory usage
+  int64_t currentAllocs = 0;
+  Size currentLeaks = 0;
+  dview->sort (PROP_TSTAMP);
+  long sz = dview->getSize ();
+  for (long i = 0; i < sz; i++)
+    {
+      int64_t net_alloc = dview->getLongValue (PROP_HCUR_NET_ALLOC, i);
+      currentAllocs += net_alloc;
+      dview->setValue (PROP_HCUR_ALLOCS, i, currentAllocs);
+
+      Size leaks = dview->getULongValue (PROP_HCUR_LEAKS, i);
+      currentLeaks += leaks;
+      dview->setValue (PROP_HCUR_LEAKS, i, currentLeaks);
+    }
+}
+
+void
+Experiment::DBG_memuse (Sample * s)
+{
+  DataDescriptor *dDscr = getDataDescriptor (DATA_HEAP);
+  if (dDscr == NULL || dDscr->getSize () == 0)
+    return;
+
+  DataView *dview = dDscr->createView ();
+  dview->sort (PROP_TSTAMP);
+  hrtime_t ts1 = s->get_start_time ();
+  hrtime_t ts2 = s->get_end_time ();
+
+  HeapMap *heapmap = new HeapMap ();
+  long sz = dview->getSize ();
+  Size maxSize = 0;
+  Size curSize = 0;
+  hrtime_t maxTime = 0;
+  for (long i = 0; i < sz; i++)
+    {
+      hrtime_t tstamp = dview->getLongValue (PROP_TSTAMP, i);
+      if (tstamp < ts1)
+       continue;
+      if (tstamp >= ts2)
+       break;
+
+      Heap_type mtype = (Heap_type) dview->getIntValue (PROP_HTYPE, i);
+      Vaddr vaddr = dview->getULongValue (PROP_HVADDR, i);
+      Vaddr ovaddr = dview->getULongValue (PROP_HOVADDR, i);
+      switch (mtype)
+       {
+       case REALLOC_TRACE:
+         break;
+       case MALLOC_TRACE:
+         ovaddr = 0;
+         break;
+       case FREE_TRACE:
+         ovaddr = vaddr;
+         vaddr = 0;
+         break;
+       default:
+         vaddr = 0;
+         ovaddr = 0;
+         break;
+       }
+      if (ovaddr)
+       {
+         long idx = heapmap->deallocate (ovaddr) - 1;
+         if (idx >= 0)
+           curSize -= dview->getULongValue (PROP_HSIZE, idx);
+       }
+      if (vaddr)
+       {
+         heapmap->allocate (vaddr, i + 1);
+         curSize += dview->getULongValue (PROP_HSIZE, i);
+         if (curSize > maxSize)
+           {
+             maxSize = curSize;
+             maxTime = tstamp;
+           }
+       }
+    }
+  printf ("SAMPLE=%s (id=%d) MEMUSE=%lld TSTAMP=%lld\n", s->get_start_label (),
+         s->get_number (), maxSize, maxTime - getStartTime ());
+  delete dview;
+  delete heapmap;
+}
+
+void
+Experiment::DBG_memuse (const char *sname)
+{
+  for (int i = 0; i < samples->size (); ++i)
+    {
+      Sample *sample = samples->fetch (i);
+      if (streq (sname, sample->get_start_label ()))
+       {
+         DBG_memuse (sample);
+         break;
+       }
+    }
+}
+
+DataDescriptor *
+Experiment::get_race_events ()
+{
+  DataDescriptor *dDscr = getDataDescriptor (DATA_RACE);
+  if (dDscr == NULL)
+    return NULL;
+  if (dDscr->getSize () == 0)
+    {
+      char *base_name = get_basename (expt_name);
+      char *msg = dbe_sprintf (GTXT ("Loading Race Data: %s"), base_name);
+      read_data_file (SP_RACETRACE_FILE, msg);
+      free (msg);
+      resolve_frame_info (dDscr);
+    }
+  return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_deadlock_events ()
+{
+  DataDescriptor *dDscr = getDataDescriptor (DATA_DLCK);
+  if (dDscr == NULL)
+    return NULL;
+  if (dDscr->getSize () == 0)
+    {
+      char *base_name = get_basename (expt_name);
+      char *msg = dbe_sprintf (GTXT ("Loading Deadlocks Data: %s"), base_name);
+      read_data_file (SP_DEADLOCK_FILE, msg);
+      free (msg);
+      resolve_frame_info (dDscr);
+    }
+  return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_sample_events ()
+{
+  DataDescriptor *dDscr = getDataDescriptor (DATA_SAMPLE);
+  if (dDscr == NULL)
+    return NULL;
+  if (dDscr->getSize () > 0)
+    return dDscr;
+
+  // read_overview_file(); //YXXX do this here at some point instead of:
+  PropDescr *tmp_propDscr;
+  tmp_propDscr = new PropDescr (PROP_SMPLOBJ, NTXT ("SMPLOBJ"));
+  tmp_propDscr->uname = NULL;
+  tmp_propDscr->vtype = TYPE_OBJ;
+  dDscr->addProperty (tmp_propDscr);
+
+  tmp_propDscr = new PropDescr (PROP_TSTAMP, NTXT ("TSTAMP"));
+  tmp_propDscr->uname = dbe_strdup ("High resolution timestamp");
+  tmp_propDscr->vtype = TYPE_UINT64;
+  dDscr->addProperty (tmp_propDscr);
+
+  tmp_propDscr = new PropDescr (PROP_SAMPLE, NTXT ("SAMPLE"));
+  tmp_propDscr->uname = dbe_strdup ("Sample number");
+  tmp_propDscr->vtype = TYPE_UINT64;
+  dDscr->addProperty (tmp_propDscr);
+
+  tmp_propDscr = new PropDescr (PROP_EVT_TIME, NTXT ("EVT_TIME"));
+  tmp_propDscr->uname = dbe_strdup ("Event duration");
+  tmp_propDscr->vtype = TYPE_UINT64;
+  dDscr->addProperty (tmp_propDscr);
+
+  long ssize = samples->size ();
+  for (long ii = 0; ii < ssize; ii++)
+    {
+      Sample * sample = samples->fetch (ii);
+      long recn = dDscr->addRecord ();
+      hrtime_t sduration = sample->get_end_time () - sample->get_start_time ();
+      dDscr->setObjValue (PROP_SMPLOBJ, recn, sample);
+      dDscr->setValue (PROP_SAMPLE, recn, sample->get_number ());
+      dDscr->setValue (PROP_TSTAMP, recn, sample->get_end_time ());
+      dDscr->setValue (PROP_EVT_TIME, recn, sduration);
+    }
+  return dDscr;
+}
+
+DataDescriptor *
+Experiment::get_gc_events ()
+{
+  DataDescriptor *dDscr = getDataDescriptor (DATA_GCEVENT);
+  if (dDscr == NULL)
+    return NULL;
+  if (dDscr->getSize () > 0)
+    return dDscr;
+
+  // read_overview_file(); //YXXX do this here at some point instead of:
+  PropDescr *tmp_propDscr;
+  tmp_propDscr = new PropDescr (PROP_GCEVENTOBJ, NTXT ("GCEVENTOBJ"));
+  tmp_propDscr->uname = NULL;
+  tmp_propDscr->vtype = TYPE_OBJ;
+  dDscr->addProperty (tmp_propDscr);
+
+  tmp_propDscr = new PropDescr (PROP_TSTAMP, NTXT ("TSTAMP"));
+  tmp_propDscr->uname = dbe_strdup ("High resolution timestamp");
+  tmp_propDscr->vtype = TYPE_UINT64;
+  dDscr->addProperty (tmp_propDscr);
+
+  tmp_propDscr = new PropDescr (PROP_GCEVENT, NTXT ("GCEVENT"));
+  tmp_propDscr->uname = dbe_strdup ("GCEvent number");
+  tmp_propDscr->vtype = TYPE_UINT64;
+  dDscr->addProperty (tmp_propDscr);
+
+  tmp_propDscr = new PropDescr (PROP_EVT_TIME, NTXT ("EVT_TIME"));
+  tmp_propDscr->uname = dbe_strdup ("Event duration");
+  tmp_propDscr->vtype = TYPE_UINT64;
+  dDscr->addProperty (tmp_propDscr);
+
+  long ssize = gcevents->size ();
+  for (long ii = 0; ii < ssize; ii++)
+    {
+      GCEvent * gcevent = gcevents->fetch (ii);
+      long recn = dDscr->addRecord ();
+      hrtime_t sduration = gcevent->end - gcevent->start;
+      dDscr->setObjValue (PROP_GCEVENTOBJ, recn, gcevent);
+      dDscr->setValue (PROP_GCEVENT, recn, gcevent->id);
+      dDscr->setValue (PROP_TSTAMP, recn, gcevent->end);
+      dDscr->setValue (PROP_EVT_TIME, recn, sduration);
+    }
+  return dDscr;
+}
+
+void
+Experiment::update_last_event (hrtime_t ts/*wall_ts*/)
+{
+  if (last_event == ZERO_TIME)
+    {
+      // not yet initialized
+      last_event = ts;
+    }
+  if (last_event - exp_start_time < ts - exp_start_time)
+    // compare deltas to avoid hrtime_t wrap
+    last_event = ts;
+}
+
+void
+Experiment::write_header ()
+{
+  StringBuilder sb;
+
+  // write commentary to the experiment, describing the parameters
+  if (dbeSession->ipc_mode || dbeSession->rdt_mode)
+    {
+      // In GUI: print start time at the beginning
+      char *start_time = ctime (&start_sec);
+      if (start_time != NULL)
+       {
+         sb.setLength (0);
+         sb.sprintf (GTXT ("Experiment started %s"), start_time);
+         commentq->append (new Emsg (CMSG_COMMENT, sb));
+       }
+    }
+  // write message with target arglist
+  if (uarglist != NULL)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("\nTarget command (%s): '%s'"),
+                 (wsize == W32 ? "32-bit" : "64-bit"), uarglist);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+
+  sb.setLength (0);
+  sb.sprintf (GTXT ("Process pid %d, ppid %d, pgrp %d, sid %d"),
+             pid, ppid, pgrp, sid);
+  commentq->append (new Emsg (CMSG_COMMENT, sb));
+
+  // add comment for user name, if set
+  if (username != NULL)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("User: `%s'"), username);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+
+  // add comment for current working directory
+  if (ucwd != NULL)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("Current working directory: %s"), ucwd);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+
+  // add comment for collector version string
+  if (cversion != NULL)
+    {
+      char *wstring;
+      switch (wsize)
+       {
+       case Wnone:
+         wstring = NTXT ("?");
+         break;
+       case W32:
+         wstring = GTXT ("32-bit");
+         break;
+       case W64:
+         wstring = GTXT ("64-bit");
+         break;
+       default:
+         wstring = NTXT ("??");
+         break;
+       }
+      sb.setLength (0);
+      sb.sprintf (GTXT ("Collector version: `%s'; experiment version %d.%d (%s)"),
+                 cversion, exp_maj_version, exp_min_version, wstring);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+
+  // add comment for driver version string (er_kernel)
+  if (dversion != NULL)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("Kernel driver version: `%s'"), dversion);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+
+  if (jversion != NULL)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("JVM version: `%s'"), jversion);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+
+  // add comment for hostname, parameters
+  if (hostname == NULL)
+    hostname = dbe_strdup (GTXT ("unknown"));
+  if (os_version == NULL)
+    os_version = dbe_strdup (GTXT ("unknown"));
+  if (architecture == NULL)
+    architecture = dbe_strdup (GTXT ("unknown"));
+  sb.setLength (0);
+  sb.sprintf (GTXT ("Host `%s', OS `%s', page size %d, architecture `%s'"),
+             hostname, os_version, page_size, architecture);
+  commentq->append (new Emsg (CMSG_COMMENT, sb));
+
+  sb.setLength (0);
+  if (maxclock != minclock)
+    {
+      clock = maxclock;
+      sb.sprintf (
+                 GTXT ("  %d CPUs, with clocks ranging from %d to %d MHz.; max of %d MHz. assumed"),
+                 ncpus, minclock, maxclock, clock);
+    }
+  else
+    sb.sprintf (GTXT ("  %d CPU%s, clock speed %d MHz."),
+               ncpus, (ncpus == 1 ? NTXT ("") : "s"), clock);
+  commentq->append (new Emsg (CMSG_COMMENT, sb));
+
+  // add comment for machine memory size
+  if (page_size > 0 && npages > 0)
+    {
+      long long memsize = ((long long) npages * page_size) / (1024 * 1024);
+      sb.setLength (0);
+      sb.sprintf (GTXT ("  Memory: %d pages @  %d = %lld MB."),
+                 npages, page_size, memsize);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+
+  // add comment for machine memory size
+  if (machinemodel != NULL)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("  Machine model: %s"), machinemodel);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+
+  // add comment for start time
+  char *p = ctime (&start_sec);
+  sb.setLength (0);
+  if (p != NULL)
+    sb.sprintf (GTXT ("Experiment started %s"), p);
+  else
+    sb.sprintf (GTXT ("\nExperiment start not recorded"));
+  write_coll_params ();
+  commentq->append (new Emsg (CMSG_COMMENT, sb));
+  commentq->appendqueue (runlogq);
+  runlogq->mark_clear ();
+}
+
+void
+Experiment::write_coll_params ()
+{
+  StringBuilder sb;
+
+  // now write the various collection parameters as comments
+  sb.setLength (0);
+  sb.append (GTXT ("Data collection parameters:"));
+  commentq->append (new Emsg (CMSG_COMMENT, sb));
+  if (coll_params.profile_mode == 1)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("  Clock-profiling, interval = %d microsecs."),
+                 (int) (coll_params.ptimer_usec));
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+  if (coll_params.sync_mode == 1)
+    {
+      sb.setLength (0);
+      char *scope_str = NTXT ("");
+      switch (coll_params.sync_scope)
+       {
+       case 0:
+         scope_str = GTXT ("Native- and Java-APIs");
+         break;
+       case SYNCSCOPE_JAVA:
+         scope_str = GTXT ("JAVA-APIs");
+         break;
+       case SYNCSCOPE_NATIVE:
+         scope_str = GTXT ("Native-APIs");
+         break;
+       case SYNCSCOPE_JAVA | SYNCSCOPE_NATIVE:
+         scope_str = GTXT ("Native- and Java-APIs");
+         break;
+       }
+      if (coll_params.sync_threshold < 0)
+       sb.sprintf (GTXT ("  Synchronization tracing, threshold = %d microsecs. (calibrated); %s"),
+                   -coll_params.sync_threshold, scope_str);
+      else
+       sb.sprintf (GTXT ("  Synchronization tracing, threshold = %d microsecs.; %s"),
+                   coll_params.sync_threshold, scope_str);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+  if (coll_params.heap_mode == 1)
+    {
+      sb.setLength (0);
+      sb.append (GTXT ("  Heap tracing"));
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+  if (coll_params.io_mode == 1)
+    {
+      sb.setLength (0);
+      sb.append (GTXT ("  IO tracing"));
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+  if (coll_params.race_mode == 1)
+    {
+      sb.setLength (0);
+      char *race_stack_name;
+      switch (coll_params.race_stack)
+       {
+       case 0:
+         race_stack_name = GTXT ("dual-stack");
+         break;
+       case 1:
+         race_stack_name = GTXT ("single-stack");
+         break;
+       case 2:
+         race_stack_name = GTXT ("leaf");
+         break;
+       default:
+         abort ();
+       }
+      sb.sprintf (GTXT ("  Datarace detection, %s"), race_stack_name);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+  if (coll_params.deadlock_mode == 1)
+    {
+      sb.setLength (0);
+      sb.append (GTXT ("  Deadlock detection"));
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+  if (coll_params.hw_mode == 1)
+    {
+      sb.setLength (0);
+      if (hwc_default == true)
+       sb.append (GTXT ("  HW counter-profiling (default); counters:"));
+      else
+       sb.append (GTXT ("  HW counter-profiling; counters:"));
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+      for (int i = 0; i < MAX_HWCOUNT; i++)
+       {
+         if (!coll_params.hw_aux_name[i])
+           continue;
+         sb.setLength (0);
+         sb.sprintf (GTXT ("    %s, tag %d, interval %d, memop %d"),
+                     coll_params.hw_aux_name[i], i,
+                     coll_params.hw_interval[i], coll_params.hw_tpc[i]);
+         commentq->append (new Emsg (CMSG_COMMENT, sb));
+       }
+    }
+  if (coll_params.sample_periodic == 1)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("  Periodic sampling, %d secs."),
+                 coll_params.sample_timer);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+  if (coll_params.limit != 0)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("  Experiment size limit, %d"),
+                 coll_params.limit);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+  if (coll_params.linetrace != NULL)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("  Follow descendant processes from: %s"),
+                 coll_params.linetrace);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+  if (coll_params.pause_sig != NULL)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("  Pause signal %s"), coll_params.pause_sig);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+  if (coll_params.sample_sig != NULL)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("  Sample signal %s"), coll_params.sample_sig);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+  if (coll_params.start_delay != NULL)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("  Data collection delay start %s seconds"), coll_params.start_delay);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+  if (coll_params.terminate != NULL)
+    {
+      sb.setLength (0);
+      sb.sprintf (GTXT ("  Data collection termination after %s seconds"), coll_params.terminate);
+      commentq->append (new Emsg (CMSG_COMMENT, sb));
+    }
+  // add a blank line after data description
+  commentq->append (new Emsg (CMSG_COMMENT, NTXT ("")));
+}
+
+
+/*
+ *    Raw packet processing
+ */
+static int
+check_mstate (char *ptr, PacketDescriptor *pDscr, int arg)
+{
+  switch (arg)
+    {
+    case PROP_UCPU:
+    case PROP_SCPU:
+    case PROP_TRAP:
+    case PROP_TFLT:
+    case PROP_DFLT:
+    case PROP_KFLT:
+    case PROP_ULCK:
+    case PROP_TSLP:
+    case PROP_WCPU:
+    case PROP_TSTP:
+      break;
+    default:
+      return 0;
+    }
+  Vector<FieldDescr*> *fields = pDscr->getFields ();
+  for (int i = 0, sz = fields->size (); i < sz; i++)
+    {
+      FieldDescr *fDscr = fields->fetch (i);
+      if (fDscr->propID == arg)
+       return *((int*) (ptr + fDscr->offset));
+    }
+  return 0;
+}
+
+#define PACKET_ALIGNMENT 4
+
+uint64_t
+Experiment::readPacket (Data_window *dwin, Data_window::Span *span)
+{
+  Common_packet *rcp = (Common_packet *) dwin->bind (span,
+                                                   sizeof (CommonHead_packet));
+  uint16_t v16;
+  uint64_t size = 0;
+  if (rcp)
+    {
+      if ((((long) rcp) % PACKET_ALIGNMENT) != 0)
+       {
+         invalid_packet++;
+         size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
+         return size;
+       }
+      v16 = (uint16_t) rcp->tsize;
+      size = dwin->decode (v16);
+      if (size == 0)
+       {
+         size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
+         return size;
+       }
+      rcp = (Common_packet *) dwin->bind (span, size);
+    }
+  if (rcp == NULL)
+    return 0;
+
+  if ((((long) rcp) % PACKET_ALIGNMENT) != 0)
+    {
+      invalid_packet++;
+      size = PROFILE_BUFFER_CHUNK - span->offset % PROFILE_BUFFER_CHUNK;
+      return size;
+    }
+  v16 = (uint16_t) rcp->type;
+  uint32_t rcptype = dwin->decode (v16);
+  if (rcptype == EMPTY_PCKT)
+    return size;
+  if (rcptype == FRAME_PCKT)
+    {
+      RawFramePacket *fp = new RawFramePacket;
+      fp->uid = dwin->decode (((Frame_packet*) rcp)->uid);
+      fp->uidn = NULL;
+      fp->uidj = NULL;
+      fp->omp_uid = NULL;
+      fp->omp_state = 0;
+      char *ptr = (char*) rcp + dwin->decode (((Frame_packet*) rcp)->hsize);
+      if ((((long) ptr) % PACKET_ALIGNMENT) != 0)
+       {
+         invalid_packet++;
+         delete fp;
+         return size;
+       }
+      v16 = (uint16_t) ((Frame_packet*) rcp)->tsize;
+      char *end = (char*) rcp + dwin->decode (v16);
+      for (; ptr < end;)
+       {
+         Common_info *cinfo = (Common_info*) ptr;
+         uint32_t hsize = dwin->decode (cinfo->hsize);
+         if (hsize == 0 || ptr + hsize > end)
+           break;
+         int kind = dwin->decode (cinfo->kind);
+         bool compressed = false;
+         if (kind & COMPRESSED_INFO)
+           {
+             compressed = true;
+             kind &= ~COMPRESSED_INFO;
+           }
+         switch (kind)
+           {
+           case STACK_INFO:
+             {
+               char *stack = ptr + sizeof (Stack_info);
+               size_t stack_size = hsize - sizeof (Stack_info);
+               uint64_t uidn = dwin->decode (((Stack_info*) cinfo)->uid);
+               if (stack_size <= 0)
+                 {
+                   fp->uidn = get_uid_node (uidn);
+                   break;
+                 }
+               uint64_t link_uid = (uint64_t) 0;
+               if (compressed)
+                 {
+                   stack_size -= sizeof (uint64_t);
+                   unsigned char *s = (unsigned char*) (stack + stack_size);
+                   int shift = 0;
+                   for (size_t i = 0; i<sizeof (link_uid); i++)
+                     {
+                       link_uid |= (uint64_t) * s++ << shift;
+                       shift += 8;
+                     }
+                 }
+               if (wsize == W32)
+                 fp->uidn = add_uid (dwin, uidn,
+                                     (int) (stack_size / sizeof (uint32_t)),
+                                     (uint32_t*) stack, link_uid);
+               else
+                 fp->uidn = add_uid (dwin, uidn,
+                                     (int) (stack_size / sizeof (uint64_t)),
+                                     (uint64_t*) stack, link_uid);
+               break;
+             }
+           case JAVA_INFO:
+             {
+               char *stack = ptr + sizeof (Java_info);
+               size_t stack_size = hsize - sizeof (Java_info);
+               uint64_t uidj = dwin->decode (((Java_info*) cinfo)->uid);
+               if (stack_size <= 0)
+                 {
+                   fp->uidj = get_uid_node (uidj);
+                   break;
+                 }
+
+               uint64_t link_uid = (uint64_t) 0;
+               if (compressed)
+                 {
+                   stack_size -= sizeof (uint64_t);
+                   unsigned char *s = (unsigned char*) (stack + stack_size);
+                   int shift = 0;
+                   for (size_t i = 0; i<sizeof (link_uid); i++)
+                     {
+                       link_uid |= (uint64_t) * s++ << shift;
+                       shift += 8;
+                     }
+                 }
+               if (wsize == W32)
+                 fp->uidj = add_uid (dwin, uidj,
+                                     (int) (stack_size / sizeof (uint32_t)),
+                                     (uint32_t*) stack, link_uid);
+               else
+                 {
+                   // bug 6909545: garbage in 64-bit JAVA_INFO
+                   char *nstack = (char*) malloc (stack_size);
+                   char *dst = nstack;
+                   char *srcmax = stack + stack_size - sizeof (uint64_t);
+                   for (char *src = stack; src <= srcmax;)
+                     {
+                       int64_t val = dwin->decode (*(int32_t*) src);
+                       *(uint64_t*) dst = dwin->decode (val);
+                       src += sizeof (uint64_t);
+                       dst += sizeof (uint64_t);
+                       if (src > srcmax)
+                         {
+                           fprintf (stderr, "er_print: Experiment::readPacket: Error in data: src=%llx greater than %llx\n",
+                                    (long long) src, (long long) srcmax);
+                           break;
+                         }
+                       *(uint64_t*) dst = *(uint64_t*) src;
+                       src += sizeof (uint64_t);
+                       dst += sizeof (uint64_t);
+                     }
+                   fp->uidj = add_uid (dwin, uidj,
+                                       (int) (stack_size / sizeof (uint64_t)),
+                                       (uint64_t*) nstack, link_uid);
+                   free (nstack);
+                 }
+               break;
+             }
+           case OMP_INFO:
+             fp->omp_state = dwin->decode (((OMP_info*) ptr)->omp_state);
+             break;
+           case OMP2_INFO:
+             {
+               uint64_t omp_uid = dwin->decode (((OMP2_info*) ptr)->uid);
+               fp->omp_uid = get_uid_node (omp_uid);
+               fp->omp_state = dwin->decode (((OMP2_info*) ptr)->omp_state);
+               break;
+             }
+           default:
+             break;
+           }
+         ptr += hsize;
+       }
+      frmpckts->append (fp);
+      return size;
+    }
+  else if (rcptype == UID_PCKT)
+    {
+      Uid_packet *uidp = (Uid_packet*) rcp;
+      uint64_t uid = dwin->decode (uidp->uid);
+      char *arr_bytes = (char*) (uidp + 1);
+      v16 = (uint16_t) rcp->tsize;
+      size_t arr_length = dwin->decode (v16) - sizeof (Uid_packet);
+      if (arr_length <= 0)
+       return size;
+      uint64_t link_uid = (uint64_t) 0;
+      if (dwin->decode (uidp->flags) & COMPRESSED_INFO)
+       {
+         arr_length -= sizeof (uint64_t);
+         unsigned char *s = (unsigned char*) (arr_bytes + arr_length);
+         int shift = 0;
+         for (size_t i = 0; i<sizeof (link_uid); i++)
+           {
+             link_uid |= (uint64_t) * s++ << shift;
+             shift += 8;
+           }
+       }
+      if (wsize == W32)
+       add_uid (dwin, uid, (int) (arr_length / sizeof (uint32_t)),
+                (uint32_t*) arr_bytes, link_uid);
+      else
+       add_uid (dwin, uid, (int) (arr_length / sizeof (uint64_t)),
+                (uint64_t*) arr_bytes, link_uid);
+      return size;
+    }
+
+  PacketDescriptor *pcktDescr = getPacketDescriptor (rcptype);
+  if (pcktDescr == NULL)
+    return size;
+  DataDescriptor *dataDescr = pcktDescr->getDataDescriptor ();
+  if (dataDescr == NULL)
+    return size;
+
+  /* omazur: TBR START -- old experiment */
+  if (rcptype == PROF_PCKT)
+    {
+      // For backward compatibility with older SS12 experiments
+      int numstates = get_params ()->lms_magic_id; // ugly, for old experiments
+      if (numstates > LMS_NUM_SOLARIS_MSTATES)
+       numstates = LMS_NUM_SOLARIS_MSTATES;
+      for (int i = 0; i < numstates; i++)
+       if (check_mstate ((char*) rcp, pcktDescr, PROP_UCPU + i))
+         readPacket (dwin, (char*) rcp, pcktDescr, dataDescr, PROP_UCPU + i,
+                     size);
+    }
+  else
+    readPacket (dwin, (char*) rcp, pcktDescr, dataDescr, 0, size);
+  return size;
+}
+
+void
+Experiment::readPacket (Data_window *dwin, char *ptr, PacketDescriptor *pDscr,
+                       DataDescriptor *dDscr, int arg, uint64_t pktsz)
+{
+  union Value
+  {
+    uint32_t val32;
+    uint64_t val64;
+  } *v;
+
+  long recn = dDscr->addRecord ();
+  Vector<FieldDescr*> *fields = pDscr->getFields ();
+  int sz = fields->size ();
+  for (int i = 0; i < sz; i++)
+    {
+      FieldDescr *field = fields->fetch (i);
+      v = (Value*) (ptr + field->offset);
+      if (field->propID == arg)
+       {
+         dDscr->setValue (PROP_NTICK, recn, dwin->decode (v->val32));
+         dDscr->setValue (PROP_MSTATE, recn, (uint32_t) (field->propID - PROP_UCPU));
+       }
+      if (field->propID == PROP_THRID || field->propID == PROP_LWPID
+         || field->propID == PROP_CPUID)
+       {
+         uint64_t tmp64 = 0;
+         switch (field->vtype)
+           {
+           case TYPE_INT32:
+           case TYPE_UINT32:
+             tmp64 = dwin->decode (v->val32);
+             break;
+           case TYPE_INT64:
+           case TYPE_UINT64:
+             tmp64 = dwin->decode (v->val64);
+             break;
+           case TYPE_STRING:
+           case TYPE_DOUBLE:
+           case TYPE_OBJ:
+           case TYPE_DATE:
+           case TYPE_BOOL:
+           case TYPE_ENUM:
+           case TYPE_LAST:
+           case TYPE_NONE:
+             break;
+           }
+         uint32_t tag = mapTagValue ((Prop_type) field->propID, tmp64);
+         dDscr->setValue (field->propID, recn, tag);
+       }
+      else
+       {
+         switch (field->vtype)
+           {
+           case TYPE_INT32:
+           case TYPE_UINT32:
+             dDscr->setValue (field->propID, recn, dwin->decode (v->val32));
+             break;
+           case TYPE_INT64:
+           case TYPE_UINT64:
+             dDscr->setValue (field->propID, recn, dwin->decode (v->val64));
+             break;
+           case TYPE_STRING:
+             {
+               int len = (int) (pktsz - field->offset);
+               if ((len > 0) && (ptr[field->offset] != 0))
+                 {
+                   StringBuilder *sb = new StringBuilder ();
+                   sb->append (ptr + field->offset, 0, len);
+                   dDscr->setObjValue (field->propID, recn, sb);
+                 }
+               break;
+             }
+             // ignoring the following cases (why?)
+           case TYPE_DOUBLE:
+           case TYPE_OBJ:
+           case TYPE_DATE:
+           case TYPE_BOOL:
+           case TYPE_ENUM:
+           case TYPE_LAST:
+           case TYPE_NONE:
+             break;
+           }
+       }
+    }
+}
+
+#define PROG_BYTE 102400 // update progress bar every PROG_BYTE bytes
+
+void
+Experiment::read_data_file (const char *fname, const char *msg)
+{
+  Data_window::Span span;
+  off64_t total_len, remain_len;
+  char *progress_bar_msg;
+  int progress_bar_percent = -1;
+
+  char *data_file_name = dbe_sprintf (NTXT ("%s/%s"), expt_name, fname);
+  Data_window *dwin = new Data_window (data_file_name);
+  // Here we can call stat(data_file_name) to get file size,
+  // and call a function to reallocate vectors for clock profiling data
+  free (data_file_name);
+  if (dwin->not_opened ())
+    {
+      delete dwin;
+      return;
+    }
+  dwin->need_swap_endian = need_swap_endian;
+
+  span.offset = 0;
+  span.length = dwin->get_fsize ();
+  total_len = remain_len = span.length;
+  progress_bar_msg = dbe_sprintf (NTXT ("%s %s"), NTXT ("  "), msg);
+  invalid_packet = 0;
+  for (;;)
+    {
+      uint64_t pcktsz = readPacket (dwin, &span);
+      if (pcktsz == 0)
+       break;
+      // Update progress bar
+      if ((span.length <= remain_len) && (remain_len > 0))
+       {
+         int percent = (int) (100 * (total_len - remain_len) / total_len);
+         if (percent > progress_bar_percent)
+           {
+             progress_bar_percent += 10;
+             theApplication->set_progress (percent, progress_bar_msg);
+           }
+         remain_len -= PROG_BYTE;
+       }
+      span.length -= pcktsz;
+      span.offset += pcktsz;
+    }
+  delete dwin;
+
+  if (invalid_packet)
+    {
+      StringBuilder sb;
+      sb.sprintf (GTXT ("WARNING: There are %d invalid packet(s) in the %s file"),
+                 invalid_packet, fname);
+      Emsg *m = new Emsg (CMSG_WARN, sb);
+      warnq->append (m);
+    }
+
+  theApplication->set_progress (0, NTXT (""));
+  free (progress_bar_msg);
+}
+
+int
+Experiment::read_overview_file ()
+{
+  char *data_file_name = dbe_sprintf ("%s/%s", expt_name, SP_OVERVIEW_FILE);
+  Data_window *dwin = new Data_window (data_file_name);
+  free (data_file_name);
+  if (dwin->not_opened ())
+    {
+      delete dwin;
+      return 0;
+    }
+  dwin->need_swap_endian = need_swap_endian;
+  newDataDescriptor (DATA_SAMPLE);
+
+  Data_window::Span span;
+  span.offset = 0;
+  span.length = dwin->get_fsize ();
+
+  PrUsage *data = NULL, *data_prev = NULL;
+  Sample *sample;
+  int sample_number = 1;
+
+  int64_t prDataSize;
+  if (wsize == W32)
+    prDataSize = PrUsage::bind32Size ();
+  else
+    prDataSize = PrUsage::bind64Size ();
+
+  while (span.length > 0)
+    {
+      data_prev = data;
+      data = new PrUsage ();
+
+      void *dw = dwin->bind (&span, prDataSize);
+      if ((dw == NULL) || (prDataSize > span.length))
+       {
+         Emsg *m = new Emsg (CMSG_ERROR, GTXT ("Warning: overview data file can't be read"));
+         warnq->append (m);
+         status = FAILURE;
+         delete dwin;
+         return status;
+       }
+
+      if (wsize == W32)
+       data->bind32 (dw, need_swap_endian);
+      else
+       data->bind64 (dw, need_swap_endian);
+      span.length -= prDataSize;
+      span.offset += prDataSize;
+
+      // Skip the first packet
+      if (data_prev == NULL)
+       continue;
+      if (sample_number > samples->size ())
+       { // inconsistent log/overview
+         sample = new Sample (sample_number);
+         char * label = GTXT ("<unknown>");
+         sample->start_label = dbe_strdup (label);
+         sample->end_label = dbe_strdup (label);
+         samples->append (sample);
+       }
+      else
+       sample = samples->fetch (sample_number - 1);
+      sample_number++;
+      sample->start_time = data_prev->pr_tstamp + 1;
+      sample->end_time = data->pr_tstamp;
+      sample->prusage = data_prev;
+
+      data_prev->pr_rtime = data->pr_rtime - data_prev->pr_rtime;
+      data_prev->pr_utime = data->pr_utime - data_prev->pr_utime;
+      data_prev->pr_stime = data->pr_stime - data_prev->pr_stime;
+      data_prev->pr_ttime = data->pr_ttime - data_prev->pr_ttime;
+      data_prev->pr_tftime = data->pr_tftime - data_prev->pr_tftime;
+      data_prev->pr_dftime = data->pr_dftime - data_prev->pr_dftime;
+      data_prev->pr_kftime = data->pr_kftime - data_prev->pr_kftime;
+      data_prev->pr_ltime = data->pr_ltime - data_prev->pr_ltime;
+      data_prev->pr_slptime = data->pr_slptime - data_prev->pr_slptime;
+      data_prev->pr_wtime = data->pr_wtime - data_prev->pr_wtime;
+      data_prev->pr_stoptime = data->pr_stoptime - data_prev->pr_stoptime;
+      data_prev->pr_minf = data->pr_minf - data_prev->pr_minf;
+      data_prev->pr_majf = data->pr_majf - data_prev->pr_majf;
+      data_prev->pr_nswap = data->pr_nswap - data_prev->pr_nswap;
+      data_prev->pr_inblk = data->pr_inblk - data_prev->pr_inblk;
+      data_prev->pr_oublk = data->pr_oublk - data_prev->pr_oublk;
+      data_prev->pr_msnd = data->pr_msnd - data_prev->pr_msnd;
+      data_prev->pr_mrcv = data->pr_mrcv - data_prev->pr_mrcv;
+      data_prev->pr_sigs = data->pr_sigs - data_prev->pr_sigs;
+      data_prev->pr_vctx = data->pr_vctx - data_prev->pr_vctx;
+      data_prev->pr_ictx = data->pr_ictx - data_prev->pr_ictx;
+      data_prev->pr_sysc = data->pr_sysc - data_prev->pr_sysc;
+      data_prev->pr_ioch = data->pr_ioch - data_prev->pr_ioch;
+      sample->get_usage (); // force validation
+    }
+
+  for (long smpNum = samples->size (); smpNum >= sample_number; smpNum--)
+    {
+      // overview file was truncated
+      sample = samples->remove (smpNum - 1);
+      delete sample;
+    }
+
+  if (data)
+    {
+      // Update last_event so that getEndTime() covers
+      // all loadobjects, too.
+      update_last_event (data->pr_tstamp);
+      delete data;
+    }
+  delete dwin;
+  return SUCCESS;
+}
+
+int
+Experiment::uidNodeCmp (const void *a, const void *b)
+{
+  UIDnode *nd1 = *(UIDnode**) a;
+  UIDnode *nd2 = *(UIDnode**) b;
+  if (nd1->uid == nd2->uid)
+    return 0;
+  return nd1->uid < nd2->uid ? -1 : 1;
+}
+
+static uint64_t
+funcAddr (uint32_t val)
+{
+  if (val == (uint32_t) SP_LEAF_CHECK_MARKER)
+    return (uint64_t) SP_LEAF_CHECK_MARKER;
+  if (val == (uint32_t) SP_TRUNC_STACK_MARKER)
+    return (uint64_t) SP_TRUNC_STACK_MARKER;
+  if (val == (uint32_t) SP_FAILED_UNWIND_MARKER)
+    return (uint64_t) SP_FAILED_UNWIND_MARKER;
+  return val;
+}
+
+Experiment::UIDnode *
+Experiment::add_uid (Data_window *dwin, uint64_t uid, int size,
+                    uint32_t *array, uint64_t link_uid)
+{
+  if (uid == (uint64_t) 0)
+    return NULL;
+  uint64_t val = funcAddr (dwin->decode (array[0]));
+  UIDnode *node = NULL;
+  UIDnode *res = get_uid_node (uid, val);
+  UIDnode *next = res;
+  for (int i = 0; i < size; i++)
+    {
+      val = funcAddr (dwin->decode (array[i]));
+      if (next == NULL)
+       {
+         next = get_uid_node ((uint64_t) 0, val);
+         if (node != NULL)
+           node->next = next;
+       }
+      node = next;
+      next = node->next;
+      if (node->val == 0)
+       node->val = val;
+      else if (node->val != val)   // Algorithmic error (should never happen)
+       node->val = (uint64_t) SP_LEAF_CHECK_MARKER;
+    }
+  if (next == NULL && link_uid != (uint64_t) 0 && node != NULL)
+    node->next = get_uid_node (link_uid);
+  return res;
+}
+
+Experiment::UIDnode *
+Experiment::add_uid (Data_window *dwin, uint64_t uid, int size, uint64_t *array, uint64_t link_uid)
+{
+  if (uid == (uint64_t) 0)
+    return NULL;
+  UIDnode *node = NULL;
+  uint64_t val = dwin->decode (array[0]);
+  UIDnode *res = get_uid_node (uid, val);
+  UIDnode *next = res;
+  for (int i = 0; i < size; i++)
+    {
+      val = dwin->decode (array[i]);
+      if (next == NULL)
+       {
+         next = get_uid_node ((uint64_t) 0, val);
+         if (node != NULL)
+           node->next = next;
+       }
+      node = next;
+      next = node->next;
+      if (node->val == (uint64_t) 0)
+       node->val = val;
+      else if (node->val != val)   // Algorithmic error (should never happen)
+       node->val = (uint64_t) - 1;
+    }
+  if (next == NULL && link_uid != (uint64_t) 0 && node != NULL)
+    node->next = get_uid_node (link_uid);
+  return res;
+}
+
+Experiment::UIDnode *
+Experiment::new_uid_node (uint64_t uid, uint64_t val)
+{
+#define NCHUNKSTEP 1024
+  if (nnodes >= nchunks * CHUNKSZ)
+    {
+      // Reallocate Node chunk array
+      UIDnode** old_chunks = chunks;
+      chunks = new UIDnode*[nchunks + NCHUNKSTEP];
+      memcpy (chunks, old_chunks, nchunks * sizeof (UIDnode*));
+      nchunks += NCHUNKSTEP;
+      delete[] old_chunks;
+      // Clean future pointers
+      memset (&chunks[nchunks - NCHUNKSTEP], 0, NCHUNKSTEP * sizeof (UIDnode*));
+    }
+
+  if (NULL == chunks[nnodes / CHUNKSZ])   // Allocate new chunk for nodes.
+    chunks[nnodes / CHUNKSZ] = new UIDnode[CHUNKSZ];
+  UIDnode *node = &chunks[nnodes / CHUNKSZ][nnodes % CHUNKSZ];
+  node->uid = uid;
+  node->val = val;
+  node->next = NULL;
+  nnodes++;
+  return node;
+}
+
+Experiment::UIDnode *
+Experiment::get_uid_node (uint64_t uid, uint64_t val)
+{
+  int hash = (((int) uid) >> 4) & (HTableSize - 1);
+  if (uid != (uint64_t) 0)
+    {
+      UIDnode *node = uidHTable[hash];
+      if (node && node->uid == uid)
+       return node;
+    }
+  UIDnode *node = new_uid_node (uid, val);
+  if (uid != (uint64_t) 0)
+    {
+      uidHTable[hash] = node;
+      uidnodes->append (node);
+    }
+  return node;
+}
+
+Experiment::UIDnode *
+Experiment::get_uid_node (uint64_t uid)
+{
+  if (uid == (uint64_t) 0)
+    return NULL;
+  int hash = (((int) uid) >> 4) & (HTableSize - 1);
+  UIDnode *node = uidHTable[hash];
+  if (node && node->uid == uid)
+    return node;
+  node = new_uid_node (uid, (uint64_t) 0);
+  node->next = node;
+  return node;
+}
+
+Experiment::UIDnode *
+Experiment::find_uid_node (uint64_t uid)
+{
+  int hash = (((int) uid) >> 4) & (HTableSize - 1);
+  UIDnode *node = uidHTable[hash];
+  if (node && node->uid == uid)
+    return node;
+  int lt = 0;
+  int rt = uidnodes->size () - 1;
+  while (lt <= rt)
+    {
+      int md = (lt + rt) / 2;
+      node = uidnodes->fetch (md);
+      if (node->uid < uid)
+       lt = md + 1;
+      else if (node->uid > uid)
+       rt = md - 1;
+      else
+       {
+         uidHTable[hash] = node;
+         return node;
+       }
+    }
+  return NULL;
+}
+
+int
+Experiment::frUidCmp (const void *a, const void *b)
+{
+  RawFramePacket *fp1 = *(RawFramePacket**) a;
+  RawFramePacket *fp2 = *(RawFramePacket**) b;
+  if (fp1->uid == fp2->uid)
+    return 0;
+  return fp1->uid < fp2->uid ? -1 : 1;
+}
+
+Experiment::RawFramePacket *
+Experiment::find_frame_packet (uint64_t uid)
+{
+  int lt = 0;
+  int rt = frmpckts->size () - 1;
+  while (lt <= rt)
+    {
+      int md = (lt + rt) / 2;
+      RawFramePacket *fp = frmpckts->fetch (md);
+      if (fp->uid < uid)
+       lt = md + 1;
+      else if (fp->uid > uid)
+       rt = md - 1;
+      else
+       return fp;
+    }
+
+  return NULL;
+}
+
+#define FRINFO_CACHEOPT_SIZE_LIMIT  4000000
+#define FRINFO_PIPELINE_SIZE_LIMIT  500000
+#define FRINFO_PIPELINE_NUM_STAGES  3
+
+// Pipelined execution of resolve_frame_info() and add_stack().
+// Since this is the largest time consuming part of loading an experiment (especially
+// so for large java experiments) - executing this part as a 3 stage pipeline can
+// give significant performance gain - and this concept can be aggressively applied
+// to enhance the gain further in future. The three stages are:
+// Phase 1:  resolve_frame_info()
+// Phase 2:  first part of add_stack() where the native stack is built
+// Phase 3:  second part og add_stack() where the java stack is built
+// Phase 4:   insert the native and java stacks into the stack map
+// The main thread operates in the first Phase and the other stages are
+// operated by a ssplib sequential queue - The threads working on the queues run concurrently
+// with each other and with the main thread. But within a particular queue, jobs are
+// executed sequentially
+
+
+// This is the second phase of the pipeline of resolve_frame_info and add_stack
+//  It works on a chunk of iterations (size CSTCTX_CHUNK_SZ) and invokes add_stack()
+// for each one of them
+
+void
+Experiment::resolve_frame_info (DataDescriptor *dDscr)
+{
+  if (!resolveFrameInfo)
+    return;
+  if (NULL == cstack)
+    return;
+  dDscr->setResolveFrInfoDone ();
+
+  // Check for TSTAMP
+  int propID = dbeSession->getPropIdByName (NTXT ("TSTAMP"));
+  Data *dataTStamp = dDscr->getData (propID);
+  if (dataTStamp == NULL)
+    return;
+
+  propID = dbeSession->getPropIdByName (NTXT ("FRINFO"));
+  Data *dataFrinfo = dDscr->getData (propID);
+
+  propID = dbeSession->getPropIdByName (NTXT ("THRID"));
+  Data *dataThrId = dDscr->getData (propID);
+
+  // We can get frame info either by FRINFO or by [THRID,STKIDX]
+  if (dataFrinfo == NULL)
+    return;
+
+  char *propName = NTXT ("MSTACK");
+  propID = dbeSession->getPropIdByName (propName);
+  PropDescr *prMStack = new PropDescr (propID, propName);
+  prMStack->uname = dbe_strdup (GTXT ("Machine Call Stack"));
+  prMStack->vtype = TYPE_OBJ;
+  dDscr->addProperty (prMStack);
+
+  propName = NTXT ("USTACK");
+  propID = dbeSession->getPropIdByName (propName);
+  PropDescr *prUStack = new PropDescr (propID, propName);
+  prUStack->uname = dbe_strdup (GTXT ("User Call Stack"));
+  prUStack->vtype = TYPE_OBJ;
+  dDscr->addProperty (prUStack);
+
+  propName = NTXT ("XSTACK");
+  propID = dbeSession->getPropIdByName (propName);
+  PropDescr *prXStack = new PropDescr (propID, propName);
+  prXStack->uname = dbe_strdup (GTXT ("Expert Call Stack"));
+  prXStack->vtype = TYPE_OBJ;
+  dDscr->addProperty (prXStack);
+
+  propName = NTXT ("HSTACK");
+  propID = dbeSession->getPropIdByName (propName);
+  PropDescr *prHStack = new PropDescr (propID, propName);
+  prHStack->uname = dbe_strdup (GTXT ("ShowHide Call Stack"));
+  prHStack->vtype = TYPE_OBJ;
+  dDscr->addProperty (prHStack);
+
+  if (has_java)
+    {
+      propName = NTXT ("JTHREAD");
+      propID = dbeSession->getPropIdByName (propName);
+      PropDescr *prJThread = new PropDescr (propID, propName);
+      prJThread->uname = dbe_strdup (GTXT ("Java Thread"));
+      prJThread->vtype = TYPE_OBJ;
+      dDscr->addProperty (prJThread);
+    }
+
+  if (ompavail)
+    {
+      PropDescr *prop = new PropDescr (PROP_OMPSTATE, NTXT ("OMPSTATE"));
+      prop->uname = dbe_strdup (GTXT ("OpenMP state"));
+      prop->vtype = TYPE_UINT32;
+      char * stateNames [OMP_LAST_STATE] = OMP_THR_STATE_STRINGS;
+      char * stateUNames[OMP_LAST_STATE] = OMP_THR_STATE_USTRINGS;
+      for (int ii = 0; ii < OMP_LAST_STATE; ii++)
+       prop->addState (ii, stateNames[ii], stateUNames[ii]);
+      dDscr->addProperty (prop);
+
+      // add PROP_CPRID to profiling data (not same as omptrace's PROP_CPRID)
+      prop = dDscr->getProp (PROP_CPRID);
+      if (prop)
+       {
+         VType_type type = prop->vtype;
+         assert (type == TYPE_OBJ); //see 7040526
+       }
+      prop = new PropDescr (PROP_CPRID, NTXT ("CPRID")); //profiling PROP_CPRID
+      prop->uname = dbe_strdup (GTXT ("OpenMP parallel region"));
+      prop->vtype = TYPE_OBJ;
+      dDscr->addProperty (prop);
+
+      // add PROP_TSKID to profiling data (not same as omptrace's PROP_TSKID)
+      prop = dDscr->getProp (PROP_TSKID);
+      if (prop)
+       {
+         VType_type type = prop->vtype;
+         assert (type == TYPE_OBJ); //see 7040526
+       }
+      prop = new PropDescr (PROP_TSKID, NTXT ("TSKID")); //profiling PROP_TSKID
+      prop->uname = dbe_strdup (GTXT ("OpenMP task"));
+      prop->vtype = TYPE_OBJ;
+      dDscr->addProperty (prop);
+    }
+  char *progress_bar_msg = dbe_sprintf (NTXT ("%s %s: %s"), NTXT ("  "),
+                                       GTXT ("Processing CallStack Data"),
+                                       get_basename (expt_name));
+  int progress_bar_percent = -1;
+  long deltaReport = 5000;
+  long nextReport = 0;
+
+  long size = dDscr->getSize ();
+  //    bool resolve_frinfo_pipelined = size > FRINFO_PIPELINE_SIZE_LIMIT && !ompavail;
+  bool resolve_frinfo_pipelined = false;
+
+  Map<uint64_t, uint64_t> *nodeCache = NULL;
+  Map<uint64_t, uint64_t> *frameInfoCache = NULL;
+  if (size > FRINFO_CACHEOPT_SIZE_LIMIT && dversion == NULL)
+    {
+      frameInfoCache = new CacheMap<uint64_t, uint64_t>;
+      nodeCache = new CacheMap<uint64_t, uint64_t>;
+    }
+
+  pushCnt = popCnt = pushCnt3 = popCnt3 = 0;
+  nPush = nPop = 0;
+
+  FramePacket *fp = NULL;
+  //    DbeThreadPool * threadPool = new DbeThreadPool(5);
+  fp = new FramePacket;
+  fp->stack = new Vector<Vaddr>;
+  fp->jstack = new Vector<Vaddr>;
+  fp->ompstack = new Vector<Vaddr>;
+  fp->omp_state = 0;
+  fp->mpi_state = 0;
+
+  // piggyback on post-processing to calculate exp->last_event
+  const hrtime_t _exp_start_time = getStartTime (); // wall clock time
+  hrtime_t exp_duration = getLastEvent () == ZERO_TIME ? 0
+         : getLastEvent () - _exp_start_time; // zero-based
+
+  int missed_fi = 0;
+  int total_fi = 0;
+
+  for (long i = 0; i < size; i++)
+    {
+      if (i == nextReport)
+       {
+         int percent = (int) (i * 100 / size);
+         if (percent > progress_bar_percent)
+           {
+             progress_bar_percent += 10;
+             theApplication->set_progress (percent, progress_bar_msg);
+           }
+         nextReport += deltaReport;
+       }
+
+      uint32_t thrid = (uint32_t) dataThrId->fetchInt (i);
+      hrtime_t tstamp = (hrtime_t) dataTStamp->fetchLong (i);
+
+      // piggyback on post-processing to calculate exp->last_event
+      {
+       hrtime_t relative_timestamp = tstamp - _exp_start_time;
+       if (exp_duration < relative_timestamp)
+         exp_duration = relative_timestamp;
+      }
+      uint64_t frinfo = (uint64_t) dataFrinfo->fetchLong (i);
+
+      RawFramePacket *rfp = NULL;
+      if (frinfo)
+       {
+         // CacheMap does not work with NULL key
+         if (frameInfoCache != NULL)
+           rfp = (RawFramePacket *) frameInfoCache->get (frinfo);
+       }
+      if (rfp == 0)
+       {
+         rfp = find_frame_packet (frinfo);
+         if (rfp != 0)
+           {
+             if (frameInfoCache != NULL)
+               frameInfoCache->put (frinfo, (uint64_t) rfp);
+           }
+         else
+           missed_fi++;
+         total_fi++;
+       }
+
+      // Process OpenMP properties
+      if (ompavail)
+       {
+         fp->omp_state = rfp ? rfp->omp_state : 0;
+         dDscr->setValue (PROP_OMPSTATE, i, fp->omp_state);
+
+         fp->omp_cprid = mapPRid->get (thrid, tstamp, mapPRid->REL_EQLE);
+         void *omp_preg = mapPReg->get (thrid, tstamp, mapPReg->REL_EQLE);
+         if (!omp_preg)
+           {
+             char *idxname = NTXT ("OMP_preg");
+             int idxtype = dbeSession->findIndexSpaceByName (idxname);
+             if (idxtype != -1)
+               {
+                 Histable *preg0 = dbeSession->findObjectById (Histable::INDEXOBJ, idxtype, (int64_t) 0);
+                 if (preg0)
+                   {
+                     Vector<Histable*> pregs;
+                     pregs.append (preg0);
+                     omp_preg = cstack->add_stack (&pregs);
+                     mapPReg->put (thrid, tstamp, omp_preg);
+                   }
+               }
+           }
+         dDscr->setObjValue (PROP_CPRID, i, omp_preg); //profiling PROP_CPRID
+         void *omp_task = mapTask->get (thrid, tstamp, mapTask->REL_EQLE);
+         if (!omp_task)
+           {
+             char *idxname = NTXT ("OMP_task");
+             int idxtype = dbeSession->findIndexSpaceByName (idxname);
+             if (idxtype != -1)
+               {
+                 Histable *task0 = dbeSession->findObjectById (Histable::INDEXOBJ, idxtype, (int64_t) 0);
+                 if (task0)
+                   {
+                     Vector<Histable*> tasks;
+                     tasks.append (task0);
+                     omp_task = cstack->add_stack (&tasks);
+                     mapTask->put (thrid, tstamp, omp_task);
+                   }
+               }
+           }
+         dDscr->setObjValue (PROP_TSKID, i, omp_task); //profiling PROP_TSKID
+       }
+      else
+       {
+         fp->omp_state = 0;
+         fp->omp_cprid = 0;
+       }
+
+      // Construct the native stack
+      fp->stack->reset ();
+      Vaddr leafpc = dDscr->getULongValue (PROP_LEAFPC, i);
+      if (leafpc)
+       fp->stack->append (leafpc);
+      UIDnode *node = rfp ? rfp->uidn : NULL;
+      while (node)
+       {
+         if (node->next == node)
+           // this node contains link_uid
+           node = find_uid_node (node->uid);
+         else
+           {
+             fp->stack->append (node->val);
+             node = node->next;
+           }
+       }
+      fp->truncated = 0;
+      int last = fp->stack->size () - 1;
+      if (last >= 0)
+       {
+         switch (fp->stack->fetch (last))
+           {
+           case SP_TRUNC_STACK_MARKER:
+             fp->truncated = (Vaddr) SP_TRUNC_STACK_MARKER;
+             fp->stack->remove (last);
+             break;
+           case SP_FAILED_UNWIND_MARKER:
+             fp->truncated = (Vaddr) SP_FAILED_UNWIND_MARKER;
+             fp->stack->remove (last);
+             break;
+           }
+       }
+
+      // Construct the Java stack
+      fp->jstack->reset ();
+      node = rfp ? rfp->uidj : NULL;
+      while (node)
+       {
+         if (node->next == node)
+           {
+             // this node contains link_uid
+             UIDnode *n = NULL;
+             if (node->uid)
+               {
+                 // CacheMap does not work with NULL key
+                 if (nodeCache != NULL)
+                   n = (UIDnode *) nodeCache->get (node->uid);
+               }
+             if (n == NULL)
+               {
+                 n = find_uid_node (node->uid);
+                 if (n != NULL)
+                   {
+                     if (nodeCache != NULL)
+                       nodeCache->put (node->uid, (uint64_t) n);
+                   }
+               }
+             node = n;
+           }
+         else
+           {
+             fp->jstack->append (node->val);
+             node = node->next;
+           }
+       }
+      fp->jtruncated = false;
+      last = fp->jstack->size () - 1;
+      if (last >= 1 && fp->jstack->fetch (last) == SP_TRUNC_STACK_MARKER)
+       {
+         fp->jtruncated = true;
+         fp->jstack->remove (last);
+         fp->jstack->remove (last - 1);
+       }
+
+      // Construct the OpenMP stack
+      if (ompavail)
+       {
+         fp->ompstack->reset ();
+         if (rfp && rfp->omp_uid)
+           {
+             if (leafpc)
+               fp->ompstack->append (leafpc);
+             node = rfp->omp_uid;
+             while (node)
+               {
+                 if (node->next == node)
+                   // this node contains link_uid
+                   node = find_uid_node (node->uid);
+                 else
+                   {
+                     fp->ompstack->append (node->val);
+                     node = node->next;
+                   }
+               }
+             fp->omptruncated = false;
+             last = fp->ompstack->size () - 1;
+             if (last >= 0)
+               {
+                 switch (fp->ompstack->fetch (last))
+                   {
+                   case SP_TRUNC_STACK_MARKER:
+                     fp->omptruncated = (Vaddr) SP_TRUNC_STACK_MARKER;
+                     fp->ompstack->remove (last);
+                     break;
+                   case SP_FAILED_UNWIND_MARKER:
+                     fp->omptruncated = (Vaddr) SP_FAILED_UNWIND_MARKER;
+                     fp->ompstack->remove (last);
+                     break;
+                   }
+               }
+           }
+       }
+      cstack->add_stack (dDscr, i, fp, NULL);
+    }
+
+  // piggyback on post-processing to calculate exp->last_event
+  {
+    hrtime_t exp_end_time = _exp_start_time + exp_duration;
+    update_last_event (exp_end_time);
+  }
+
+  if (missed_fi > 0)
+    {
+      StringBuilder sb;
+      sb.sprintf (
+                 GTXT ("*** Warning: %d frameinfo packets are missing from total of %d when resolving %s."),
+                 missed_fi, total_fi, dDscr->getName ());
+      warnq->append (new Emsg (CMSG_WARN, sb));
+    }
+
+  //    threadPool->wait_group();
+  //    delete threadPool;
+  theApplication->set_progress (0, NTXT (""));
+  free (progress_bar_msg);
+  if (!resolve_frinfo_pipelined && fp != NULL)
+    {
+      delete fp->ompstack;
+      delete fp->jstack;
+      delete fp->stack;
+      delete fp;
+    }
+  delete frameInfoCache;
+  frameInfoCache = NULL;
+  delete nodeCache;
+  nodeCache = NULL;
+}
+
+void
+Experiment::post_process ()
+{
+  // update non_paused_time after final update to "last_event"
+  if (resume_ts != MAX_TIME && last_event)
+    {
+      hrtime_t ts = last_event - exp_start_time;
+      hrtime_t delta = ts - resume_ts;
+      non_paused_time += delta;
+      resume_ts = MAX_TIME; // collection is paused
+    }
+
+  // GC: prune events outside of experiment duration, calculate GC duration, update indices
+  int index;
+  GCEvent * gcevent;
+  gc_duration = ZERO_TIME;
+  if (gcevents != NULL)
+    {
+      // delete events that finish before exp_start_time or start after last_event
+      for (int ii = 0; ii < gcevents->size ();)
+       {
+         gcevent = gcevents->fetch (ii);
+         if (gcevent->end - exp_start_time < 0
+             || last_event - gcevent->start < 0)
+           delete gcevents->remove (ii);
+         else
+           ii++;
+       }
+    }
+  Vec_loop (GCEvent*, gcevents, index, gcevent)
+  {
+    gcevent->id = index + 1; // renumber to account for any deleted events
+    if (gcevent->start - exp_start_time < 0 || gcevent->start == ZERO_TIME)
+      // truncate events that start before experiment start
+      gcevent->start = exp_start_time;
+    if (last_event - gcevent->end < 0)
+      // truncate events that end after experiment end
+      gcevent->end = last_event;
+    gc_duration += gcevent->end - gcevent->start;
+  }
+}
+
+Experiment::Exp_status
+Experiment::find_expdir (char *path)
+{
+  // This function checks that the experiment directory
+  // is of the proper form, and accessible
+  struct stat64 sbuf;
+
+  // Save the name
+  expt_name = dbe_strdup (path);
+
+  // Check that the name ends in .er
+  size_t i = strlen (path);
+  if (i > 0 && path[i - 1] == '/')
+    path[--i] = '\0';
+
+  if (i < 4 || strcmp (&path[i - 3], NTXT (".er")) != 0)
+    {
+      Emsg *m = new Emsg (CMSG_FATAL,
+                         GTXT ("*** Error: not a valid experiment name"));
+      errorq->append (m);
+      status = FAILURE;
+      return FAILURE;
+    }
+
+  // Check if new directory structure (i.e., no pointer file)
+  if (dbe_stat (path, &sbuf))
+    {
+      Emsg *m = new Emsg (CMSG_FATAL, GTXT ("*** Error: experiment not found"));
+      errorq->append (m);
+      status = FAILURE;
+      return FAILURE;
+    }
+  if (S_ISDIR (sbuf.st_mode) == 0)
+    {
+      // ignore pointer-file experiments
+      Emsg *m = new Emsg (CMSG_FATAL,
+                         GTXT ("*** Error: experiment was recorded with an earlier version, and can not be read"));
+      errorq->append (m);
+      obsolete = 1;
+      status = FAILURE;
+      return FAILURE;
+    }
+  return SUCCESS;
+}
+
+void
+Experiment::purge ()
+{
+  // This routine will purge all of the caches of releasable storage.
+  for (int i = 0; i < dataDscrs->size (); ++i)
+    {
+      DataDescriptor *dataDscr = dataDscrs->fetch (i);
+      if (dataDscr == NULL)
+       continue;
+      dataDscr->reset ();
+    }
+  delete cstack;
+  delete cstackShowHide;
+  cstack = CallStack::getInstance (this);
+  cstackShowHide = CallStack::getInstance (this);
+}
+
+void
+Experiment::resetShowHideStack ()
+{
+  delete cstackShowHide;
+  cstackShowHide = CallStack::getInstance (this);
+}
+
+#define GET_INT_VAL(v, s, len) \
+    for (v = len = 0; isdigit(*s); s++, len++) { v = v * 10 + (*s -'0'); }
+
+static int
+dir_name_cmp (const void *a, const void *b)
+{
+  char *s1 = *((char **) a);
+  char *s2 = *((char **) b);
+  while (*s1)
+    {
+      if (isdigit (*s1) && isdigit (*s2))
+       {
+         int v1, v2, len1, len2;
+         GET_INT_VAL (v1, s1, len1);
+         GET_INT_VAL (v2, s2, len2);
+         if (v1 != v2)
+           return v1 - v2;
+         if (len1 != len2)
+           return len2 - len1;
+         continue;
+       }
+      if (*s1 != *s2)
+       break;
+      s1++;
+      s2++;
+    }
+  return *s1 - *s2;
+}
+
+Vector<char*> *
+Experiment::get_descendants_names ()
+{
+  char *dir_name = get_expt_name ();
+  if (dir_name == NULL)
+    return NULL;
+  DIR *exp_dir = opendir (dir_name);
+  if (exp_dir == NULL)
+    return NULL;
+  Vector<char*> *exp_names = new Vector<char*>();
+  for (struct dirent *entry = readdir (exp_dir); entry;
+         entry = readdir (exp_dir))
+    {
+      if (entry->d_name[0] == '_' || strncmp (entry->d_name, "M_r", 3) == 0)
+       {
+         char *dpath = dbe_sprintf (NTXT ("%s/%s"), dir_name, entry->d_name);
+         struct stat64 sbuf;
+         if (dbe_stat (dpath, &sbuf) == 0 && S_ISDIR (sbuf.st_mode))
+           exp_names->append (dpath);
+         else
+           free (dpath);
+       }
+    }
+  closedir (exp_dir);
+  if (exp_names->size () == 0)
+    {
+      delete exp_names;
+      return NULL;
+    }
+  exp_names->sort (dir_name_cmp);
+  return exp_names;
+}
+
+bool
+Experiment::create_dir (char *dname)
+{
+  if (mkdir (dname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) == 0)
+    {
+      return true;
+    }
+  struct stat64 sbuf;
+  if (dbe_stat (dname, &sbuf) != 0 || S_ISDIR (sbuf.st_mode) == 0)
+    {
+      char *buf = dbe_sprintf (GTXT ("Unable to create directory `%s'\n"),
+                              dname);
+      errorq->append (new Emsg (CMSG_ERROR, buf));
+      free (buf);
+      return false;
+    }
+  return true;
+}
+
+char *
+Experiment::get_arch_name ()
+{
+  if (arch_name == NULL)
+    {
+      // Determine the master experiment directory.
+      // omazur: should do it in a less hacky way. XXXX
+      char *ptr = strstr_r (expt_name, DESCENDANT_EXPT_KEY);
+      ptr = ptr ? ptr + 3 : expt_name + strlen (expt_name);
+      arch_name = dbe_sprintf (NTXT ("%.*s/%s"), (int) (ptr - expt_name),
+                              expt_name, SP_ARCHIVES_DIR);
+    }
+  return arch_name;
+}
+
+char *
+Experiment::get_fndr_arch_name ()
+{
+  if (fndr_arch_name == NULL)
+    // Determine the founder experiment directory.
+    fndr_arch_name = dbe_strdup (get_arch_name ());
+  return fndr_arch_name;
+}
+
+enum
+{
+  HASH_NAME_LEN     = 11    // (64 / 6 + 1) = 11
+};
+
+static char *
+get_hash_string (char buf[HASH_NAME_LEN + 1], uint64_t hash)
+{
+  static const char *har =
+         "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
+  for (int i = 0; i < HASH_NAME_LEN; i++)
+    {
+      buf[i] = har[hash & 0x3f];
+      hash = hash >> 6;
+    }
+  buf[HASH_NAME_LEN] = 0;
+  return buf;
+}
+
+char *
+Experiment::getNameInArchive (const char *fname, bool archiveFile)
+{
+  char *aname = get_archived_name (fname, archiveFile);
+  char *ret = dbe_sprintf (NTXT ("%s/%s"), get_arch_name (), aname);
+  free (aname);
+  return ret;
+}
+
+#define MAX_ARCHIVE_FILENAME_LEN    (256 - HASH_NAME_LEN - 2)
+
+char *
+Experiment::get_archived_name (const char *fname, bool archiveFile)
+{
+  char *bname = get_basename (fname);
+
+  // dirname_hash:
+  char dirnameHash[HASH_NAME_LEN + 1];
+  // Treat "a.out" and "./a.out" equally
+  uint64_t hash = bname != fname ? crc64 (fname, bname - fname)
+                                : crc64 (NTXT ("./"), 2);
+  get_hash_string (dirnameHash, hash);
+
+  char *ret;
+  long bname_len = dbe_sstrlen (bname);
+  if (bname_len > MAX_ARCHIVE_FILENAME_LEN)
+    {
+      char basenameHash[HASH_NAME_LEN + 1];
+      hash = crc64 (bname, bname_len);
+      get_hash_string (basenameHash, hash);
+      ret = dbe_sprintf ("%.*s%c%s_%s",
+                        MAX_ARCHIVE_FILENAME_LEN - HASH_NAME_LEN - 1,
+                        bname, archiveFile ? '.' : '_',
+                        dirnameHash, basenameHash);
+    }
+  else
+    ret = dbe_sprintf ("%s%c%s", bname, archiveFile ? '.' : '_', dirnameHash);
+  return ret;
+}
+
+char *
+Experiment::checkFileInArchive (const char *fname, bool archiveFile)
+{
+  if (archiveMap)
+    {
+      char *aname = get_archived_name (fname, archiveFile);
+      DbeFile *df = archiveMap->get (aname);
+      free (aname);
+      if (df)
+       return strdup (df->get_location ());
+      return NULL;
+    }
+  if (founder_exp)
+    return founder_exp->checkFileInArchive (fname, archiveFile);
+  return NULL;
+}
+
+
+// Comparing SegMem
+
+static int
+SegMemCmp (const void *a, const void *b)
+{
+  SegMem *item1 = *((SegMem **) a);
+  SegMem *item2 = *((SegMem **) b);
+  return item1->unload_time > item2->unload_time ? 1 :
+        item1->unload_time == item2->unload_time ? 0 : -1;
+}
+
+SegMem*
+Experiment::update_ts_in_maps (Vaddr addr, hrtime_t ts)
+{
+  Vector<SegMem *> *segMems = (Vector<SegMem *> *) maps->values ();
+  if (!segMems->is_sorted ())
+    {
+      Dprintf (DEBUG_MAPS, NTXT ("update_ts_in_maps: segMems.size=%lld\n"), (long long) segMems->size ());
+      segMems->sort (SegMemCmp);
+    }
+  for (int i = 0, sz = segMems ? segMems->size () : 0; i < sz; i++)
+    {
+      SegMem *sm = segMems->fetch (i);
+      if (ts < sm->unload_time)
+       {
+         for (; i < sz; i++)
+           {
+             sm = segMems->fetch (i);
+             if ((addr >= sm->base) && (addr < sm->base + sm->size))
+               {
+                 Dprintf (DEBUG_MAPS,
+                          "update_ts_in_maps: old:%u.%09u -> %u.%09u addr=0x%08llx size=%lld\n",
+                          (unsigned) (sm->load_time / NANOSEC),
+                          (unsigned) (sm->load_time % NANOSEC),
+                          (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
+                          (unsigned long long) sm->base, (long long) sm->size);
+                 maps->remove (sm->base, sm->load_time);
+                 sm->load_time = ts;
+                 maps->insert (sm->base, ts, sm);
+                 return sm;
+               }
+           }
+       }
+    }
+  Dprintf (DEBUG_MAPS, "update_ts_in_maps: NOT FOUND %u.%09u addr=0x%08llx\n",
+          (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
+          (unsigned long long) addr);
+  return NULL;
+}
+
+DbeInstr*
+Experiment::map_Vaddr_to_PC (Vaddr addr, hrtime_t ts)
+{
+  // Look up in the hash table first
+  int hash = (((int) addr) >> 8) & (HTableSize - 1);
+  SegMem *si = smemHTable[hash];
+  if (si == NULL || addr < si->base || addr >= si->base + si->size
+      || ts < si->load_time || ts >= si->unload_time)
+    {
+      // Not in the hash table
+      si = (SegMem*) maps->locate (addr, ts);
+      if (si == NULL || addr < si->base || addr >= si->base + si->size
+         || ts < si->load_time || ts >= si->unload_time)
+       {
+         si = update_ts_in_maps (addr, ts);
+         if (si == NULL)
+           return dbeSession->get_Unknown_Function ()->find_dbeinstr (PCInvlFlag, addr);
+       }
+      smemHTable[hash] = si;
+    }
+
+  // Calculate the file offset of 'addr'
+  uint64_t f_offset = si->get_file_offset () + (addr - si->base);
+
+  DbeInstr *instr;
+  if (si->obj->get_type () == Histable::LOADOBJECT)
+    {
+      LoadObject *lo = (LoadObject*) si->obj;
+      lo->sync_read_stabs ();
+      instr = lo->find_dbeinstr (f_offset);
+    }
+  else
+    {
+      int hash2 = ((((int) addr) & 0xFFFC00) | (((int) f_offset) >> 2))
+             & (HTableSize - 1);
+      instr = instHTable[hash2];
+      if (instr == NULL || instr->func != si->obj || instr->addr != f_offset)
+       {
+         // Not in the hash table
+         Function *fp = (Function *) si->obj;
+         instr = fp->find_dbeinstr (0, f_offset);
+         instHTable[hash2] = instr;
+       }
+    }
+  if (!instr->func->isUsed)
+    {
+      instr->func->isUsed = true;
+      instr->func->module->isUsed = true;
+      instr->func->module->loadobject->isUsed = true;
+    }
+  return instr;
+}
+
+Sample *
+Experiment::map_event_to_Sample (hrtime_t ts)
+{
+  Sample *sample;
+  int index;
+
+  // Check if the last used sample is the right one,
+  // if not then find it.
+  if (sample_last_used && ts >= sample_last_used->start_time
+      && ts <= sample_last_used->end_time)
+    return sample_last_used;
+
+  Vec_loop (Sample*, samples, index, sample)
+  {
+    if ((ts >= sample->start_time) &&
+       (ts <= sample->end_time))
+      {
+       sample_last_used = sample;
+       return sample;
+      }
+  }
+  return (Sample*) NULL;
+}
+
+GCEvent *
+Experiment::map_event_to_GCEvent (hrtime_t ts)
+{
+  GCEvent *gcevent;
+  int index;
+
+  // Check if the last used sample is the right one,
+  // if not then find it.
+  if (gcevent_last_used && ts >= gcevent_last_used->start
+      && ts <= gcevent_last_used->end)
+    return gcevent_last_used;
+  Vec_loop (GCEvent*, gcevents, index, gcevent)
+  {
+    if ((ts >= gcevent->start) &&
+       (ts <= gcevent->end))
+      {
+       gcevent_last_used = gcevent;
+       return gcevent;
+      }
+  }
+  return (GCEvent*) NULL;
+}
+
+DbeInstr*
+Experiment::map_jmid_to_PC (Vaddr mid, int bci, hrtime_t ts)
+{
+  if (mid == 0 || jmaps == NULL)
+    // special case: no Java stack was recorded, bci - error code
+    return dbeSession->get_JUnknown_Function ()->find_dbeinstr (0, bci);
+
+  JMethod *jmthd = jmidHTable->get (mid);
+  if (jmthd == NULL)
+    {
+      jmthd = (JMethod *) jmaps->locate_exact_match (mid, ts);
+      if (jmthd)
+       jmidHTable->put (mid, jmthd);
+    }
+  if (jmthd == NULL || jmthd->get_type () != Histable::FUNCTION)
+    return dbeSession->get_JUnknown_Function ()->find_dbeinstr (0, (uint64_t) mid);
+  return jmthd->find_dbeinstr (0, bci);
+}
+
+Emsg *
+Experiment::fetch_comments ()
+{
+  return commentq->fetch ();
+}
+
+Emsg *
+Experiment::fetch_runlogq ()
+{
+  return runlogq->fetch ();
+}
+
+Emsg *
+Experiment::fetch_errors ()
+{
+  return errorq->fetch ();
+}
+
+Emsg *
+Experiment::fetch_warnings ()
+{
+  return warnq->fetch ();
+}
+
+Emsg *
+Experiment::fetch_notes ()
+{
+  return notesq->fetch ();
+}
+
+Emsg *
+Experiment::fetch_ifreq ()
+{
+  return ifreqq->fetch ();
+}
+
+Emsg *
+Experiment::fetch_pprocq ()
+{
+  return pprocq->fetch ();
+}
+
+int
+Experiment::read_dyntext_file ()
+{
+  char *data_file_name = dbe_sprintf ("%s/%s", expt_name, SP_DYNTEXT_FILE);
+  Data_window *dwin = new Data_window (data_file_name);
+  if (dwin->not_opened ())
+    {
+      free (data_file_name);
+      delete dwin;
+      return 1;
+    }
+  dwin->need_swap_endian = need_swap_endian;
+
+  Function *fp = NULL;
+  char *progress_msg = NULL; // Message for the progress bar
+  for (int64_t offset = 0;;)
+    {
+      DT_common *cpckt = (DT_common *) dwin->bind (offset, sizeof (DT_common));
+      if (cpckt == NULL)
+       break;
+      size_t cpcktsize = dwin->decode (cpckt->size);
+      cpckt = (DT_common *) dwin->bind (offset, cpcktsize);
+      if (cpckt == NULL)
+       break;
+      switch (dwin->decode (cpckt->type))
+       {
+       case DT_HEADER:
+         {
+           DT_header *hdr = (DT_header*) cpckt;
+           hrtime_t ts = dwin->decode (hdr->time) + exp_start_time;
+           SegMem *si = (SegMem*) maps->locate (dwin->decode (hdr->vaddr), ts);
+           fp = si ? (Function *) si->obj : NULL;
+           if (fp && (fp->get_type () != Histable::FUNCTION
+                      || !(fp->flags & FUNC_FLAG_DYNAMIC)))
+             fp = NULL;
+           break;
+         }
+       case DT_CODE:
+         if (fp)
+           {
+             fp->img_fname = data_file_name;
+             fp->img_offset = offset + sizeof (DT_common);
+             if ((platform != Intel) && (platform != Amd64))
+               { //ARCH(SPARC)
+                 // Find out 'save' instruction address for SPARC
+                 char *ptr = ((char*) cpckt) + sizeof (DT_common);
+                 size_t img_size = cpcktsize - sizeof (DT_common);
+                 for (size_t i = 0; i < img_size; i += 4)
+                   if (ptr[i] == (char) 0x9d && ptr[i + 1] == (char) 0xe3)
+                     {
+                       fp->save_addr = i;
+                       break;
+                     }
+               }
+           }
+         break;
+       case DT_SRCFILE:
+         if (fp)
+           {
+             char *srcname = dbe_strndup (((char*) cpckt) + sizeof (DT_common),
+                                          cpcktsize - sizeof (DT_common));
+             LoadObject *ds = fp->module ? fp->module->loadobject : NULL;
+             assert (ds != NULL);
+             Module *mod = dbeSession->createModule (ds, NULL);
+             mod->set_file_name (srcname);
+             //}
+             if (fp->module)
+               {
+                 // It's most likely (unknown). Remove fp from it.
+                 long idx = fp->module->functions->find (fp);
+                 if (idx >= 0)
+                   fp->module->functions->remove (idx);
+               }
+             fp->module = mod;
+             mod->functions->append (fp);
+           }
+         break;
+       case DT_LTABLE:
+         if (fp)
+           {
+             DT_lineno *ltab = (DT_lineno*) ((char*) cpckt + sizeof (DT_common));
+             size_t sz = (cpcktsize - sizeof (DT_common)) / sizeof (DT_lineno);
+             if (sz <= 0)
+               break;
+             // Take care of the progress bar
+             static int percent = 0;
+             static long deltaReport = sz / 100; // 1000;
+             static long nextReport = 0;
+             static long progress_count = 0;
+             fp->pushSrcFile (fp->getDefSrc (), 0);
+             for (size_t i = 0; i < sz; i++)
+               {
+                 int lineno = dwin->decode (ltab[i].lineno);
+                 if (fp->usrfunc != NULL)
+                   {
+                     // Update progress bar
+                     if (dbeSession->is_interactive ())
+                       {
+                         if (progress_count == nextReport)
+                           {
+                             if (percent < 99)
+                               {
+                                 percent++;
+                                 if (NULL == progress_msg)
+                                   {
+                                     progress_msg = dbe_sprintf (GTXT ("Processing Dynamic Text: %s"),
+                                                                 get_basename (expt_name));
+                                   }
+                                 theApplication->set_progress (percent, progress_msg);
+                                 nextReport += deltaReport;
+                               }
+                           }
+                         progress_count++;
+                       }
+                     DbeLine *dbeline = fp->usrfunc->mapPCtoLine (lineno, NULL);
+                     lineno = dbeline != NULL ? dbeline->lineno : -1;
+                   }
+                 fp->add_PC_info (dwin->decode (ltab[i].offset), lineno);
+               }
+             fp->popSrcFile ();
+           }
+         break;
+       default:
+         // skip unknown records
+         break;
+       }
+      offset += cpcktsize;
+    }
+  free (progress_msg);
+  free (data_file_name);
+  delete dwin;
+  return 0;
+}
+
+uint32_t
+Experiment::mapTagValue (Prop_type prop, uint64_t value)
+{
+  Vector<Histable*> *objs = tagObjs->fetch (prop);
+  int lt = 0;
+  int rt = objs->size () - 1;
+  while (lt <= rt)
+    {
+      int md = (lt + rt) / 2;
+      Other *obj = (Other*) objs->fetch (md);
+      if (obj->value64 < value)
+       lt = md + 1;
+      else if (obj->value64 > value)
+       rt = md - 1;
+      else
+       return obj->tag;
+    }
+
+  uint32_t tag;
+  if (sparse_threads && (prop == PROP_THRID || prop == PROP_LWPID))
+    tag = objs->size () + 1; // "+ 1" related to 7038295
+  else
+    tag = (int) value; // truncation; See 6788767
+
+  Other *obj = new Other ();
+  obj->value64 = value;
+  obj->tag = tag;
+  if (lt == objs->size ())
+    objs->append (obj);
+  else
+    objs->insert (lt, obj);
+
+  // Update min and max tags
+  if (prop == PROP_LWPID)
+    {
+      if ((uint64_t) tag < min_lwp)
+       min_lwp = (uint64_t) tag;
+      if ((uint64_t) tag > max_lwp)
+       max_lwp = (uint64_t) tag;
+      lwp_cnt++;
+    }
+  else if (prop == PROP_THRID)
+    {
+      if ((uint64_t) tag < min_thread)
+       min_thread = (uint64_t) tag;
+      if ((uint64_t) tag > max_thread)
+       max_thread = (uint64_t) tag;
+      thread_cnt++;
+    }
+  else if (prop == PROP_CPUID)
+    {
+      // On Solaris 8, we don't get CPU id -- don't change
+      if (value != (uint64_t) - 1)
+       {//YXXX is this related only to solaris 8?
+         if ((uint64_t) tag < min_cpu)
+           min_cpu = (uint64_t) tag;
+         if ((uint64_t) tag > max_cpu)
+           max_cpu = (uint64_t) tag;
+       }
+      cpu_cnt++;
+    }
+  return obj->tag;
+}
+
+Vector<Histable*> *
+Experiment::getTagObjs (Prop_type prop)
+{
+  return tagObjs->fetch (prop);
+}
+
+Histable *
+Experiment::getTagObj (Prop_type prop, uint32_t tag)
+{
+  Vector<Histable*> *objs = tagObjs->fetch (prop);
+  if (objs == NULL)
+    return NULL;
+  for (int i = 0; i < objs->size (); i++)
+    {
+      Other *obj = (Other*) objs->fetch (i);
+      if (obj->tag == tag)
+       return obj;
+    }
+  return NULL;
+}
+
+JThread *
+Experiment::map_pckt_to_Jthread (uint32_t tid, hrtime_t tstamp)
+{
+  if (!has_java)
+    return JTHREAD_DEFAULT;
+  int lt = 0;
+  int rt = jthreads_idx->size () - 1;
+  while (lt <= rt)
+    {
+      int md = (lt + rt) / 2;
+      JThread *jthread = jthreads_idx->fetch (md);
+      if (jthread->tid < tid)
+       lt = md + 1;
+      else if (jthread->tid > tid)
+       rt = md - 1;
+      else
+       {
+         for (; jthread; jthread = jthread->next)
+           if (tstamp >= jthread->start && tstamp < jthread->end)
+             return jthread;
+         break;
+       }
+    }
+
+  return JTHREAD_NONE;
+}
+
+JThread*
+Experiment::get_jthread (uint32_t tid)
+{
+  if (!has_java)
+    return JTHREAD_DEFAULT;
+  int lt = 0;
+  int rt = jthreads_idx->size () - 1;
+  while (lt <= rt)
+    {
+      int md = (lt + rt) / 2;
+      JThread *jthread = jthreads_idx->fetch (md);
+      if (jthread->tid < tid)
+       lt = md + 1;
+      else if (jthread->tid > tid)
+       rt = md - 1;
+      else
+       {
+         JThread *jthread_first = jthread;
+         while ((jthread = jthread->next) != NULL)
+           if (!jthread->is_system () &&
+               jthread->jthr_id < jthread_first->jthr_id)
+             jthread_first = jthread;
+         return jthread_first;
+       }
+    }
+
+  return JTHREAD_NONE;
+}
+
+// SS12 experiment
+DataDescriptor *
+Experiment::newDataDescriptor (int data_id, int flags,
+                              DataDescriptor *master_dDscr)
+{
+  DataDescriptor *dataDscr = NULL;
+  if (data_id >= 0 && data_id < dataDscrs->size ())
+    {
+      dataDscr = dataDscrs->fetch (data_id);
+      if (dataDscr != NULL)
+       return dataDscr;
+    }
+
+  assert (data_id >= 0 && data_id < DATA_LAST);
+  const char *nm = get_prof_data_type_name (data_id);
+  const char *uname = get_prof_data_type_uname (data_id);
+
+  if (master_dDscr)
+    dataDscr = new DataDescriptor (data_id, nm, uname, master_dDscr);
+  else
+    dataDscr = new DataDescriptor (data_id, nm, uname, flags);
+  dataDscrs->store (data_id, dataDscr);
+  return dataDscr;
+}
+
+Vector<DataDescriptor*> *
+Experiment::getDataDescriptors ()
+{
+  Vector<DataDescriptor*> *result = new Vector<DataDescriptor*>;
+  for (int i = 0; i < dataDscrs->size (); ++i)
+    {
+      DataDescriptor *dd;
+      dd = get_raw_events (i); // force data fetch
+      if (dd != NULL)
+       result->append (dd);
+    }
+  return result;
+}
+
+DataDescriptor *
+Experiment::getDataDescriptor (int data_id)
+{
+  if (data_id < 0 || data_id >= dataDscrs->size ())
+    return NULL;
+  return dataDscrs->fetch (data_id);
+}
+
+PacketDescriptor *
+Experiment::newPacketDescriptor (int kind, DataDescriptor *dDscr)
+{
+  PacketDescriptor *pDscr = new PacketDescriptor (dDscr);
+  pcktDscrs->store (kind, pDscr);
+  return pDscr;
+}
+
+PacketDescriptor *
+Experiment::getPacketDescriptor (int kind)
+{
+  if (kind < 0 || kind >= pcktDscrs->size ())
+    return NULL;
+  return pcktDscrs->fetch (kind);
+}
+
+void
+Experiment::set_clock (int clk)
+{
+  if (clk > 0)
+    {
+      if (maxclock < clk)
+       {
+         maxclock = clk;
+         clock = maxclock;
+       }
+      if (minclock == 0 || minclock > clk)
+       minclock = clk;
+    }
+}
+
+bool
+JThread::is_system ()
+{
+  if (group_name == NULL)
+    return false;
+  return strcmp (group_name, NTXT ("system")) == 0;
+}
+
+void
+Experiment::dump_stacks (FILE *outfile)
+{
+  cstack->print (outfile);
+}
+
+void
+Experiment::dump_map (FILE *outfile)
+{
+  int index;
+  SegMem *s;
+  fprintf (outfile, GTXT ("Experiment %s\n"), get_expt_name ());
+  fprintf (outfile, GTXT ("Address         Size (hex)              Load time     Unload time    Checksum  Name\n"));
+  Vec_loop (SegMem*, seg_items, index, s)
+  {
+    timestruc_t load;
+    timestruc_t unload;
+    hr2timestruc (&load, (s->load_time - exp_start_time));
+    if (load.tv_nsec < 0)
+      {
+       load.tv_sec--;
+       load.tv_nsec += NANOSEC;
+      }
+    if (s->unload_time == MAX_TIME)
+      {
+       unload.tv_sec = 0;
+       unload.tv_nsec = 0;
+      }
+    else
+      hr2timestruc (&unload, (s->unload_time - exp_start_time));
+    if (load.tv_nsec < 0)
+      {
+       load.tv_sec--;
+       load.tv_nsec += NANOSEC;
+      }
+    fprintf (outfile,
+            "0x%08llx  %8lld (0x%08llx) %5ld.%09ld %5ld.%09ld  \"%s\"\n",
+            s->base, s->size, s->size, load.tv_sec, load.tv_nsec,
+            unload.tv_sec, unload.tv_nsec, s->obj->get_name ());
+  }
+  fprintf (outfile, NTXT ("\n"));
+}
+
+/**
+ * Copy file to archive
+ * @param name
+ * @param aname
+ * @param hide_msg
+ * @return 0 - success, 1 - error
+ */
+int
+Experiment::copy_file_to_archive (const char *name, const char *aname, int hide_msg)
+{
+  errno = 0;
+  int fd_w = open64 (aname, O_WRONLY | O_CREAT | O_EXCL, 0644);
+  if (fd_w == -1)
+    {
+      if (errno == EEXIST)
+       return 0;
+      fprintf (stderr, GTXT ("er_archive: unable to copy `%s': %s\n"),
+              name, STR (strerror (errno)));
+      return 1;
+    }
+
+  if (dbe_stat_file (name, NULL) != 0)
+    {
+      fprintf (stderr, GTXT ("er_archive: cannot access file `%s': %s\n"),
+              name, STR (strerror (errno)));
+      close (fd_w);
+      return 1;
+    }
+
+  int fd_r = open64 (name, O_RDONLY);
+  if (fd_r == -1)
+    {
+      fprintf (stderr, GTXT ("er_archive: unable to open `%s': %s\n"),
+              name, strerror (errno));
+      close (fd_w);
+      unlink (aname);
+      return 1;
+    }
+
+  if (!hide_msg)
+    fprintf (stderr, GTXT ("Copying `%s'  to `%s'\n"), name, aname);
+  bool do_unlink = false;
+  for (;;)
+    {
+      unsigned char buf[65536];
+      int n, n1;
+      n = (int) read (fd_r, (void *) buf, sizeof (buf));
+      if (n <= 0)
+       break;
+      n1 = (int) write (fd_w, buf, n);
+      if (n != n1)
+       {
+         fprintf (stderr, GTXT ("er_archive: unable to write %d bytes to `%s': %s\n"),
+                  n, aname, STR (strerror (errno)));
+         do_unlink = true;
+         break;
+       }
+    }
+  close (fd_w);
+
+  struct stat64 s_buf;
+  if (fstat64 (fd_r, &s_buf) == 0)
+    {
+      struct utimbuf u_buf;
+      u_buf.actime = s_buf.st_atime;
+      u_buf.modtime = s_buf.st_mtime;
+      utime (aname, &u_buf);
+    }
+  close (fd_r);
+  if (do_unlink)
+    {
+      if (!hide_msg)
+       fprintf (stderr, GTXT ("er_archive: remove %s\n"), aname);
+      unlink (aname);
+      return 1;
+    }
+  return 0;
+}
+
+/**
+ * Copy file to common archive
+ * Algorithm:
+ * Calculate checksum
+ * Generate file name to be created in common archive
+ * Check if it is not in common archive yet
+ * Copy file to the common archive directory if it is not there yet
+ * Create symbolic link: "aname" -> "caname", where "caname" is the name in common archive
+ * @param name - original file name
+ * @param aname - file name in experiment archive
+ * @param common_archive - common archive directory
+ * @return 0 - success, 1 - error
+ */
+int
+Experiment::copy_file_to_common_archive (const char *name, const char *aname,
+                                        int hide_msg,
+                                        const char *common_archive,
+                                        int relative_path)
+{
+  if (!name || !aname || !common_archive)
+    {
+      if (!name)
+       fprintf (stderr, GTXT ("er_archive: Internal error: file name is NULL\n"));
+      if (!aname)
+       fprintf (stderr, GTXT ("er_archive: Internal error: file name in archive is NULL\n"));
+      if (!common_archive)
+       fprintf (stderr, GTXT ("er_archive: Internal error: path to common archive is NULL\n"));
+      return 1;
+    }
+  // Check if file is already archived
+  if (dbe_stat (aname, NULL) == 0)
+    return 0; // File is already archived
+  // Generate full path to common archive directory
+  char *cad = NULL;
+  char *abs_aname = NULL;
+  if ((common_archive[0] != '/') || (aname[0] != '/'))
+    {
+      long size = pathconf (NTXT ("."), _PC_PATH_MAX);
+      if (size < 0)
+       {
+         fprintf (stderr, GTXT ("er_archive: Fatal error: pathconf(\".\", _PC_PATH_MAX) failed\n"));
+         return 1;
+       }
+      char *buf = (char *) malloc ((size_t) size);
+      if (buf == NULL)
+       {
+         fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
+         return 1;
+       }
+      char *ptr = getcwd (buf, (size_t) size);
+      if (ptr == NULL)
+       {
+         fprintf (stderr, GTXT ("er_archive: Fatal error: cannot determine current directory\n"));
+         free (buf);
+         return 1;
+       }
+      if (common_archive[0] != '/')
+       cad = dbe_sprintf (NTXT ("%s/%s"), ptr, common_archive);
+      else
+       cad = dbe_strdup (common_archive);
+      if (aname[0] != '/')
+       abs_aname = dbe_sprintf (NTXT ("%s/%s"), ptr, aname);
+      else
+       abs_aname = dbe_strdup (aname);
+      free (buf);
+    }
+  else
+    {
+      cad = dbe_strdup (common_archive);
+      abs_aname = dbe_strdup (aname);
+    }
+  // Calculate checksum
+  char * errmsg = NULL;
+  uint32_t crcval = get_cksum (name, &errmsg);
+  if (0 == crcval)
+    { // error
+      free (cad);
+      free (abs_aname);
+      if (NULL != errmsg)
+       {
+         fprintf (stderr, GTXT ("er_archive: Fatal error: %s\n"), errmsg);
+         free (errmsg);
+         return 1;
+       }
+      fprintf (stderr,
+              GTXT ("er_archive: Fatal error: get_cksum(%s) returned %d\n"),
+              name, crcval);
+      return 1;
+    }
+  // Generate file name to be created in common archive
+  char *fname = get_basename (name);
+  char *abs_caname = dbe_sprintf (NTXT ("%s/%u_%s"), cad, crcval, fname);
+  if (abs_caname == NULL)
+    {
+      free (cad);
+      free (abs_aname);
+      fprintf (stderr,
+              GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
+      return 1;
+    }
+  // Check if full name is not too long
+  long len = dbe_sstrlen (abs_caname);
+  long max = pathconf (cad, _PC_PATH_MAX);
+  if ((max < 0) || (len <= 0))
+    { // unknown error
+      fprintf (stderr, GTXT ("er_archive: Fatal error: pathconf(%s, _PC_PATH_MAX) failed\n"),
+              cad);
+      free (abs_caname);
+      free (cad);
+      free (abs_aname);
+      return 1;
+    }
+  if (len >= max)
+    {
+      // Try to truncate the name
+      if ((len - max) <= dbe_sstrlen (fname))
+       {
+         // Yes, we can do it
+         abs_caname[max - 1] = 0;
+         if (!hide_msg)
+           fprintf (stderr, GTXT ("er_archive: file path is too long - truncated:%s\n"),
+                    abs_caname);
+       }
+    }
+  // Check if file name is not too long
+  char *cafname = get_basename (abs_caname);
+  len = dbe_sstrlen (cafname);
+  max = pathconf (cad, _PC_NAME_MAX);
+  if ((max < 0) || (len <= 0))
+    { // unknown error
+      fprintf (stderr, GTXT ("er_archive: Fatal error: pathconf(%s, _PC_NAME_MAX) failed\n"),
+              cad);
+      free (abs_caname);
+      free (cad);
+      free (abs_aname);
+      return 1;
+    }
+  if (len >= max)
+    {
+      // Try to truncate the name
+      if ((len - max) <= dbe_sstrlen (fname))
+       {
+         // Yes, we can do it
+         cafname[max - 1] = 0;
+         if (!hide_msg)
+           fprintf (stderr, GTXT ("er_archive: file name is too long - truncated:%s\n"),
+                    abs_caname);
+       }
+    }
+  // Copy file to the common archive directory if it is not there yet
+  int res = 0;
+  if (dbe_stat_file (abs_caname, NULL) != 0)
+    {
+      // Use temporary file to avoid synchronization problems
+      char *t = dbe_sprintf ("%s/archive_%llx", cad, (unsigned long long) gethrtime());
+      free (cad);
+      // Copy file to temporary file
+      res = copy_file_to_archive (name, t, hide_msg); // hide messages
+      if (res != 0)
+       {
+         fprintf (stderr, GTXT ("er_archive: Fatal error: cannot copy file %s to temporary file: %s\n"),
+                  name, t);
+         unlink (t);
+         free (t);
+         free (abs_caname);
+         free (abs_aname);
+         return 1;
+       }
+      // Set read-only permissions
+      struct stat64 statbuf;
+      if (0 == dbe_stat_file (name, &statbuf))
+       {
+         mode_t mask = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+         mode_t mode = statbuf.st_mode & mask;
+         chmod (t, mode);
+       }
+      // Try to rename temporary file "t" to "abs_caname"
+      // res = link(t, abs_caname); // link() fails on some f/s - use rename()
+      res = rename (t, abs_caname);
+      if (res != 0)
+       {
+         if (errno != EEXIST)
+           {
+             fprintf (stderr, GTXT ("er_archive: Fatal error: rename(%s, %s) returned error: %d\n"),
+                      t, abs_caname, res);
+             unlink (t);
+             free (t);
+             free (abs_caname);
+             free (abs_aname);
+             return 1;
+           }
+         // File "abs_caname" is already there - continue
+       }
+      unlink (t);
+      free (t);
+    }
+  else
+    free (cad);
+  char *lname = NULL;
+  if (relative_path)
+    {
+      if (common_archive[0] != '/' && aname[0] != '/')
+       {
+         // compare one relative path to another and find common beginning
+         char *rel_caname = dbe_sprintf ("%s/%s", common_archive, cafname);
+         if (rel_caname == NULL)
+           {
+             fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
+             return 1;
+           }
+         lname = get_relative_link (rel_caname, aname);
+         free (rel_caname);
+       }
+      else
+       {
+         if (abs_aname == NULL)
+           {
+             fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
+             return 1;
+           }
+         lname = get_relative_link (abs_caname, abs_aname);
+       }
+    }
+  else  // absolute path
+    lname = dbe_strdup (abs_caname);
+  free (abs_aname);
+  if (lname == NULL)
+    {
+      fprintf (stderr, GTXT ("er_archive: Fatal error: unable to allocate memory\n"));
+      return 1;
+    }
+  // Create symbolic link: aname -> lname
+  if (dbe_stat_file (abs_caname, NULL) == 0)
+    {
+      res = symlink (lname, aname);
+      if (res != 0)
+       {
+         fprintf (stderr, GTXT ("er_archive: Fatal error: symlink(%s, %s) returned error: %d (errno=%s)\n"),
+                  lname, aname, res, strerror (errno));
+         free (abs_caname);
+         free (lname);
+         return 1;
+       }
+      if (!hide_msg)
+       fprintf (stderr, GTXT ("Created symbolic link %s to file in common archive: %s\n"),
+                aname, lname);
+    }
+  else
+    {
+      fprintf (stderr, GTXT ("er_archive: Internal error: file does not exist in common archive: %s\n"),
+              abs_caname);
+      res = 1;
+    }
+  free (abs_caname);
+  free (lname);
+  return res;
+}
+
+/**
+ * Copy file to archive
+ * @param name
+ * @param aname
+ * @param hide_msg
+ * @param common_archive
+ * @return 0 - success
+ */
+int
+Experiment::copy_file (char *name, char *aname, int hide_msg, char *common_archive, int relative_path)
+{
+  if (common_archive)
+    {
+      if (0 == copy_file_to_common_archive (name, aname, hide_msg,
+                                           common_archive, relative_path))
+       return 0;
+      // Error. For now - fatal error. Message is already printed.
+      fprintf (stderr, GTXT ("er_archive: Fatal error: cannot copy file %s to common archive %s\n"),
+              name, common_archive);
+      return 1;
+    }
+  return (copy_file_to_archive (name, aname, hide_msg));
+}
+
+LoadObject *
+Experiment::createLoadObject (const char *path, uint64_t chksum)
+{
+  LoadObject *lo = dbeSession->createLoadObject (path, chksum);
+  if (lo->firstExp == NULL)
+    lo->firstExp = this;
+  return lo;
+}
+
+LoadObject *
+Experiment::createLoadObject (const char *path, const char *runTimePath)
+{
+  DbeFile *df = findFileInArchive (path, runTimePath);
+  if (df && (df->get_stat () == NULL))
+    df = NULL; // No access to file
+  LoadObject *lo = dbeSession->createLoadObject (path, runTimePath, df);
+  if (df && (lo->dbeFile->get_location (false) == NULL))
+    {
+      lo->dbeFile->set_location (df->get_location ());
+      lo->dbeFile->inArchive = df->inArchive;
+      lo->dbeFile->sbuf = df->sbuf;
+      lo->dbeFile->experiment = df->experiment;
+      lo->firstExp = df->experiment;
+    }
+  if (lo->firstExp == NULL)
+    {
+      lo->firstExp = this;
+      lo->dbeFile->experiment = this;
+    }
+  return lo;
+}
+
+SourceFile *
+Experiment::get_source (const char *path)
+{
+  if (founder_exp && (founder_exp != this))
+    return founder_exp->get_source (path);
+  if (sourcesMap == NULL)
+    sourcesMap = new StringMap<SourceFile*>(1024, 1024);
+  if (strncmp (path, NTXT ("./"), 2) == 0)
+    path += 2;
+  SourceFile *sf = sourcesMap->get (path);
+  if (sf)
+    return sf;
+  char *fnm = checkFileInArchive (path, false);
+  if (fnm)
+    {
+      sf = new SourceFile (path);
+      dbeSession->append (sf);
+      DbeFile *df = sf->dbeFile;
+      df->set_location (fnm);
+      df->inArchive = true;
+      df->check_access (fnm); // init 'sbuf'
+      df->sbuf.st_mtime = 0; // Don't check timestamps
+      free (fnm);
+    }
+  else
+    sf = dbeSession->createSourceFile (path);
+  sourcesMap->put (path, sf);
+  return sf;
+}
+
+Vector<Histable*> *
+Experiment::get_comparable_objs ()
+{
+  update_comparable_objs ();
+  if (comparable_objs || dbeSession->expGroups->size () <= 1)
+    return comparable_objs;
+  comparable_objs = new Vector<Histable*>(dbeSession->expGroups->size ());
+  for (long i = 0, sz = dbeSession->expGroups->size (); i < sz; i++)
+    {
+      ExpGroup *gr = dbeSession->expGroups->get (i);
+      if (groupId == gr->groupId)
+       {
+         comparable_objs->append (this);
+         continue;
+       }
+      Histable *h = NULL;
+      for (long i1 = 0, sz1 = gr->exps ? gr->exps->size () : 0; i1 < sz1; i1++)
+       {
+         Experiment *exp = gr->exps->get (i1);
+         if ((exp->comparable_objs == NULL) && (dbe_strcmp (utargname, exp->utargname) == 0))
+           {
+             exp->phaseCompareIdx = phaseCompareIdx;
+             h = exp;
+             h->comparable_objs = comparable_objs;
+             break;
+           }
+       }
+      comparable_objs->append (h);
+    }
+  dump_comparable_objs ();
+  return comparable_objs;
+}
+
+DbeFile *
+Experiment::findFileInArchive (const char *fname)
+{
+  if (archiveMap)
+    {
+      char *aname = get_archived_name (fname);
+      DbeFile *df = archiveMap->get (aname);
+      free (aname);
+      return df;
+    }
+  if (founder_exp)
+    return founder_exp->findFileInArchive (fname);
+  return NULL;
+}
+
+DbeFile *
+Experiment::findFileInArchive (const char *className, const char *runTimePath)
+{
+  DbeFile *df = NULL;
+  if (runTimePath)
+    {
+      const char *fnm = NULL;
+      if (strncmp (runTimePath, NTXT ("zip:"), 4) == 0)
+       fnm = runTimePath + 4;
+      else if (strncmp (runTimePath, NTXT ("jar:file:"), 9) == 0)
+       fnm = runTimePath + 9;
+      if (fnm)
+       {
+         const char *s = strchr (fnm, '!');
+         if (s)
+           {
+             char *s1 = dbe_strndup (fnm, s - fnm);
+             df = findFileInArchive (s1);
+             free (s1);
+           }
+         else
+           df = findFileInArchive (fnm);
+         if (df)
+           df->filetype |= DbeFile::F_JAR_FILE;
+       }
+      else if (strncmp (runTimePath, NTXT ("file:"), 5) == 0)
+       {
+         fnm = runTimePath + 5;
+         df = findFileInArchive (fnm);
+       }
+      else
+       df = findFileInArchive (runTimePath);
+    }
+  if (df == NULL)
+    df = findFileInArchive (className);
+  return df;
+}
diff --git a/gprofng/src/Experiment.h b/gprofng/src/Experiment.h
new file mode 100644 (file)
index 0000000..41c44e4
--- /dev/null
@@ -0,0 +1,689 @@
+/* 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 _EEXPERIMENT_H
+#define _EEXPERIMENT_H
+
+// The experiment class is responsible for managing all the data
+//  for an individual experiment
+
+#include "Metric.h"
+#include "Histable.h"
+#include "Stats_data.h"
+#include "DefaultMap.h"
+#include "HeapMap.h"
+
+class Data_window;
+class DbeFile;
+class CallStack;
+class JMethod;
+class Sample;
+class SegMem;
+class LoadObject;
+class SourceFile;
+class UserLabel;
+class PRBTree;
+class Emsg;
+class Emsgqueue;
+struct JThread;
+struct GCEvent;
+class FileData;
+class Module;
+class Experiment;
+template <class ITEM> class Vector;
+
+#define JTHREAD_DEFAULT     ((JThread*)0)
+#define JTHREAD_NONE        ((JThread*)-1)
+
+// When we perform the pipelined optimization on resolve_frame_info() and add_stack()
+// this is the number of iterations one phase works on before passing on the work to
+// the next phase
+
+#define CSTCTX_CHUNK_SZ 10000
+#define PIPELINE_QUEUE_SZ_HI 8
+#define PIPELINE_QUEUE_SZ_LOW 2
+
+// the add_stack_ctx structure contains the intermediate state (context) after
+// CSTCTX_CHUNK_SZ number of iterations to pass on the work to another thread to
+// operate on the next stage
+typedef struct
+{
+  Vector<DbeInstr*> *natpcs;
+  Vector<Histable*> *jpcs;
+  long idx;
+  FramePacket *frp;
+  hrtime_t tstamp;
+  uint32_t thrid;
+  bool last_ctx;
+} cstk_ctx;
+
+// To minimize threadpool overhead, the granularity of a job submitted is made larger:
+// containing a chunk of iterations (of size CSTCTX_CHUNK_SZ)
+typedef struct
+{
+  cstk_ctx* cstCtxAr[CSTCTX_CHUNK_SZ];
+  int last_idx;
+  long idx_begin;
+  long idx_end;
+  DataDescriptor *dDscr;
+  Experiment *exp;
+  void *cstk;
+} cstk_ctx_chunk;
+
+class Experiment : public Histable, public DbeMessages
+{
+public:
+
+  enum Exp_status
+  {
+    SUCCESS,
+    INCOMPLETE,
+    FAILURE
+  };
+
+  Experiment ();
+  virtual ~Experiment ();
+
+  virtual Histable_type
+  get_type ()
+  {
+    return EXPERIMENT;
+  };
+  virtual Vector<Histable*> *get_comparable_objs ();
+
+  int groupId;
+  Experiment *founder_exp;              // parent of this experiment
+  Vector<Experiment*> *children_exps;   // children of this experiment
+
+  // Configuration Information
+  char *hostname;       // Hosthame (e.g. mymachine)
+  long start_sec;       // Starting timeval secs.
+  char *username;       // name of person performing the test
+  char *architecture;   // Architecture name ("sun4")
+  Platform_t platform;  // Sparc,Sparcv9,Intel
+  WSize_t wsize;        // word size: may be w32 or w64
+  int clock;            // CPU clock frequency, Mhz
+  int varclock;         // Set if CPU clock frequency can change: turbo-mode
+  int maxclock;         // max. CPU clock frequency on MP machine
+  int minclock;         // min. CPU clock frequency on MP machine
+  int ncpus;            // count of CPUs where expt was recorded
+  int hw_cpuver;        // CPU version from libcpc
+  char *machinemodel;   // machine model of machine on which experiment was recorded
+  char *os_version;     // Operating system name
+  int page_size;        // Page size (bytes)
+  int npages;           // Number of page size
+  int exp_maj_version;  // major version number of current experiment
+  int exp_min_version;  // minor version number of current experiment
+  int hex_field_width;  // number of digits in hex form of address
+                       // for current experiment, i.e. 8 for 32bit addresses
+  int broken;           // If SP_JCMD_RUN line not seen
+  int obsolete;         // If pointer file experiment detected
+  bool hwc_default;     // True if HW counters were enabled by default
+  int hwc_bogus;        // Count of bogus HWC packets
+  int hwc_lost_int;     // Count of packets reflecting lost interrupt
+  int hwc_scanned;      // If the HWC packets have been scanned
+  int invalid_packet;   // Count of invalid packets
+  bool exec_started;    // True if exec was called, and exec error not yet seen
+  bool dataspaceavail;  // True if dataspace data is in the experiment
+  bool leaklistavail;   // True if leaklist data is in the experiment
+  bool heapdataavail;   // True if heap data is in the experiment
+  bool racelistavail;   // true if there are race events in the experiment
+  bool iodataavail;     // true if there are io events in the experiment
+  bool deadlocklistavail; // true if there are deadlock events in the experiment
+  bool timelineavail;   // true if there are valid timestamps in the experiment
+  bool ifreqavail;      // True if instruction-frequency data is in the experiment
+  bool ompavail;        // true if there is OpenMP data in the experiment
+  bool has_java;
+  char *uarglist;       // argv[] array, as a string
+  char *utargname;      // basename of argv[0] extracted from uarglist
+  char *ucwd;           // working directory
+  char *cversion;       // collector version string
+  char *dversion;       // driver version string (er_kernel)
+  char *jversion;       // Java version string (java profiling)
+
+  // Open the named experiment record and process log file
+  Exp_status open (char *directory_name);
+
+  // Update experiment (read and process new data)
+  Exp_status update ();
+
+  // Returns collector parameters for the current sample selection
+  Collection_params *
+  get_params ()
+  {
+    return &coll_params;
+  }
+
+  Exp_status
+  get_status ()
+  {
+    return status;
+  }
+
+  // Returns the number of samples. For use by FilterNumeric
+  int
+  nsamples ()
+  {
+    return samples->size ();
+  }
+
+  // Release any releasable memory.
+  void purge ();
+
+  void resetShowHideStack ();
+  int save_notes (char*, bool);
+  int delete_notes (bool);
+  Experiment *getBaseFounder (); // returns topmost founder or this if no descendents
+
+  hrtime_t
+  getStartTime ()
+  {
+    return exp_start_time;
+  }
+  hrtime_t getRelativeStartTime (); // delta between start and founder's start
+
+  hrtime_t
+  getWallStartSec ()
+  {
+    return start_sec;
+  }
+
+  hrtime_t
+  getLastEvent ()
+  {
+    if (last_event != ZERO_TIME)
+      return last_event;
+    return exp_start_time;
+  }
+
+  hrtime_t
+  getGCDuration ()
+  {
+    return gc_duration;
+  }
+
+  int
+  getPID ()
+  {
+    return pid;
+  }
+
+  int
+  getUserExpId ()
+  {
+    return userExpId;
+  }
+
+  int
+  getExpIdx ()
+  {
+    return expIdx;
+  }
+
+  void
+  setExpIdx (int idx)
+  {
+    expIdx = idx;
+  }
+
+  void
+  setUserExpId (int idx)
+  {
+    userExpId = idx;
+  }
+
+  void
+  setTinyThreshold (int limit)
+  {
+    tiny_threshold = limit;
+  }
+
+  bool
+  isDiscardedTinyExperiment ()
+  {
+    return discardTiny;
+  }
+
+  Exp_status open_epilogue ();
+  void read_experiment_data (bool read_ahead);
+  static int copy_file_to_archive (const char *name, const char *aname, int hide_msg);
+  static int copy_file_to_common_archive (const char *name, const char *aname,
+              int hide_msg, const char *common_archive, int relative_path = 0);
+  static int copy_file (char *name, char *aname, int hide_msg,
+                       char *common_archive = NULL, int relative_path = 0);
+
+  // get_raw_events()
+  // action: get unfiltered packets, loading them if required
+  // parameters: data_id (see ProfData_type)
+  DataDescriptor *get_raw_events (int data_id);
+  Vector<DataDescriptor*> *getDataDescriptors ();
+
+  // Some DATA_* types are derived from others, e.g. DATA_HEAPSZ is derived from DATA_HEAP
+  // The following hooks support derived DataViews
+  int base_data_id (int data_id); // returns base data_id type  (ProfData_type DATA_*)
+  DataView *create_derived_data_view (int data_id, DataView *dview);
+
+  Vector<BaseMetric*>*
+  get_metric_list ()
+  {
+    return metrics;
+  }
+
+  char *
+  get_expt_name ()
+  {
+    return expt_name;   // Return the pathname to the experiment
+  };
+
+  Vector<char*> *get_descendants_names ();
+  char *get_fndr_arch_name ();
+  char *get_arch_name ();
+  char *getNameInArchive (const char *fname, bool archiveFile = false);
+  char *checkFileInArchive (const char *fname, bool archiveFile = false);
+  DbeFile *findFileInArchive (const char *className, const char *runTimePath);
+  DbeFile *findFileInArchive (const char *fname);
+  bool create_dir (char *dname);
+
+  Vaddr
+  ret_stack_base ()
+  {
+    return stack_base;
+  };
+
+  // Map a virtual address to a PC pair
+  DbeInstr *map_Vaddr_to_PC (Vaddr addr, hrtime_t ts);
+  DbeInstr *map_jmid_to_PC (Vaddr mid, int lineno, hrtime_t ts);
+  Sample *map_event_to_Sample (hrtime_t ts);
+  GCEvent *map_event_to_GCEvent (hrtime_t ts);
+
+  DataView *
+  getOpenMPdata ()
+  {
+    return openMPdata;
+  }
+
+  time_t
+  get_mtime ()
+  {
+    return mtime;
+  }
+
+  Emsg *fetch_comments (void);  // fetch the queue of comment messages
+  Emsg *fetch_runlogq (void);   // fetch the queue of run log messages
+  Emsg *fetch_errors (void);    // fetch the queue of error messages
+  Emsg *fetch_warnings (void);  // fetch the queue of warning messages
+  Emsg *fetch_notes (void);     // fetch the queue of notes messages
+  Emsg *fetch_ifreq (void);     // fetch the queue of ifreq messages
+  Emsg *fetch_pprocq (void);    // fetch the queue of post-processing messages
+
+  // message queues
+  Emsgqueue *commentq;  // comments for the experiment header
+  Emsgqueue *runlogq;   // used temporarily; after log file processing,
+  // messages are appended to the commentq
+  Emsgqueue *errorq;    // error messages
+  Emsgqueue *warnq;     // warning messages
+  Emsgqueue *notesq;    // user-written notes messages
+  Emsgqueue *pprocq;    // postprocessing messages
+  Emsgqueue *ifreqq;    // Instruction frequency data, from count experiment
+  Map<const char*, LoadObject*> *loadObjMap;
+  Vector<LoadObject*> *loadObjs;
+  void append (LoadObject *lo);
+  LoadObject *createLoadObject (const char *path, uint64_t chksum = 0);
+  LoadObject *createLoadObject (const char *path, const char *runTimePath);
+  SourceFile *get_source (const char *path);
+  void set_clock (int clk);
+
+  CallStack *
+  callTree ()
+  {
+    return cstack;
+  }
+
+  CallStack *
+  callTreeShowHide ()
+  {
+    return cstackShowHide;
+  }
+
+  uint32_t mapTagValue (Prop_type, uint64_t value);
+  Histable *getTagObj (Prop_type, uint32_t idx);
+  Vector<Histable*> *getTagObjs (Prop_type);
+
+  JThread *map_pckt_to_Jthread (uint32_t tid, hrtime_t tstamp);
+  JThread *get_jthread (uint32_t tid);
+
+  Vector<JThread*> *
+  get_jthreads ()
+  {
+    return jthreads;
+  }
+
+  Vector<GCEvent*> *
+  get_gcevents ()
+  {
+    return gcevents;
+  }
+
+  bool need_swap_endian;
+  Collection_params coll_params; // Collection params
+
+  // Ranges for threads, lwps, cpu
+  uint64_t min_thread;
+  uint64_t max_thread;
+  uint64_t thread_cnt;
+  uint64_t min_lwp;
+  uint64_t max_lwp;
+  uint64_t lwp_cnt;
+  uint64_t min_cpu;
+  uint64_t max_cpu;
+  uint64_t cpu_cnt;
+  uint64_t dsevents;        // count of dataspace events
+  uint64_t dsnoxhwcevents;  /* count of ds events that could be be validated
+                            * because of no branch target info */
+
+  PacketDescriptor *newPacketDescriptor (int kind, DataDescriptor *dDscr);
+  PacketDescriptor *getPacketDescriptor (int kind);
+
+  // debugging aids -- dump_stacks, dump_map
+  void dump_stacks (FILE *);
+  void dump_map (FILE *);
+
+  // These methods are used in nightly performance regression testing
+  void DBG_memuse (Sample *);
+  void DBG_memuse (const char *sname);
+  void init_cache ();
+
+  DefaultMap<int64_t, FileData*> *
+  getFDataMap ()
+  {
+    return fDataMap;
+  }
+  CallStack *cstack;
+
+protected:
+
+  Exp_status status;        // Error status
+  Vector<SegMem*> *seg_items; // Master list of seg_items
+  CallStack *cstackShowHide;
+  PRBTree *maps;            // All maps in (Vaddr,time)
+
+  hrtime_t gc_duration;     // wall-clock hrtime of total GC intervals
+  hrtime_t exp_start_time;  // wall-clock hrtime at exp start
+  hrtime_t last_event;      // wall-clock hrtime of last known sample or log.xml entry
+  hrtime_t non_paused_time; // sum of periods where data collection is active (not paused)
+  hrtime_t resume_ts;       // tracks log.xml start/resume times
+  void update_last_event (hrtime_t ts /*wall time (not 0-based)*/);
+
+  char *expt_name;      // name of experiment
+  char *arch_name;      // <experiment>/archive
+  char *fndr_arch_name; // <founder_experiment>/archive
+  //TBR? hrtime_t sample_time;  // total of sample durations
+  int yyparse ();       // Allow yyparse actions to access
+  Vaddr stack_base;     // Stack base
+
+  // Write experiment header to comment queue
+  void write_header ();
+  void write_coll_params ();
+
+  Exp_status find_expdir (char *directory_name);
+
+  // Invoke the parser to process a file.
+  void read_data_file (const char*, const char*);
+  int read_log_file ();
+  void read_labels_file ();
+  void read_notes_file ();
+  void read_archives ();
+  int read_java_classes_file ();
+  void read_map_file ();
+  int read_overview_file ();
+  int read_dyntext_file ();
+  void read_omp_file ();
+  void read_omp_preg ();
+  void read_omp_task ();
+  void read_ifreq_file ();
+  void read_frameinfo_file ();
+
+  // Functions to process the log and loadobjects file entries
+  // They are deliberately made virtual to overload them
+  // in er_export.
+  virtual int process_arglist_cmd (char *, char *);
+  virtual int process_desc_start_cmd (char *, hrtime_t, char *, char *, int, char *);
+  virtual int process_desc_started_cmd (char *, hrtime_t, char *, char *, int, char *);
+  virtual int process_fn_load_cmd (Module *mod, char *fname, Vaddr vaddr, int fsize, hrtime_t ts);
+  virtual int process_fn_unload_cmd (char *, Vaddr, hrtime_t);
+  virtual int process_hwcounter_cmd (char *, int, char *, char *, int, int, int, char *);
+  virtual int process_hwsimctr_cmd (char *, int, char *, char *, char*, int, int, int, int, int);
+  virtual int process_jcm_load_cmd (char*, Vaddr, Vaddr, int, hrtime_t);
+  virtual int process_jcm_unload_cmd (char*, Vaddr, hrtime_t);
+  virtual int process_Linux_kernel_cmd (hrtime_t);
+  virtual int process_jthr_end_cmd (char *, uint64_t, Vaddr, Vaddr, hrtime_t);
+  virtual int process_jthr_start_cmd (char *, char *, char *, char *, uint64_t, Vaddr, Vaddr, hrtime_t);
+  virtual int process_gc_end_cmd (hrtime_t);
+  virtual int process_gc_start_cmd (hrtime_t);
+  virtual int process_sample_cmd (char *, hrtime_t, int id, char *lbl);
+  virtual int process_sample_sig_cmd (char *, int);
+  virtual int process_seg_map_cmd (char *, hrtime_t, Vaddr, int, int, int64_t, int64_t, int64_t, char *);
+  virtual int process_seg_unmap_cmd (char *, hrtime_t, Vaddr);
+
+  // creation time for experiment
+  time_t mtime;
+  hrtime_t exp_rel_start_time;      // start of exp. relative to founder
+  bool exp_rel_start_time_set;
+  Vector<UserLabel*> *userLabels;   // List of er_labels
+  int userExpId;                    // user value for EXPID
+  int expIdx;                       // DbeSession exp identifier
+  PRBTree *jmaps;                   // JAVA_CLASSES: (id,time)->Histable
+  Experiment* baseFounder;  // outermost experiment (null until lazily computed)
+
+  // Represents a file in experiment
+  class ExperimentFile;
+
+  // XML handler to parse various experiment files
+  class ExperimentHandler;
+  class ExperimentLabelsHandler;
+
+  uint64_t readPacket (Data_window *dwin, Data_window::Span *span);
+  void readPacket (Data_window *dwin, char *ptr, PacketDescriptor *pDscr,
+                  DataDescriptor *dDscr, int arg, uint64_t pktsz);
+
+  // read data
+  DataDescriptor *get_profile_events ();
+  DataDescriptor *get_sync_events ();
+  DataDescriptor *get_hwc_events ();
+  DataDescriptor *get_heap_events ();
+  DataDescriptor *get_heapsz_events ();
+  DataDescriptor *get_iotrace_events ();
+  DataDescriptor *get_race_events ();
+  DataDescriptor *get_deadlock_events ();
+  DataDescriptor *get_sample_events ();
+  DataDescriptor *get_gc_events ();
+  DataDescriptor *getDataDescriptor (int data_id);
+  DataDescriptor *newDataDescriptor (int data_id, int flags = 0,
+                                    DataDescriptor *master_dDscr = NULL);
+
+  // Frame info data structures and methods
+  struct UIDnode;
+  struct RawFramePacket;
+
+  Vector<RawFramePacket*>*frmpckts; // frame info data
+  static int frUidCmp (const void*, const void*);
+  RawFramePacket *find_frame_packet (uint64_t uid);
+
+  static const int CHUNKSZ = 16384;
+  long nnodes;
+  long nchunks;
+  UIDnode **chunks;
+  UIDnode **uidHTable;
+  Vector<UIDnode*> *uidnodes;
+  bool resolveFrameInfo;
+  bool discardTiny;
+  int tiny_threshold; /* optimize away tiny experiments which ran
+                      * for less than specified time (ms): default 0 */
+
+  static int uidNodeCmp (const void *a, const void *b);
+  UIDnode *add_uid (Data_window *dwin, uint64_t uid, int size, uint32_t *array, uint64_t link_uid);
+  UIDnode *add_uid (Data_window *dwin, uint64_t uid, int size, uint64_t *array, uint64_t link_uid);
+  UIDnode *new_uid_node (uint64_t uid, uint64_t val);
+  UIDnode *get_uid_node (uint64_t uid, uint64_t val);
+  UIDnode *get_uid_node (uint64_t uid);
+  UIDnode *find_uid_node (uint64_t uid);
+
+  ExperimentFile *logFile;
+
+  // Data descriptors
+  Vector<DataDescriptor*> *dataDscrs;
+  Vector<PacketDescriptor*> *pcktDscrs;
+  long blksz; // binary data file block size
+
+  // Processed data packets
+  DataView *openMPdata; // OMP fork events
+
+  // Map events to OpenMP parallel regions and tasks
+  Map2D<uint32_t, hrtime_t, uint64_t> *mapPRid;
+  Map2D<uint32_t, hrtime_t, void*> *mapPReg;
+  Map2D<uint32_t, hrtime_t, void*> *mapTask;
+
+  // Archive content
+  Map<const char*, DbeFile *> *archiveMap;
+  Map<const char*, SourceFile*>*sourcesMap;
+
+  void init ();
+  void fini ();
+  void post_process ();
+  void constructJavaStack (FramePacket *, UIDnode *, Map<uint64_t, uint64_t> *);
+  void resolve_frame_info (DataDescriptor*);
+  void cleanup_cstk_ctx_chunk ();
+  void register_metric (Metric::Type type);
+  void register_metric (Hwcentry *ctr, const char* aux, const char* username);
+
+  Sample *sample_last_used;
+  GCEvent *gcevent_last_used;
+  char *first_sample_label;
+  Module *get_jclass (const char *className, const char *fileName);
+  LoadObject *get_j_lo (const char *className, const char *fileName);
+
+  Vector<BaseMetric*> *metrics;
+  Vector<JThread*> *jthreads;       // master list of Java threads
+  Vector<JThread*> *jthreads_idx;   // index in the master list
+  Vector<GCEvent*> *gcevents;
+  Vector<UnmapChunk*> *heapUnmapEvents;
+  Vector<Sample*> *samples;         // Array of Sample pointers
+
+  DefaultMap<int64_t, FileData*> *fDataMap; // list of FileData objects using the virtual File descriptor as the key
+  DefaultMap<int, int64_t> *vFdMap; // list of virtual file descrptors using the file descriptor as the key
+
+  Vector<Vector<Histable*>*> *tagObjs; // tag objects
+  bool sparse_threads;
+
+  SegMem **smemHTable; // hash table for SegMem's
+  DbeInstr **instHTable; // hash table for DbeInstr
+  Map<unsigned long long, JMethod*> *jmidHTable; // hash table for jmid
+
+  // identity of target process
+  int pid;
+  int ppid;
+  int pgrp;
+  int sid;
+
+  // Map file processing related data
+  struct MapRecord
+  {
+
+    enum
+    {
+      LOAD, UNLOAD
+    } kind;
+    Histable *obj;
+    Vaddr base;
+    Size size;
+    hrtime_t ts;
+    uint64_t foff;
+  };
+
+  void mrec_insert (MapRecord *mrec);
+  SegMem *update_ts_in_maps (Vaddr addr, hrtime_t ts);
+  int read_warn_file ();
+  LoadObject *get_dynfunc_lo (const char *loName);
+  Function *create_dynfunc (Module *mod, char *fname, int64_t vaddr, int64_t fsize);
+  char *get_archived_name (const char *fname, bool archiveFile = false);
+
+  Vector<MapRecord*> *mrecs;
+
+private:
+  void add_evt_time_to_profile_events (DataDescriptor *dDscr);
+  DataView *create_heapsz_data_view (DataView *heap_dview);
+  void compute_heapsz_data_view (DataView *heapsz_dview);
+};
+
+struct JThread
+{
+  JThread *next;
+  char *name;
+  char *group_name;
+  char *parent_name;
+  uint32_t tid;     // system thread id
+  Vaddr jthr;       // recorded Java thread id
+  Vaddr jenv;       // recorded JNIEnv id
+  uint32_t jthr_id; // internal JThread object id
+  hrtime_t start;
+  hrtime_t end;
+
+  JThread ()
+  {
+    name = NULL;
+    group_name = NULL;
+    parent_name = NULL;
+  }
+
+  ~JThread ()
+  {
+    free (name);
+    free (group_name);
+    free (parent_name);
+  }
+  bool is_system ();
+};
+
+struct GCEvent
+{
+
+  GCEvent ()
+  {
+    id = -1;
+  }
+
+  ~GCEvent () { }
+
+  hrtime_t start;
+  hrtime_t end;
+  int id;
+};
+
+class ExperimentLoadCancelException
+{
+public:
+
+  ExperimentLoadCancelException () { };
+
+  ~ExperimentLoadCancelException () { };
+};
+
+
+#endif  /* _EEXPERIMENT_H */
diff --git a/gprofng/src/Expression.cc b/gprofng/src/Expression.cc
new file mode 100644 (file)
index 0000000..49c94a8
--- /dev/null
@@ -0,0 +1,1279 @@
+/* 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 <assert.h>
+#include "CallStack.h"
+#include "DbeSession.h"
+#include "DbeView.h"
+#include "DataObject.h"
+#include "Exp_Layout.h"
+#include "Experiment.h"
+#include "Module.h"
+#include "LoadObject.h"
+#include "Expression.h"
+#include "Function.h"
+#include "Histable.h"
+#include "Sample.h"
+#include "Table.h"
+
+//////////////////////////////////////////////////////////
+//  class Expression::Context
+
+static const uint64_t INDXOBJ_EXPGRID_SHIFT = 60;
+static const uint64_t INDXOBJ_EXPID_SHIFT   = 32;
+
+Expression::Context::Context (DbeView *_dbev, Experiment *_exp)
+{
+  dbev = _dbev;
+  exp = _exp;
+  dview = NULL;
+  eventId = 0;
+}
+
+Expression::Context::Context (DbeView *_dbev, Experiment *_exp,
+                             DataView *_dview, long _eventId)
+{
+  dbev = _dbev;
+  exp = _exp;
+  dview = _dview;
+  eventId = _eventId;
+}
+
+//////////////////////////////////////////////////////////
+//  class Expression
+Expression::Expression (OpCode _op, uint64_t _v)
+{
+  op = _op;
+  v = Value (_v);
+  arg0 = NULL;
+  arg1 = NULL;
+}
+
+Expression::Expression (OpCode _op, const Expression *_arg0,
+                       const Expression *_arg1)
+{
+  op = _op;
+  v = Value ();
+  arg0 = NULL;
+  arg1 = NULL;
+  if (_arg0)
+    arg0 = _arg0->copy ();
+  if (_arg1)
+    arg1 = _arg1->copy ();
+}
+
+Expression::~Expression ()
+{
+  delete arg0;
+  delete arg1;
+}
+
+Expression::Expression (const Expression &rhs)
+{
+  op = rhs.op;
+  arg0 = NULL;
+  arg1 = NULL;
+  if (rhs.arg0)
+    arg0 = rhs.arg0->copy ();
+  if (rhs.arg1)
+    arg1 = rhs.arg1->copy ();
+  v = Value (rhs.v);
+  fixupValues ();
+}
+
+Expression::Expression (const Expression *rhs)
+{
+  arg0 = NULL;
+  arg1 = NULL;
+  copy (rhs);
+}
+
+void
+Expression::copy (const Expression *rhs)
+{
+  op = rhs->op;
+  delete arg0;
+  delete arg1;
+  arg0 = NULL;
+  arg1 = NULL;
+  if (rhs->arg0)
+    arg0 = rhs->arg0->copy ();
+  if (rhs->arg1)
+    arg1 = rhs->arg1->copy ();
+  v = Value (rhs->v);
+  fixupValues ();
+}
+
+Expression &
+Expression::operator= (const Expression &rhs)
+{
+  if (this == &rhs)
+    return *this;
+  copy (&rhs);
+  return *this;
+}
+
+void
+Expression::fixupValues ()
+{
+  if (v.next)
+    {
+      assert (arg0 && v.next == &(arg0->v));
+      v.next = &(arg0->v);
+    }
+}
+
+bool
+Expression::getVal (int propId, Context *ctx)
+{
+  v.val = 0;
+  v.next = NULL;
+  int origPropId = propId;
+  switch (propId)
+    {
+    default:
+      {
+       if (!ctx->dview)
+         return false;
+       PropDescr *propDscr = ctx->dview->getProp (propId);
+       if (!propDscr)
+         return false;
+       switch (propDscr->vtype)
+         {
+         case TYPE_INT32:
+           v.val = ctx->dview->getIntValue (propId, ctx->eventId);
+           break;
+         case TYPE_UINT32:
+           v.val = (uint32_t) ctx->dview->getIntValue (propId, ctx->eventId); //prevent sign extension
+           break;
+         case TYPE_INT64:
+         case TYPE_UINT64:
+           v.val = ctx->dview->getLongValue (propId, ctx->eventId);
+           break;
+         case TYPE_OBJ:
+           // YM: not sure if we should allow this
+           v.val = (long long) ctx->dview->getObjValue (propId, ctx->eventId);
+           break;
+         case TYPE_STRING:
+         case TYPE_DOUBLE:
+         default:
+           return false; // Weird, programming error?
+         }
+       break;
+      }
+    case PROP_FREQ_MHZ:
+      if (ctx->exp && ctx->exp->clock)
+       v.val = ctx->exp->clock;
+      else
+       return false;
+      break;
+    case PROP_PID:
+      if (ctx->exp == NULL)
+       return false;
+      v.val = ctx->exp->getPID ();
+      break;
+    case PROP_EXPID:
+      if (ctx->exp == NULL)
+       return false;
+      v.val = ctx->exp->getUserExpId ();
+      break;
+    case PROP_EXPID_CMP:
+      if (ctx->exp == NULL)
+       return false;
+      else
+       {
+         Experiment *exp = ctx->exp;
+         if (ctx->dbev && ctx->dbev->comparingExperiments ())
+           exp = (Experiment *) exp->get_compare_obj ();
+         v.val = exp->getUserExpId ();
+       }
+      break;
+    case PROP_EXPGRID:
+      if (ctx->exp == NULL)
+       return false;
+      v.val = ctx->exp->groupId;
+      break;
+    case PROP_NTICK_USEC:
+      if (ctx->exp == NULL)
+       return false;
+      if (ctx->dview && ctx->dview->getProp (PROP_NTICK))
+       v.val = ctx->dview->getIntValue (PROP_NTICK, ctx->eventId)
+               * ctx->exp->get_params ()->ptimer_usec;
+      else
+       return false;
+      break;
+    case PROP_ATSTAMP:
+    case PROP_ETSTAMP:
+      if (ctx->exp == NULL)
+       return false;
+      if (ctx->dview && ctx->dview->getProp (PROP_TSTAMP))
+       v.val = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
+      else
+       return false;
+      if (propId == PROP_ATSTAMP)
+       break; // absolute time, no adjustments
+      // propId==PROP_ETSTAMP
+      // calculate relative time from start of this experiment
+      v.val -= ctx->exp->getStartTime ();
+      break;
+    case PROP_TSTAMP:
+    case PROP_TSTAMP_LO:
+    case PROP_TSTAMP_HI:
+      {
+       if (ctx->exp == NULL)
+         return false;
+       if (!(ctx->dview && ctx->dview->getProp (PROP_TSTAMP)))
+         return false;
+       hrtime_t tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
+       // compute relative time from start of founder experiment
+       v.val = tstamp - ctx->exp->getStartTime ()
+               + ctx->exp->getRelativeStartTime ();
+       if (propId == PROP_TSTAMP)
+         break;
+       if (ctx->dview->getProp (PROP_EVT_TIME))
+         {
+           hrtime_t delta = ctx->dview->getLongValue (PROP_EVT_TIME, ctx->eventId);
+           if (propId == PROP_TSTAMP_LO)
+             {
+               if (delta > 0)
+                 { // positive delta means TSTAMP is at end
+                   // TSTAMP_LO = TSTAMP-delta
+                   v.val -= delta;
+                   break;
+                 }
+               break;
+             }
+           else
+             { // PROP_TSTAMP_HI
+               if (delta < 0)
+                 { // negative delta means TSTAMP is at start
+                   // TSTAMP_HI = TSTAMP+(-delta)
+                   v.val -= delta;
+                   break;
+                 }
+               break;
+             }
+         }
+       else if (ctx->dview->getProp (PROP_TSTAMP2))
+         {
+           if (propId == PROP_TSTAMP_HI)
+             {
+               hrtime_t tstamp2 = ctx->dview->getLongValue (PROP_TSTAMP2,
+                                                            ctx->eventId);
+               if (tstamp2 == 0)
+                 break; // if not initialized, event does not have duration
+               if (tstamp2 == MAX_TIME)
+                 tstamp2 = ctx->exp->getLastEvent ();
+               hrtime_t delta = tstamp2 - tstamp;
+               if (delta >= 0)
+                 {
+                   v.val += delta;
+                   break;
+                 }
+               break; // weird, delta should not be negative
+             }
+           break; // PROP_TSTAMP_LO, no modification needed
+         }
+       break; // should never be hit
+      }
+    case PROP_IOHEAPBYTES:
+      {
+       propId = PROP_IONBYTE;
+       if (ctx->dview == NULL)
+         return false;
+       if (!ctx->dview->getProp (propId))
+         { // has property?
+           propId = PROP_HSIZE;
+           if (!ctx->dview->getProp (propId))
+             return false;
+         }
+       v.val = ctx->dview->getLongValue (propId, ctx->eventId);
+       break;
+      }
+    case PROP_SAMPLE_MAP:
+      {
+       if (ctx->exp == NULL)
+         return false;
+       if (ctx->dview == NULL)
+         return false;
+       if (ctx->dview->getProp (PROP_SAMPLE))
+         v.val = ctx->dview->getIntValue (PROP_SAMPLE, ctx->eventId);
+       else
+         { // does not have property, convert to time.
+           uint64_t tstamp;
+           tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
+           Sample *sample = ctx->exp->map_event_to_Sample (tstamp);
+           v.val = sample ? sample->get_number () : -1;
+         }
+       break;
+      }
+    case PROP_GCEVENT_MAP:
+      {
+       if (ctx->exp == NULL)
+         return false;
+       if (ctx->dview == NULL)
+         return false;
+       if (ctx->dview->getProp (PROP_GCEVENT))
+         v.val = ctx->dview->getIntValue (PROP_GCEVENT, ctx->eventId);
+       else
+         { // does not have property, convert to time.
+           uint64_t tstamp;
+           tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
+           GCEvent *gcevent = ctx->exp->map_event_to_GCEvent (tstamp);
+           v.val = gcevent ? gcevent->id : 0;
+         }
+       break;
+      }
+    case PROP_LEAF:
+      {
+       if (ctx->dview == NULL)
+         return false;
+       VMode vmode = ctx->dbev ? ctx->dbev->get_view_mode () : VMODE_USER;
+       int prop_id;
+       if (vmode == VMODE_MACHINE)
+         prop_id = PROP_MSTACK;
+       else if (vmode == VMODE_EXPERT)
+         prop_id = PROP_XSTACK;
+       else
+         prop_id = PROP_USTACK;
+       if (!ctx->dview->getProp (prop_id))
+         return false;
+       Histable *obj = CallStack::getStackPC (ctx->dview->getObjValue (prop_id, ctx->eventId), 0);
+       Function *func = (Function*) obj->convertto (Histable::FUNCTION);
+       v.val = func->id; // LEAF
+       break;
+      }
+    case PROP_STACKID:
+      {
+       VMode vmode = ctx->dbev ? ctx->dbev->get_view_mode () : VMODE_USER;
+       if (vmode == VMODE_MACHINE)
+         propId = PROP_MSTACK;
+       else if (vmode == VMODE_EXPERT)
+         propId = PROP_XSTACK;
+       else
+         propId = PROP_USTACK;
+       if (ctx->dview == NULL)
+         return false;
+       if (!ctx->dview->getProp (propId))
+         return false;
+       v.val = (long) ctx->dview->getObjValue (propId, ctx->eventId);
+       break;
+      }
+    case PROP_STACKL:
+    case PROP_STACKI:
+    case PROP_STACK:
+      {
+       VMode vmode = ctx->dbev ? ctx->dbev->get_view_mode () : VMODE_USER;
+       if (vmode == VMODE_MACHINE)
+         propId = PROP_MSTACK;
+       else if (vmode == VMODE_EXPERT)
+         propId = PROP_XSTACK;
+       else
+         propId = PROP_USTACK;
+      }
+      // no break;
+    case PROP_MSTACKL:
+    case PROP_XSTACKL:
+    case PROP_USTACKL:
+    case PROP_MSTACKI:
+    case PROP_XSTACKI:
+    case PROP_USTACKI:
+      switch (propId)
+       {
+       case PROP_MSTACKL:
+       case PROP_MSTACKI:
+         propId = PROP_MSTACK;
+         break;
+       case PROP_XSTACKL:
+       case PROP_XSTACKI:
+         propId = PROP_XSTACK;
+         break;
+       case PROP_USTACKL:
+       case PROP_USTACKI:
+         propId = PROP_USTACK;
+         break;
+       default:
+         break;
+       }
+      // no break;
+    case PROP_MSTACK:
+    case PROP_XSTACK:
+    case PROP_USTACK:
+      {
+       if (ctx->dview == NULL)
+         return false;
+       if (!ctx->dview->getProp (propId))
+         return false;
+       bool hide_mode = !ctx->dbev->isShowAll ()
+               || ctx->dbev->isFilterHideMode ();
+       Expression *cur = this;
+       for (CallStackNode *stack = (CallStackNode *)
+               ctx->dview->getObjValue (propId, ctx->eventId);
+               stack; stack = stack->get_ancestor ())
+         {
+           Histable *hist = stack->get_instr ();
+           if (origPropId == PROP_STACK || origPropId == PROP_MSTACK
+               || origPropId == PROP_XSTACK || origPropId == PROP_USTACK)
+             {
+               cur->v.val = hist->convertto (Histable::FUNCTION)->id;
+               cur->v.fn = cur->v.val;
+             }
+           else if (origPropId == PROP_STACKL || origPropId == PROP_MSTACKL
+                   || origPropId == PROP_XSTACKL || origPropId == PROP_USTACKL)
+             {
+               cur->v.val = hist->convertto (Histable::LINE)->id;
+               if (hide_mode)
+                 cur->v.fn = hist->convertto (Histable::FUNCTION)->id;
+               else
+                 cur->v.fn = 0;
+             }
+           else if (origPropId == PROP_STACKI || origPropId == PROP_MSTACKI
+                   || origPropId == PROP_XSTACKI || origPropId == PROP_USTACKI)
+             {
+               cur->v.val = hist->convertto (Histable::INSTR)->id;
+               if (hide_mode)
+                 cur->v.fn = hist->convertto (Histable::FUNCTION)->id;
+               else
+                 cur->v.fn = 0;
+             }
+           if (cur->arg1 == NULL)
+             cur->arg1 = new Expression (OP_NONE, (uint64_t) 0);
+           if (stack->get_ancestor () == NULL)
+             {
+               if (origPropId == PROP_STACKL || origPropId == PROP_MSTACKL
+                   || origPropId == PROP_XSTACKL || origPropId == PROP_USTACKL
+                   || origPropId == PROP_STACKI || origPropId == PROP_MSTACKI
+                   || origPropId == PROP_XSTACKI || origPropId == PROP_USTACKI)
+                 {
+                   cur->v.next = NULL;
+                   continue;
+                 }
+             }
+           cur->v.next = &cur->arg1->v;
+           cur = cur->arg1;
+         }
+       if (origPropId == PROP_STACK || origPropId == PROP_MSTACK
+           || origPropId == PROP_XSTACK || origPropId == PROP_USTACK)
+         {
+           cur->v.val = dbeSession->get_Total_Function ()->id;
+           cur->v.fn = cur->v.val;
+           cur->v.next = NULL;
+         }
+       break;
+      }
+    case PROP_DOBJ:
+      {
+       if (ctx->dview == NULL)
+         return false;
+       if (!ctx->dview->getProp (PROP_DOBJ))
+         return false;
+       DataObject *dobj = (DataObject*)
+               ctx->dview->getObjValue (PROP_DOBJ, ctx->eventId);
+       if (dobj != NULL)
+         {
+           Expression *cur = this;
+           for (;;)
+             {
+               cur->v.val = dobj->id;
+               dobj = dobj->parent;
+               if (dobj == NULL)
+                 break;
+               if (cur->arg1 == NULL)
+                 cur->arg1 = new Expression (OP_NONE, (uint64_t) 0);
+               cur->v.next = &cur->arg1->v;
+               cur = cur->arg1;
+             }
+           cur->v.next = NULL;
+         }
+       break;
+      }
+    case PROP_CPRID:
+    case PROP_TSKID:
+      {
+       if (ctx->dview == NULL)
+         return false;
+       if (!ctx->dview->getProp (propId))
+         return false;
+       CallStackNode *ompstack = (CallStackNode *)
+               ctx->dview->getObjValue (propId, ctx->eventId);
+       Histable *hobj = ompstack->get_instr ();
+       if (hobj != NULL)
+         v.val = hobj->id;
+       break;
+      }
+    case PROP_JTHREAD:
+      {
+       if (ctx->exp == NULL)
+         return false;
+       if (ctx->dview == NULL)
+         return false;
+       if (!ctx->dview->getProp (propId))
+         return false;
+       uint64_t tstamp;
+       tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
+       uint32_t thrid;
+       uint64_t jthr_id = 0;
+       thrid = ctx->dview->getIntValue (PROP_THRID, ctx->eventId);
+       JThread *jthread = ctx->exp->map_pckt_to_Jthread (thrid, tstamp);
+       if (jthread != JTHREAD_NONE && jthread != JTHREAD_DEFAULT)
+         {
+           jthr_id = jthread->jthr_id;
+           uint64_t grid = ctx->exp->groupId;
+           uint64_t expid = ctx->exp->getUserExpId ();
+           v.val = (grid << INDXOBJ_EXPGRID_SHIFT) |
+                   (expid << INDXOBJ_EXPID_SHIFT) | jthr_id;
+         }
+       break;
+      }
+    }
+  return true;
+}
+
+bool
+Expression::bEval (Context *ctx)
+{
+  uint64_t v0, v1;
+  switch (op)
+    {
+    case OP_DEG:
+      if (!arg1->bEval (ctx))
+       return false;
+      if (arg1->v.val < 0)
+       {
+         v.val = 0;
+         return true;
+       }
+      if (!arg0->bEval (ctx))
+       {
+         return false;
+       }
+      v0 = arg0->v.val;
+      v1 = arg1->v.val;
+      for (v.val = 1; v1 > 0; v1--)
+       v.val *= v0;
+      return true;
+    case OP_MUL:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val * arg1->v.val;
+         return true;
+       }
+      return false;
+    case OP_DIV:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v1 = arg1->v.val;
+         v.val = (v1 == 0) ? 0 : (arg0->v.val / v1);
+         return true;
+       }
+      return false;
+    case OP_REM:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v1 = arg1->v.val;
+         v.val = (v1 == 0) ? 0 : (arg0->v.val % v1);
+         return true;
+       }
+      return false;
+    case OP_ADD:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val + arg1->v.val;
+         // DBFIXME LIBRARY VISIBILITY
+         // hack to pass v.fn value to new expression for leaf filters USTACK+0
+         v.fn = arg0->v.fn + arg1->v.fn;
+         return true;
+       }
+      return false;
+    case OP_MINUS:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val - arg1->v.val;
+         return true;
+       }
+      return false;
+    case OP_LS:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val << arg1->v.val;
+         return true;
+       }
+      return false;
+    case OP_RS:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val >> arg1->v.val;
+         return true;
+       }
+      return false;
+    case OP_LT:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val < arg1->v.val ? 1 : 0;
+         return true;
+       }
+      return false;
+    case OP_LE:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val <= arg1->v.val ? 1 : 0;
+         return true;
+       }
+      return false;
+    case OP_GT:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val > arg1->v.val ? 1 : 0;
+         return true;
+       }
+      return false;
+    case OP_GE:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val >= arg1->v.val ? 1 : 0;
+         return true;
+       }
+      return false;
+    case OP_EQ:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val == arg1->v.val ? 1 : 0;
+         return true;
+       }
+      return false;
+    case OP_NE:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val != arg1->v.val ? 1 : 0;
+         return true;
+       }
+      return false;
+    case OP_BITAND:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val & arg1->v.val;
+         return true;
+       }
+      return false;
+    case OP_BITXOR:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val ^ arg1->v.val;
+         return true;
+       }
+      return false;
+    case OP_BITOR:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v.val = arg0->v.val | arg1->v.val;
+         return true;
+       }
+      return false;
+    case OP_AND:
+      if (arg0->bEval (ctx))
+       {
+         if (arg0->v.val == 0)
+           {
+             v.val = 0;
+             return true;
+           }
+         if (arg1->bEval (ctx))
+           {
+             v.val = arg1->v.val == 0 ? 0 : 1;
+             return true;
+           }
+         return false;
+       }
+      if (arg1->bEval (ctx) && arg1->v.val == 0)
+       {
+         v.val = 0;
+         return true;
+       }
+      return false;
+    case OP_OR:
+      if (arg0->bEval (ctx))
+       {
+         if (arg0->v.val != 0)
+           {
+             v.val = 1;
+             return true;
+           }
+         if (arg1->bEval (ctx))
+           {
+             v.val = arg1->v.val == 0 ? 0 : 1;
+             return true;
+           }
+         return false;
+       }
+      if (arg1->bEval (ctx) && arg1->v.val != 0)
+       {
+         v.val = 1;
+         return true;
+       }
+      return false;
+    case OP_NEQV:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v0 = arg0->v.val;
+         v1 = arg1->v.val;
+         v.val = (v0 == 0 && v1 != 0) || (v0 != 0 && v1 == 0) ? 1 : 0;
+         return true;
+       }
+      return false;
+    case OP_EQV:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         v0 = arg0->v.val;
+         v1 = arg1->v.val;
+         v.val = (v0 == 0 && v1 == 0) || (v0 != 0 && v1 != 0) ? 1 : 0;
+         return true;
+       }
+      return false;
+    case OP_QWE:
+      if (arg0->bEval (ctx))
+       {
+         if (arg0->v.val != 0)
+           {
+             if (arg1->arg0->bEval (ctx))
+               {
+                 v.val = arg1->arg0->v.val;
+                 return true;
+               }
+           }
+         else
+           {
+             if (arg1->arg1->bEval (ctx))
+               {
+                 v.val = arg1->arg1->v.val;
+                 return true;
+               }
+           }
+       }
+      return false;
+    case OP_COMMA:
+      if (arg0->bEval (ctx))
+       {
+         v.next = &arg0->v;
+         if (arg1->bEval (ctx))
+           {
+             v.val = arg1->v.val;
+             return true;
+           }
+       }
+      return false;
+    case OP_IN:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         for (Value *s = &arg0->v; s; s = s->next)
+           {
+             bool found = false;
+             for (Value *t = &arg1->v; t; t = t->next)
+               {
+                 if (t->val == s->val)
+                   {
+                     found = true;
+                     break;
+                   }
+               }
+             if (!found)
+               {
+                 v.val = 0;
+                 return true;
+               }
+           }
+         v.val = 1;
+         return true;
+       }
+      return false;
+    case OP_SOMEIN:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         for (Value *s = &arg0->v; s; s = s->next)
+           {
+             for (Value *t = &arg1->v; t; t = t->next)
+               {
+                 if (t->val == s->val)
+                   {
+                     v.val = 1;
+                     return true;
+                   }
+               }
+           }
+         v.val = 0;
+         return true;
+       }
+      return false;
+    case OP_ORDRIN:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         for (Value *t0 = &arg1->v; t0; t0 = t0->next)
+           {
+             bool found = true;
+             for (Value *s = &arg0->v, *t = t0; s; s = s->next, t = t->next)
+               {
+                 if (t == NULL || t->val != s->val)
+                   {
+                     found = false;
+                     break;
+                   }
+               }
+             if (found)
+               {
+                 v.val = 1;
+                 return true;
+               }
+           }
+         v.val = 0;
+         return true;
+       }
+      return false;
+      // LIBRARY_VISIBILITY
+    case OP_LIBRARY_IN:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         for (Value *s = &arg0->v; s; s = s->next)
+           {
+             bool found = false;
+             uint64_t objId = s->val;
+             Histable *obj = dbeSession->findObjectById (objId);
+             bool libraryFound = false;
+             Function *fn;
+             if (obj != NULL && obj->get_type () == Histable::FUNCTION)
+               {
+                 fn = (Function *) obj;
+                 if (fn->isHideFunc)
+                   // this belongss to a loadobject in hide/library mode
+                   libraryFound = true;
+               }
+
+             if (libraryFound)
+               {
+                 uint64_t lo_id = fn->module->loadobject->id;
+                 for (Value *t = &arg1->v; t; t = t->next)
+                   {
+                     uint64_t t_id = t->fn;
+                     Histable *obj2 = dbeSession->findObjectById (t_id);
+                     if (obj2 != NULL
+                         && obj2->get_type () == Histable::FUNCTION)
+                       {
+                         Function *func2 = (Function *) obj2;
+                         uint64_t lo_id2 = func2->module->loadobject->id;
+                         if (lo_id2 == lo_id)
+                           {
+                             found = true;
+                             break;
+                           }
+                       }
+                   }
+               }
+             else
+               {
+                 // Not a loadobject
+                 for (Value *t = &arg1->v; t; t = t->next)
+                   {
+                     if (t->val == s->val)
+                       {
+                         found = true;
+                         break;
+                       }
+                   }
+               }
+             if (!found)
+               {
+                 v.val = 0;
+                 return true;
+               }
+           }
+         v.val = 1;
+         return true;
+       }
+      return false;
+    case OP_LIBRARY_SOMEIN:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         for (Value *s = &arg0->v; s; s = s->next)
+           {
+             uint64_t objId = s->val;
+             Histable *obj = dbeSession->findObjectById (objId);
+             bool libraryFound = false;
+             Function *fn;
+             if (obj != NULL && obj->get_type () == Histable::FUNCTION)
+               {
+                 fn = (Function *) obj;
+                 if (fn->isHideFunc)
+                   // this belongs to a loadobject in hide/library mode
+                   libraryFound = true;
+               }
+
+             if (libraryFound)
+               {
+                 uint64_t lo_id = fn->module->loadobject->id;
+                 for (Value *t = &arg1->v; t; t = t->next)
+                   {
+                     uint64_t t_id = t->fn;
+                     Histable *obj2 = dbeSession->findObjectById (t_id);
+                     if (obj2 != NULL && obj2->get_type () == Histable::FUNCTION)
+                       {
+                         Function *func2 = (Function *) obj2;
+                         uint64_t lo_id2 = func2->module->loadobject->id;
+                         if (lo_id2 == lo_id)
+                           {
+                             v.val = 1;
+                             return true;
+                           }
+                       }
+                   }
+               }
+             else
+               {
+                 for (Value *t = &arg1->v; t; t = t->next)
+                   if (t->val == s->val)
+                     {
+                       v.val = 1;
+                       return true;
+                     }
+               }
+           }
+         v.val = 0;
+         return true;
+       }
+      return false;
+    case OP_LIBRARY_ORDRIN:
+      if (arg0->bEval (ctx) && arg1->bEval (ctx))
+       {
+         for (Value *t0 = &arg1->v; t0; t0 = t0->next)
+           {
+             bool found = true;
+             Value *t = t0;
+             for (Value *s = &arg0->v; s; s = s->next)
+               {
+                 // start comparing s->val with t->val
+                 // if matches move on to s->next and t->next
+                 uint64_t objId = s->val;
+                 Histable *obj = dbeSession->findObjectById (objId);
+                 bool libraryFound = false;
+                 Function *fn;
+                 if (obj != NULL && obj->get_type () == Histable::FUNCTION)
+                   {
+                     fn = (Function *) obj;
+                     if (fn->isHideFunc)
+                       libraryFound = true;
+                   }
+                 if (libraryFound)
+                   {
+                     // s->val is from a loadobject
+                     // check if t->val is a func whose loadobject matches s->val
+                     uint64_t lo_id = fn->module->loadobject->id;
+                     uint64_t t_id = t->fn;
+                     Histable *obj2 = dbeSession->findObjectById (t_id);
+                     if (obj2 != NULL
+                         && obj2->get_type () == Histable::FUNCTION)
+                       {
+                         Function *func2 = (Function *) obj2;
+                         uint64_t lo_id2 = func2->module->loadobject->id;
+                         if (lo_id2 != lo_id)
+                           {
+                             // no match
+                             found = false;
+                             break;
+                           }
+                         else
+                           {
+                             // t->val is a func whose loadobject matches s->val
+                             while (t != NULL && lo_id2 == lo_id)
+                               {
+                                 // skip frames with same load object
+                                 t = t->next;
+                                 t_id = t->fn;
+                                 obj2 = dbeSession->findObjectById (t_id);
+                                 if (obj2 != NULL
+                                     && obj2->get_type () == Histable::FUNCTION)
+                                   {
+                                     func2 = (Function *) obj2;
+                                     lo_id2 = func2->module->loadobject->id;
+                                   }
+                               }
+                           }
+                       }
+                   }
+                 else
+                   {
+                     if (t == NULL || t->val != s->val)
+                       {
+                         found = false;
+                         break;
+                       }
+                     t = t->next;
+                   }
+               }
+             if (found)
+               {
+                 v.val = 1;
+                 return true;
+               }
+           }
+         v.val = 0;
+         return true;
+       }
+      return false;
+    case OP_BITNOT:
+      if (arg0->bEval (ctx))
+       {
+         v.val = ~arg0->v.val;
+         return true;
+       }
+      return false;
+    case OP_NOT:
+      if (arg0->bEval (ctx))
+       {
+         v.val = !arg0->v.val;
+         return true;
+       }
+      return false;
+    case OP_NUM:
+      return true;
+    case OP_NAME:
+      if (ctx && arg0->bEval (ctx) && getVal ((int) arg0->v.val, ctx))
+       return true;
+      return false;
+    case OP_FUNC:
+      // FNAME is completely processed by pEval for now
+      v.val = 0;
+      return true;
+    case OP_HASPROP:
+      if (!ctx || !ctx->dview)
+       return false; // can't be resolved (occurs during pEval() )
+      else if (arg0->op != OP_NAME || !arg0->arg0)
+       return false; // weird, wrong arg type
+      else
+       {
+         int propId = (int) arg0->arg0->v.val;
+         if (ctx->dview->getProp (propId))
+           v.val = 1;
+         else
+           v.val = 0;
+         return true;
+       }
+    case OP_FILE:
+      // FILENAME is completely processed by pEval for now
+      v.val = 0;
+      return true;
+    case OP_JAVA:
+      //JGROUP & JPARENT is completely processed by pEval for now
+      v.val = 0;
+      return true;
+    case OP_COLON:
+      return false; // OK for arg1 of OP_QWE
+    default:
+#ifdef IPC_LOG
+      fprintf (stderr, "INTERNAL ERROR: Expression::eval op=%d\n", op);
+#endif
+      return false;
+    }
+  return false;
+}
+
+Expression *
+Expression::pEval (Context *ctx) // partial evaluation (dview may be NULL)
+{
+  Expression *res = NULL;
+  switch (op)
+    {
+    case OP_FUNC:
+      {
+       Vector<Histable*> *objs = NULL;
+       if (arg0->v.val == FUNC_FNAME)
+         {
+           Histable::NameFormat nfmt = ctx ? ctx->dbev->get_name_format () : Histable::NA;
+           objs = (Vector<Histable*>*)dbeSession->match_func_names ((char*) arg1->v.val, nfmt);
+         }
+       else if (arg0->v.val == FUNC_DNAME)
+         objs = (Vector<Histable*>*)dbeSession->match_dobj_names ((char*) arg1->v.val);
+       Expression *cur = new Expression (Expression::OP_NUM, (uint64_t) 0);
+       res = cur;
+       int i = objs ? objs->size () - 1 : -1;
+       for (; i >= 0; i--)
+         {
+           cur->v.val = objs->fetch (i)->id;
+           if (i == 0)
+             break;
+           cur->arg0 = new Expression (OP_NONE, (uint64_t) 0);
+           cur->v.next = &cur->arg0->v;
+           cur = cur->arg0;
+         }
+       cur->v.next = NULL;
+       if (objs)
+         delete objs;
+       break;
+      }
+    case OP_JAVA:
+      {
+       Vector<JThread*> *objs = NULL;
+       Vector<uint64_t> *grids = NULL;
+       Vector<uint64_t> *expids = NULL;
+       if (arg0->v.val == JAVA_JGROUP)
+         objs = dbeSession->match_java_threads ((char*) arg1->v.val, 0, grids,
+                                                expids);
+       else if (arg0->v.val == JAVA_JPARENT)
+         objs = dbeSession->match_java_threads ((char*) arg1->v.val, 1, grids,
+                                                expids);
+       Expression *cur = new Expression (Expression::OP_NUM, (uint64_t) 0);
+       res = cur;
+       int i = objs ? objs->size () - 1 : -1;
+       for (; i >= 0; i--)
+         {
+           uint64_t jthr_id = 0;
+           JThread *jthread = (JThread *) (objs->fetch (i));
+           jthr_id = jthread->jthr_id;
+           uint64_t grid = grids->fetch (i);
+           uint64_t expid = expids->fetch (i);
+           cur->v.val = (grid << INDXOBJ_EXPGRID_SHIFT) |
+                   (expid << INDXOBJ_EXPID_SHIFT) | jthr_id;
+           if (i == 0)
+             break;
+           cur->arg0 = new Expression (OP_NONE, (uint64_t) 0);
+           cur->v.next = &cur->arg0->v;
+           cur = cur->arg0;
+         }
+       cur->v.next = NULL;
+       delete objs;
+       delete grids;
+       delete expids;
+       break;
+      }
+    case OP_FILE:
+      {
+       Vector<Histable*> *objs = NULL;
+       Histable::NameFormat nfmt = ctx ? ctx->dbev->get_name_format () : Histable::NA;
+       if (ctx)
+         objs = (Vector<Histable*>*)dbeSession->match_file_names ((char*) arg1->v.val, nfmt);
+       Expression *cur = new Expression (Expression::OP_NUM, (uint64_t) 0);
+       res = cur;
+       int i = objs ? objs->size () - 1 : -1;
+       for (; i >= 0; i--)
+         {
+           cur->v.val = objs->fetch (i)->id;
+           if (i == 0)
+             break;
+           cur->arg0 = new Expression (OP_NONE, (uint64_t) 0);
+           cur->v.next = &cur->arg0->v;
+           cur = cur->arg0;
+         }
+       cur->v.next = NULL;
+       if (objs)
+         delete objs;
+       break;
+      }
+    case OP_NUM:
+    case OP_COMMA:
+      res = copy ();
+      break;
+    case OP_IN:
+    case OP_SOMEIN:
+    case OP_ORDRIN:
+      {
+       // LIBRARY_VISIBILITY:
+       // Evaluate the arg0 of OP_IN, OP_SOMEIN, OP_ORDRIN to see if it has any library/loadobject
+       // Change it to OP_LIBRARY_IN, OP_LIBRARY_SOMEIN or OP_LIBRARY_ORDRIN respectively
+       if (dbeSession->is_lib_visibility_used () && (arg0->hasLoadObject ()
+                                                    || arg1->hasLoadObject ()))
+         {
+           OpCode new_op;
+           switch (op)
+             {
+             case OP_IN:
+               new_op = OP_LIBRARY_IN;
+               break;
+             case OP_SOMEIN:
+               new_op = OP_LIBRARY_SOMEIN;
+               break;
+             case OP_ORDRIN:
+               new_op = OP_LIBRARY_ORDRIN;
+               break;
+             default:
+               new_op = op; // Should never reach here
+               break;
+             }
+           if (arg1->hasLoadObject ())
+             res = new Expression (new_op, arg1 ? arg1->pEval (ctx) : NULL,
+                                   arg0 ? arg0->pEval (ctx) : NULL);
+           else
+             res = new Expression (new_op, arg0 ? arg0->pEval (ctx) : NULL,
+                                   arg1 ? arg1->pEval (ctx) : NULL);
+           res->v = v;
+           ctx->dbev->setFilterHideMode ();
+           return res;
+         }
+      }
+      // no break; if no loadobjects found fall thru to the default case
+    default:
+      if (bEval (ctx))
+       {
+         res = new Expression (OP_NUM, v.val);
+         break;
+       }
+      res = new Expression (op, arg0 ? arg0->pEval (ctx) : NULL,
+                           arg1 ? arg1->pEval (ctx) : NULL);
+      res->v = v;
+      break;
+    }
+  return res;
+}
+
+bool
+Expression::verifyObjectInExpr (Histable *obj)
+{
+  uint64_t id = ((uint64_t) obj->id);
+  if (op == OP_NUM && v.val == id)
+    return true;
+  bool inArg0 = false;
+  bool inArg1 = false;
+  if (arg0 != NULL)
+    inArg0 = arg0->verifyObjectInExpr (obj);
+  if (inArg0)
+    return true;
+  if (arg1 != NULL)
+    inArg1 = arg1->verifyObjectInExpr (obj);
+  if (inArg1)
+    return true;
+  return false;
+}
+
+bool
+Expression::hasLoadObject ()
+{
+  if (op == OP_NUM)
+    {
+      uint64_t id = v.val;
+      Histable *obj = dbeSession->findObjectById (id);
+      if (obj != NULL && obj->get_type () == Histable::FUNCTION)
+       {
+         Function *func = (Function *) obj;
+         if (func->isHideFunc)
+           return true;
+       }
+    }
+  if (arg0 && arg0->hasLoadObject ())
+    return true;
+  if (arg1 && arg1->hasLoadObject ())
+    return true;
+  return false;
+}
diff --git a/gprofng/src/Expression.h b/gprofng/src/Expression.h
new file mode 100644 (file)
index 0000000..7542853
--- /dev/null
@@ -0,0 +1,180 @@
+/* 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 _EXPRESSION_H
+#define _EXPRESSION_H
+
+#include <inttypes.h>
+
+class Experiment;
+class DataView;
+class DbeView;
+class Histable;
+
+class Expression
+{
+public:
+
+  class Context
+  {
+  public:
+    Context (DbeView *_dbev, Experiment *_exp = 0);
+    Context (DbeView *_dbev, Experiment *_exp, DataView *_dview, long _eventId);
+
+    ~Context () { };
+
+    void
+    put (DataView *d, long id)
+    {
+      dview = d;
+      eventId = id;
+    };
+
+    void
+    put (Experiment *_exp)
+    {
+      exp = _exp;
+    };
+
+    Experiment *exp;
+    DataView *dview;
+    DbeView *dbev;
+    long eventId;
+  };
+
+  enum OpCode
+  {
+    OP_NONE,
+    OP_QWE,
+    OP_COLON,
+    OP_OR,
+    OP_AND,
+    OP_NOT,
+    OP_EQV,
+    OP_NEQV,
+    OP_BITOR,
+    OP_BITAND,
+    OP_BITXOR,
+    OP_BITNOT,
+    OP_EQ,
+    OP_NE,
+    OP_LT,
+    OP_GT,
+    OP_LE,
+    OP_GE,
+    OP_LS,
+    OP_RS,
+    OP_ADD,
+    OP_MINUS,
+    OP_MUL,
+    OP_DIV,
+    OP_REM,
+    OP_DEG,
+    OP_COMMA,
+    OP_IN,
+    OP_SOMEIN,
+    OP_ORDRIN,
+    OP_NUM,
+    OP_NAME,
+    OP_FUNC,
+    OP_FILE,
+    OP_JAVA,
+    OP_HASPROP,
+    OP_LIBRARY_IN,
+    OP_LIBRARY_SOMEIN,
+    OP_LIBRARY_ORDRIN
+  };
+
+  enum FuncCode
+  {
+    FUNC_FNAME,
+    FUNC_DNAME
+  };
+
+  enum JavaCode
+  {
+    JAVA_JGROUP,
+    JAVA_JPARENT
+  };
+
+  Expression (OpCode, const Expression*, const Expression* = 0);
+  Expression (OpCode, uint64_t);
+  Expression (const Expression &rhs);
+  Expression (const Expression *rhs);
+  Expression &operator= (const Expression &rhs);
+  ~Expression ();
+
+  Expression *
+  copy () const
+  {
+    return new Expression (this);
+  }
+  void copy (const Expression *rhs);
+
+  uint64_t
+  eval (Context *ctx)
+  {
+    return bEval (ctx) ? v.val : 0;
+  };
+
+  bool
+  passes (Context *ctx)
+  {
+    return bEval (ctx) ? v.val != 0 : true;
+  };
+
+  bool
+  complete ()
+  {
+    return op == OP_NUM;
+  };
+
+  bool verifyObjectInExpr (Histable *obj);
+  Expression *
+  pEval (Context *ctx); // Partial evaluation to simplify expression
+
+private:
+
+  struct Value
+  {
+
+    Value (uint64_t _val = 0, Value *_next = 0) : val (_val), next (_next)
+    {
+      fn = 0;
+    }
+    uint64_t val;
+    uint64_t fn;
+    Value *next;
+  };
+
+  bool getVal (int propId, Context *ctx);
+  bool bEval (Context *ctx);
+
+  bool hasLoadObject ();
+  void fixupValues ();
+
+  OpCode op;
+  Value v;
+  Expression *arg0;
+  Expression *arg1;
+};
+
+
+#endif /* _EXPRESSION_H */
diff --git a/gprofng/src/FileData.cc b/gprofng/src/FileData.cc
new file mode 100644 (file)
index 0000000..7a941f5
--- /dev/null
@@ -0,0 +1,400 @@
+/* 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 <assert.h>
+#include <string.h>
+
+#include "util.h"
+#include "FileData.h"
+
+void
+FileData::init ()
+{
+  readTime = 0;
+  writeTime = 0;
+  otherTime = 0;
+  errorTime = 0;
+  readBytes = 0;
+  writeBytes = 0;
+  readCnt = 0;
+  writeCnt = 0;
+  otherCnt = 0;
+  errorCnt = 0;
+  wSlowestBytes = 0;
+  wSmallestBytes = _10TB;
+  wLargestBytes = 0;
+  w0KB1KBCnt = 0;
+  w1KB8KBCnt = 0;
+  w8KB32KBCnt = 0;
+  w32KB128KBCnt = 0;
+  w128KB256KBCnt = 0;
+  w256KB512KBCnt = 0;
+  w512KB1000KBCnt = 0;
+  w1000KB10MBCnt = 0;
+  w10MB100MBCnt = 0;
+  w100MB1GBCnt = 0;
+  w1GB10GBCnt = 0;
+  w10GB100GBCnt = 0;
+  w100GB1TBCnt = 0;
+  w1TB10TBCnt = 0;
+  rSlowestBytes = 0;
+  rSmallestBytes = _10TB;
+  rLargestBytes = 0;
+  r0KB1KBCnt = 0;
+  r1KB8KBCnt = 0;
+  r8KB32KBCnt = 0;
+  r32KB128KBCnt = 0;
+  r128KB256KBCnt = 0;
+  r256KB512KBCnt = 0;
+  r512KB1000KBCnt = 0;
+  r1000KB10MBCnt = 0;
+  r10MB100MBCnt = 0;
+  r100MB1GBCnt = 0;
+  r1GB10GBCnt = 0;
+  r10GB100GBCnt = 0;
+  r100GB1TBCnt = 0;
+  r1TB10TBCnt = 0;
+}
+
+FileData::FileData (const char *fName)
+{
+  fileName = dbe_strdup (fName);
+  fileDesList = new Vector<int>;
+  virtualFds = new Vector<int64_t>;
+  virtualFd = -1;
+  fileDes = -1;
+  fsType[0] = '\0';
+  histType = Histable::IOACTVFD;
+  init ();
+}
+
+FileData::FileData (FileData *fData)
+{
+  fileName = dbe_strdup (fData->fileName);
+  fileDesList = new Vector<int>;
+  Vector<int> *fdList = fData->fileDesList;
+  int fd;
+  if (fdList != NULL)
+    for (int i = 0; i < fdList->size (); i++)
+      if ((fd = fdList->fetch (i)) == -1)
+       fileDesList->append (fd);
+
+  virtualFds = new Vector<int64_t>;
+  Vector<int64_t> *vfds = fData->virtualFds;
+  int64_t vfd;
+  if (vfds != NULL)
+    for (int i = 0; i < vfds->size (); i++)
+      if ((vfd = vfds->fetch (i)) == -1)
+       virtualFds->append (vfd);
+  virtualFd = fData->virtualFd;
+  fileDes = fData->fileDes;
+  histType = fData->histType;
+
+  for (int i = 0; i < FSTYPESZ; i++)
+    fsType[i] = fData->fsType[i];
+
+  readTime = fData->readTime;
+  writeTime = fData->writeTime;
+  otherTime = fData->otherTime;
+  errorTime = fData->errorTime;
+  readBytes = fData->readBytes;
+  writeBytes = fData->writeBytes;
+  readCnt = fData->readCnt;
+  writeCnt = fData->writeCnt;
+  otherCnt = fData->otherCnt;
+  errorCnt = fData->errorCnt;
+  wSlowestBytes = fData->wSlowestBytes;
+  wSmallestBytes = fData->wSmallestBytes;
+  wLargestBytes = fData->wLargestBytes;
+  w0KB1KBCnt = fData->w0KB1KBCnt;
+  w1KB8KBCnt = fData->w1KB8KBCnt;
+  w8KB32KBCnt = fData->w8KB32KBCnt;
+  w32KB128KBCnt = fData->w32KB128KBCnt;
+  w128KB256KBCnt = fData->w128KB256KBCnt;
+  w256KB512KBCnt = fData->w256KB512KBCnt;
+  w512KB1000KBCnt = fData->w512KB1000KBCnt;
+  w1000KB10MBCnt = fData->w1000KB10MBCnt;
+  w10MB100MBCnt = fData->w10MB100MBCnt;
+  w100MB1GBCnt = fData->w100MB1GBCnt;
+  w1GB10GBCnt = fData->w1GB10GBCnt;
+  w10GB100GBCnt = fData->w10GB100GBCnt;
+  w100GB1TBCnt = fData->w100GB1TBCnt;
+  w1TB10TBCnt = fData->w1TB10TBCnt;
+  rSlowestBytes = fData->rSlowestBytes;
+  rSmallestBytes = fData->rSmallestBytes;
+  rLargestBytes = fData->rLargestBytes;
+  r0KB1KBCnt = fData->r0KB1KBCnt;
+  r1KB8KBCnt = fData->r1KB8KBCnt;
+  r8KB32KBCnt = fData->r8KB32KBCnt;
+  r32KB128KBCnt = fData->r32KB128KBCnt;
+  r128KB256KBCnt = fData->r128KB256KBCnt;
+  r256KB512KBCnt = fData->r256KB512KBCnt;
+  r512KB1000KBCnt = fData->r512KB1000KBCnt;
+  r1000KB10MBCnt = fData->r1000KB10MBCnt;
+  r10MB100MBCnt = fData->r10MB100MBCnt;
+  r100MB1GBCnt = fData->r100MB1GBCnt;
+  r1GB10GBCnt = fData->r1GB10GBCnt;
+  r10GB100GBCnt = fData->r10GB100GBCnt;
+  r100GB1TBCnt = fData->r100GB1TBCnt;
+  r1TB10TBCnt = fData->r1TB10TBCnt;
+}
+
+FileData::~FileData ()
+{
+  free (fileName);
+  delete fileDesList;
+  delete virtualFds;
+}
+
+void
+FileData::setVirtualFds (int64_t vfd)
+{
+  for (int i = 0; i < virtualFds->size (); i++)
+    if (vfd == virtualFds->fetch (i))
+      return;
+  virtualFds->append (vfd);
+}
+
+void
+FileData::setFileDesList (int fd)
+{
+  for (int i = 0; i < fileDesList->size (); i++)
+    if (fd == fileDesList->fetch (i))
+      return;
+  fileDesList->append (fd);
+}
+
+void
+FileData::setFsType (const char* fst)
+{
+  size_t len = strlen (fst);
+  if (len > 0 && len < FSTYPESZ)
+    snprintf (fsType, sizeof (fsType), NTXT ("%s"), fst);
+  else
+    snprintf (fsType, sizeof (fsType), GTXT ("error"));
+}
+
+Histable*
+FileData::convertto (Histable_type type, Histable*)
+{
+  return (type == histType ? this : NULL);
+}
+
+char*
+FileData::get_name (Histable::NameFormat /*_nfmt*/)
+{
+  if (histType == Histable::IOACTVFD)
+    {
+      if (!streq (fileName, NTXT ("<Total>")))
+       {
+         if (fileDes >= 0)
+           return dbe_sprintf (GTXT ("%s (IOVFD=%lld, FD=%d)"), fileName,
+                               (long long) virtualFd, (int) fileDes);
+         return dbe_sprintf (GTXT ("%s (IOVFD=%lld)"), fileName,
+                             (long long) virtualFd);
+       }
+      else
+       return fileName;
+    }
+  else if (histType == Histable::IOACTFILE)
+    {
+      if (!streq (fileName, NTXT ("<Total>")))
+       {
+         if (!streq (fsType, NTXT ("N/A")))
+           return dbe_sprintf (GTXT ("%s (FS=%s)"), fileName, fsType);
+         return fileName;
+       }
+      return fileName;
+    }
+  return fileName;
+}
+
+char*
+FileData::get_raw_name (Histable::NameFormat /*_nfmt*/)
+{
+  return fileName;
+}
+
+void
+FileData::setFsType (FileSystem_type fst)
+{
+  const char *fsName;
+  switch (fst)
+    {
+    case ZFS_TYPE:
+      fsName = "zfs";
+      break;
+    case NFS_TYPE:
+      fsName = "nfs";
+      break;
+    case UFS_TYPE:
+      fsName = "ufs";
+      break;
+    case UDFS_TYPE:
+      fsName = "udfs";
+      break;
+    case LOFS_TYPE:
+      fsName = "lofs";
+      break;
+    case VXFS_TYPE:
+      fsName = "vxfs";
+      break;
+    case TMPFS_TYPE:
+      fsName = "tmpfs";
+      break;
+    case PCFS_TYPE:
+      fsName = "pcfs";
+      break;
+    case HSFS_TYPE:
+      fsName = "hsfs";
+      break;
+    case PROCFS_TYPE:
+      fsName = "procfs";
+      break;
+    case FIFOFS_TYPE:
+      fsName = "fifofs";
+      break;
+    case SWAPFS_TYPE:
+      fsName = "swapfs";
+      break;
+    case CACHEFS_TYPE:
+      fsName = "cachefs";
+      break;
+    case AUTOFS_TYPE:
+      fsName = "autofs";
+      break;
+    case SPECFS_TYPE:
+      fsName = "specfs";
+      break;
+    case SOCKFS_TYPE:
+      fsName = "sockfs";
+      break;
+    case FDFS_TYPE:
+      fsName = "fdfs";
+      break;
+    case MNTFS_TYPE:
+      fsName = "mntfs";
+      break;
+    case NAMEFS_TYPE:
+      fsName = "namefs";
+      break;
+    case OBJFS_TYPE:
+      fsName = "objfs";
+      break;
+    case SHAREFS_TYPE:
+      fsName = "sharefs";
+      break;
+    case EXT2FS_TYPE:
+      fsName = "ext2";
+      break;
+    case EXT3FS_TYPE:
+      fsName = "ext3";
+      break;
+    case EXT4FS_TYPE:
+      fsName = "ext4";
+      break;
+    case UNKNOWNFS_TYPE:
+      fsName = "N/A";
+      break;
+    default:
+      fsName = "N/A";
+      break;
+    }
+  setFsType (fsName);
+}
+
+void
+FileData::setWriteStat (hrtime_t wt, int64_t nb)
+{
+  if (wSlowestBytes < wt)
+    wSlowestBytes = wt;
+  if (nb != 0 && wSmallestBytes > nb)
+    wSmallestBytes = nb;
+  if (wLargestBytes < nb)
+    wLargestBytes = nb;
+  if (nb >= 0 && nb <= _1KB)
+    w0KB1KBCnt++;
+  else if (nb <= _8KB)
+    w1KB8KBCnt++;
+  else if (nb <= _32KB)
+    w8KB32KBCnt++;
+  else if (nb <= _128KB)
+    w32KB128KBCnt++;
+  else if (nb <= _256KB)
+    w128KB256KBCnt++;
+  else if (nb <= _512KB)
+    w256KB512KBCnt++;
+  else if (nb <= _1000KB)
+    w512KB1000KBCnt++;
+  else if (nb <= _10MB)
+    w1000KB10MBCnt++;
+  else if (nb <= _100MB)
+    w10MB100MBCnt++;
+  else if (nb <= _1GB)
+    w100MB1GBCnt++;
+  else if (nb <= _10GB)
+    w1GB10GBCnt++;
+  else if (nb <= _100GB)
+    w10GB100GBCnt++;
+  else if (nb <= _1TB)
+    w100GB1TBCnt++;
+  else if (nb <= _10TB)
+    w1TB10TBCnt++;
+}
+
+void
+FileData::setReadStat (hrtime_t rt, int64_t nb)
+{
+  if (rSlowestBytes < rt)
+    rSlowestBytes = rt;
+  if (nb != 0 && rSmallestBytes > nb)
+    rSmallestBytes = nb;
+  if (rLargestBytes < nb)
+    rLargestBytes = nb;
+  if (nb >= 0 && nb <= _1KB)
+    r0KB1KBCnt++;
+  else if (nb <= _8KB)
+    r1KB8KBCnt++;
+  else if (nb <= _32KB)
+    r8KB32KBCnt++;
+  else if (nb <= _128KB)
+    r32KB128KBCnt++;
+  else if (nb <= _256KB)
+    r128KB256KBCnt++;
+  else if (nb <= _512KB)
+    r256KB512KBCnt++;
+  else if (nb <= _1000KB)
+    r512KB1000KBCnt++;
+  else if (nb <= _10MB)
+    r1000KB10MBCnt++;
+  else if (nb <= _100MB)
+    r10MB100MBCnt++;
+  else if (nb <= _1GB)
+    r100MB1GBCnt++;
+  else if (nb <= _10GB)
+    r1GB10GBCnt++;
+  else if (nb <= _100GB)
+    r10GB100GBCnt++;
+  else if (nb <= _1TB)
+    r100GB1TBCnt++;
+  else if (nb <= _10TB)
+    r1TB10TBCnt++;
+}
diff --git a/gprofng/src/FileData.h b/gprofng/src/FileData.h
new file mode 100644 (file)
index 0000000..67de689
--- /dev/null
@@ -0,0 +1,522 @@
+/* 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 _FILEDATA_H
+#define _FILEDATA_H
+
+#include "gp-defs.h"
+#include "gp-time.h"
+
+#include "vec.h"
+#include "data_pckts.h"
+#include "Histable.h"
+
+#define FSTYPESZ  16
+
+#define VIRTUAL_FD_TOTAL    0
+#define VIRTUAL_FD_STDIN    1
+#define VIRTUAL_FD_STDOUT   2
+#define VIRTUAL_FD_STDERR   3
+#define VIRTUAL_FD_OTHERIO  4
+#define VIRTUAL_FD_NONE     -1
+
+#define STDIN_FD            0
+#define STDOUT_FD           1
+#define STDERR_FD           2
+#define OTHERIO_FD          -1
+
+#define OTHERIO_FILENAME    "<Other IO activity>"
+#define STDIN_FILENAME      "<stdin>"
+#define STDOUT_FILENAME     "<stdout>"
+#define STDERR_FILENAME     "<stderr>"
+#define TOTAL_FILENAME      NTXT("<Total>")
+#define UNKNOWNFD_FILENAME  "<pipe(), socket(), or other fds>"
+
+#define _1KB        1024
+#define _8KB        8192
+#define _32KB       32768
+#define _128KB      131072
+#define _256KB      262144
+#define _512KB      524288
+#define _1000KB     1048576
+#define _10MB       10485760
+#define _100MB      104857600
+#define _1GB        1073741824
+#define _10GB       10737418240
+#define _100GB      107374182400
+#define _1TB        1099511627776
+#define _10TB       10995116277760
+
+class FileData : public Histable
+{
+  friend class IOActivity;
+public:
+  FileData (const char *fName);
+  FileData (FileData *fData);
+  ~FileData ();
+
+  virtual char *get_name (Histable::NameFormat nfmt);
+  virtual Histable *convertto (Histable_type, Histable* = NULL);
+
+  char *get_raw_name (Histable::NameFormat nfmt);
+  void setFsType (FileSystem_type fst);
+  void setFsType (const char* fst);
+
+  virtual Histable_type
+  get_type ()
+  {
+    return histType;
+  };
+
+  virtual uint64_t
+  get_addr ()
+  {
+    return virtualFd;
+  };
+
+  uint64_t
+  get_index ()
+  {
+    return virtualFd;
+  };
+
+  void init ();
+
+  char *
+  getFileName ()
+  {
+    return fileName;
+  }
+
+  void
+  addReadEvent (hrtime_t rt, int64_t nb)
+  {
+    readTime += rt;
+    readBytes += nb;
+    readCnt++;
+  }
+
+  hrtime_t
+  getReadTime ()
+  {
+    return readTime;
+  }
+
+  int64_t
+  getReadBytes ()
+  {
+    return readBytes;
+  }
+
+  int32_t
+  getReadCnt ()
+  {
+    return readCnt;
+  }
+
+  void
+  addWriteEvent (hrtime_t wt, int64_t nb)
+  {
+    writeTime += wt;
+    writeBytes += nb;
+    writeCnt++;
+  }
+
+  hrtime_t
+  getWriteTime ()
+  {
+    return writeTime;
+  }
+
+  int64_t
+  getWriteBytes ()
+  {
+    return writeBytes;
+  }
+
+  int32_t
+  getWriteCnt ()
+  {
+    return writeCnt;
+  }
+
+  void
+  addOtherEvent (hrtime_t ot)
+  {
+    otherTime += ot;
+    otherCnt++;
+  }
+
+  hrtime_t
+  getOtherTime ()
+  {
+    return otherTime;
+  }
+
+  int32_t
+  getOtherCnt ()
+  {
+    return otherCnt;
+  }
+
+  void
+  addErrorEvent (hrtime_t er)
+  {
+    errorTime += er;
+    errorCnt++;
+  }
+
+  hrtime_t
+  getErrorTime ()
+  {
+    return errorTime;
+  }
+
+  int32_t
+  getErrorCnt ()
+  {
+    return errorCnt;
+  }
+
+  void setFileDesList (int fd);
+
+  Vector<int> *
+  getFileDesList ()
+  {
+    return fileDesList;
+  }
+
+  void
+  setFileDes (int fd)
+  {
+    fileDes = fd;
+  }
+
+  int32_t
+  getFileDes ()
+  {
+    return fileDes;
+  }
+
+  void setVirtualFds (int64_t vfd);
+
+  Vector<int64_t> *
+  getVirtualFds ()
+  {
+    return virtualFds;
+  }
+
+  char *
+  getFsType ()
+  {
+    return fsType;
+  }
+
+  void
+  setVirtualFd (int64_t vFd)
+  {
+    virtualFd = vFd;
+  }
+
+  int64_t
+  getVirtualFd ()
+  {
+    return virtualFd;
+  }
+
+  void
+  setHistType (Histable::Type hType)
+  {
+    histType = hType;
+  }
+
+  Histable::Type
+  getHistType ()
+  {
+    return histType;
+  }
+
+  void setWriteStat (hrtime_t wt, int64_t nb);
+
+  hrtime_t
+  getWSlowestBytes ()
+  {
+    return wSlowestBytes;
+  }
+
+  int64_t
+  getWSmallestBytes ()
+  {
+    return wSmallestBytes;
+  }
+
+  int64_t
+  getWLargestBytes ()
+  {
+    return wLargestBytes;
+  }
+
+  int32_t
+  getW0KB1KBCnt ()
+  {
+    return w0KB1KBCnt;
+  }
+
+  int32_t
+  getW1KB8KBCnt ()
+  {
+    return w1KB8KBCnt;
+  }
+
+  int32_t
+  getW8KB32KBCnt ()
+  {
+    return w8KB32KBCnt;
+  }
+
+  int32_t
+  getW32KB128KBCnt ()
+  {
+    return w32KB128KBCnt;
+  }
+
+  int32_t
+  getW128KB256KBCnt ()
+  {
+    return w128KB256KBCnt;
+  }
+
+  int32_t
+  getW256KB512KBCnt ()
+  {
+    return w256KB512KBCnt;
+  }
+
+  int32_t
+  getW512KB1000KBCnt ()
+  {
+    return w512KB1000KBCnt;
+  }
+
+  int32_t
+  getW1000KB10MBCnt ()
+  {
+    return w1000KB10MBCnt;
+  }
+
+  int32_t
+  getW10MB100MBCnt ()
+  {
+    return w10MB100MBCnt;
+  }
+
+  int32_t
+  getW100MB1GBCnt ()
+  {
+    return w100MB1GBCnt;
+  }
+
+  int32_t
+  getW1GB10GBCnt ()
+  {
+    return w1GB10GBCnt;
+  }
+
+  int32_t
+  getW10GB100GBCnt ()
+  {
+    return w10GB100GBCnt;
+  }
+
+  int32_t
+  getW100GB1TBCnt ()
+  {
+    return w100GB1TBCnt;
+  }
+
+  int32_t
+  getW1TB10TBCnt ()
+  {
+    return w1TB10TBCnt;
+  }
+
+  void setReadStat (hrtime_t rt, int64_t nb);
+
+  hrtime_t
+  getRSlowestBytes ()
+  {
+    return rSlowestBytes;
+  }
+
+  int64_t
+  getRSmallestBytes ()
+  {
+    return rSmallestBytes;
+  }
+
+  int64_t
+  getRLargestBytes ()
+  {
+    return rLargestBytes;
+  }
+
+  int32_t
+  getR0KB1KBCnt ()
+  {
+    return r0KB1KBCnt;
+  }
+
+  int32_t
+  getR1KB8KBCnt ()
+  {
+    return r1KB8KBCnt;
+  }
+
+  int32_t
+  getR8KB32KBCnt ()
+  {
+    return r8KB32KBCnt;
+  }
+
+  int32_t
+  getR32KB128KBCnt ()
+  {
+    return r32KB128KBCnt;
+  }
+
+  int32_t
+  getR128KB256KBCnt ()
+  {
+    return r128KB256KBCnt;
+  }
+
+  int32_t
+  getR256KB512KBCnt ()
+  {
+    return r256KB512KBCnt;
+  }
+
+  int32_t
+  getR512KB1000KBCnt ()
+  {
+    return r512KB1000KBCnt;
+  }
+
+  int32_t
+  getR1000KB10MBCnt ()
+  {
+    return r1000KB10MBCnt;
+  }
+
+  int32_t
+  getR10MB100MBCnt ()
+  {
+    return r10MB100MBCnt;
+  }
+
+  int32_t
+  getR100MB1GBCnt ()
+  {
+    return r100MB1GBCnt;
+  }
+
+  int32_t
+  getR1GB10GBCnt ()
+  {
+    return r1GB10GBCnt;
+  }
+
+  int32_t
+  getR10GB100GBCnt ()
+  {
+    return r10GB100GBCnt;
+  }
+
+  int32_t
+  getR100GB1TBCnt ()
+  {
+    return r100GB1TBCnt;
+  }
+
+  int32_t
+  getR1TB10TBCnt ()
+  {
+    return r1TB10TBCnt;
+  }
+
+private:
+  char *fileName;           // File name
+  hrtime_t readTime;        // The Total time for read operations;
+  hrtime_t writeTime;       // The Total time for write operations;
+  hrtime_t otherTime;       // The Total time for other IO operations;
+  hrtime_t errorTime;       // The Total time for failed IO operations;
+  int64_t readBytes;        //The total bytes read
+  int64_t writeBytes;       //The total bytes written
+  int32_t readCnt;          // The read count
+  int32_t writeCnt;         // The write count
+  int32_t otherCnt;         // The other IO count
+  int32_t errorCnt;         // The failed IO count
+  Vector<int> *fileDesList; // The list of file descriptors
+  Vector<int64_t> *virtualFds; // The list of file virtual descriptors
+  char fsType[FSTYPESZ];    // The file system type
+  int64_t virtualFd;        // The virtual file descriptor
+  int32_t fileDes;          // The file descriptor
+  Histable::Type histType;  // The Histable type: IOACTFILE, IOACTVFD, ...
+
+  // Write statistics
+  hrtime_t wSlowestBytes;
+  int64_t wSmallestBytes;
+  int64_t wLargestBytes;
+  int32_t w0KB1KBCnt;
+  int32_t w1KB8KBCnt;
+  int32_t w8KB32KBCnt;
+  int32_t w32KB128KBCnt;
+  int32_t w128KB256KBCnt;
+  int32_t w256KB512KBCnt;
+  int32_t w512KB1000KBCnt;
+  int32_t w1000KB10MBCnt;
+  int32_t w10MB100MBCnt;
+  int32_t w100MB1GBCnt;
+  int32_t w1GB10GBCnt;
+  int32_t w10GB100GBCnt;
+  int32_t w100GB1TBCnt;
+  int32_t w1TB10TBCnt;
+
+  // Read statistics
+  hrtime_t rSlowestBytes;
+  int64_t rSmallestBytes;
+  int64_t rLargestBytes;
+  int32_t r0KB1KBCnt;
+  int32_t r1KB8KBCnt;
+  int32_t r8KB32KBCnt;
+  int32_t r32KB128KBCnt;
+  int32_t r128KB256KBCnt;
+  int32_t r256KB512KBCnt;
+  int32_t r512KB1000KBCnt;
+  int32_t r1000KB10MBCnt;
+  int32_t r10MB100MBCnt;
+  int32_t r100MB1GBCnt;
+  int32_t r1GB10GBCnt;
+  int32_t r10GB100GBCnt;
+  int32_t r100GB1TBCnt;
+  int32_t r1TB10TBCnt;
+};
+
+#endif
diff --git a/gprofng/src/Filter.cc b/gprofng/src/Filter.cc
new file mode 100644 (file)
index 0000000..34eda0d
--- /dev/null
@@ -0,0 +1,514 @@
+/* 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 <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include "Filter.h"
+#include "util.h"
+#include "i18n.h"
+#include "data_pckts.h"
+#include "StringBuilder.h"
+#include "Experiment.h"
+
+
+// ========================================================================
+// Subclass: FilterNumeric
+// Public Methods
+
+FilterNumeric::FilterNumeric (Experiment *_exp, const char *_cmd,
+                             const char *_name)
+{
+  exp = _exp;
+  cmd = dbe_strdup (_cmd);
+  name = dbe_strdup (_name);
+  pattern = NULL;
+  status = NULL;
+  items = NULL;
+  prop_name = NULL;
+  first = (uint64_t) - 1;
+  last = (uint64_t) - 1;
+  nselected = 0;
+  nitems = 0;
+}
+
+FilterNumeric::~FilterNumeric ()
+{
+  free (cmd);
+  free (name);
+  free (pattern);
+  free (status);
+  Destroy (items);
+}
+
+// sets min and max for this filter; should be called when the range is
+//     known -- that comes after the first PathTree build, in the current
+//     sequence of things
+void
+FilterNumeric::set_range (uint64_t findex, uint64_t lindex, uint64_t total)
+{
+  if (first == findex && last == lindex)
+    return;
+  first = findex;
+  last = lindex;
+  nitems = total;
+  nselected = nitems;
+  if (pattern)
+    {
+      free (pattern);
+      pattern = NULL;
+    }
+  if (status)
+    {
+      free (status);
+      status = NULL;
+    }
+}
+
+void
+FilterNumeric::update_range ()
+{
+  if (exp == NULL)
+    return;
+  if (streq (cmd, NTXT ("sample")))
+    set_range (1, (uint64_t) exp->nsamples (), exp->nsamples ());
+  else if (streq (cmd, NTXT ("thread")))
+    set_range (exp->min_thread, exp->max_thread, exp->thread_cnt);
+  else if (streq (cmd, NTXT ("LWP")))
+    set_range (exp->min_lwp, exp->max_lwp, exp->lwp_cnt);
+  else if (streq (cmd, NTXT ("cpu")))
+    {
+      if (exp->min_cpu != (uint64_t) - 1)
+       set_range (exp->min_cpu, exp->max_cpu, exp->cpu_cnt);
+    }
+}
+
+// get_advanced_filter -- returns a string matching the current setting
+char *
+FilterNumeric::get_advanced_filter ()
+{
+  if (items == NULL)
+    return NULL;
+  if (items->size () == 0)
+    return dbe_strdup (NTXT ("0"));
+
+  StringBuilder sb;
+  if (items->size () > 1)
+    sb.append ('(');
+  for (int i = 0; i < items->size (); i++)
+    {
+      RangePair *rp = items->fetch (i);
+      if (i > 0)
+       sb.append (NTXT (" || "));
+      sb.append ('(');
+      sb.append (prop_name);
+      if (rp->first == rp->last)
+       {
+         sb.append (NTXT ("=="));
+         sb.append ((long long) rp->first);
+       }
+      else
+       {
+         sb.append (NTXT (">="));
+         sb.append ((long long) rp->first);
+         sb.append (NTXT (" && "));
+         sb.append (prop_name);
+         sb.append (NTXT ("<="));
+         sb.append ((long long) rp->last);
+       }
+      sb.append (')');
+    }
+  if (items->size () > 1)
+    sb.append (')');
+  return sb.toString ();
+}
+
+
+// get_pattern -- returns a string matching the current setting
+
+char *
+FilterNumeric::get_pattern ()
+{
+  update_range ();
+  if (pattern)
+    return pattern;
+  StringBuilder sb;
+  if (items == NULL)
+    {
+      if (last == (uint64_t) - 1 && last == first)
+       // neither set; data not available
+       sb.append (GTXT ("(data not recorded)"));
+      else
+       sb.append (GTXT ("all"));
+    }
+  else if (items->size () == 0)
+    sb.append (GTXT ("none"));
+  else
+    {
+      for (int i = 0; i < items->size (); i++)
+       {
+         RangePair *rp = items->fetch (i);
+         if (i > 0)
+           sb.append (',');
+         sb.append ((long long) rp->first);
+         if (rp->first != rp->last)
+           {
+             sb.append ('-');
+             sb.append ((long long) rp->last);
+           }
+       }
+    }
+  pattern = sb.toString ();
+  return pattern;
+}
+
+char *
+FilterNumeric::get_status ()
+{
+  update_range ();
+  if (status == NULL)
+    update_status ();
+  return dbe_strdup (status);
+}
+
+// set_pattern -- set the filter to a new pattern
+//     set error true/false if there was or was not an error parsing string
+//     Returns true/false if the filter changed, implying a rebuild of data
+bool
+FilterNumeric::set_pattern (char *str, bool *error)
+{
+  update_range ();
+  // save the old filter
+  Vector<RangePair *> *olditems = items;
+  *error = false;
+  if (strcmp (str, NTXT ("all")) == 0)
+    // if all, leave items NULL
+    items = NULL;
+  else if (strcmp (str, NTXT ("none")) == 0)
+    // if none, leave items as a zero-length vector
+    items = new Vector<RangePair *>(0);
+  else
+    {
+      uint64_t val, val2;
+      char *s = str;
+      char *nexts = s;
+      items = NULL;
+      for (bool done = false; done == false;)
+       {
+         // tokenize the string
+         // Does it start with a "-" ?
+         if (*nexts == '-')
+           val = first; // yes, set val to first, and see what follows
+         else
+           {
+             // it must start with a number
+             val = get_next_number (s, &nexts, error);
+             if (*error == true)
+               break;
+           }
+
+         // look at the next character
+         switch (*nexts)
+           {
+           case ',':
+             s = ++nexts;
+             *error = include_range (val, val);
+             if (*error == true)
+               done = true;
+             break;
+           case '-':
+             s = ++nexts;
+             if (*nexts == ',' || *nexts == '\0')
+               val2 = last;
+             else
+               {
+                 val2 = get_next_number (s, &nexts, error);
+                 if (*error == true)
+                   {
+                     done = true;
+                     break;
+                   }
+               }
+             if (val > val2)
+               {
+                 *error = true;
+                 done = true;
+                 break;
+               }
+             *error = include_range (val, val2);
+             if (*error == true)
+               {
+                 done = true;
+                 break;
+               }
+             if (*nexts == ',')
+               {
+                 s = ++nexts;
+                 break;
+               }
+             if (*nexts == '\0')
+               {
+                 done = true;
+                 break;
+               }
+             break;
+           case '\0':
+             *error = include_range (val, val);
+             done = true;
+             break;
+           default:
+             *error = true;
+             done = true;
+             break;
+           }
+       }
+      // if there was a parser error leave old setting
+      if (*error == true)
+       {
+         if (items)
+           {
+             items->destroy ();
+             delete items;
+           }
+         items = olditems;
+         return false;
+       }
+    }
+
+  if (first != (uint64_t) - 1 && last != (uint64_t) - 1)
+    {
+      for (long i = VecSize (items) - 1; i >= 0; i--)
+       {
+         RangePair *rp = items->get (i);
+         if ((rp->first > last) || (rp->last < first))
+           {
+             delete rp;
+             items->remove (i);
+             continue;
+           }
+         if (rp->first < first)
+           rp->first = first;
+         if (rp->last > last)
+           rp->last = last;
+       }
+      if (VecSize (items) == 1)
+       {
+         RangePair *rp = items->get (0);
+         if ((rp->first == first) && (rp->last == last))
+           {
+             // All, leave items NULL
+             items->destroy ();
+             delete items;
+             items = NULL;
+           }
+       }
+    }
+
+  // no error, delete the old setting
+  if (olditems != NULL)
+    {
+      olditems->destroy ();
+      delete olditems;
+    }
+
+  bool changed;
+  // regenerate the pattern
+  if (pattern == NULL)
+    changed = true;
+  else
+    {
+      char *oldpattern = pattern;
+      pattern = NULL; // to force a recompute with new values
+      (void) get_pattern ();
+      changed = strcmp (pattern, oldpattern) != 0;
+      free (oldpattern);
+    }
+  return changed;
+}
+
+//================================================================
+// Protected methods
+
+// set_status -- regenerate the status line, describing the current setting
+void
+FilterNumeric::update_status ()
+{
+  // regenerate the status line
+  free (status);
+  nselected = 0;
+  if (items == NULL)
+    {
+      if (last == (uint64_t) - 1 && last == first)
+       // neither set; data not available
+       status = dbe_sprintf (GTXT ("(data not recorded)"));
+      else if (first == (uint64_t) - 1 || last == (uint64_t) - 1)
+       // range was not set
+       status = dbe_sprintf (GTXT ("(all)"));
+      else
+       // range was set, compute percentage
+       status = dbe_sprintf (GTXT ("total %lld, range: %lld-%lld"),
+                             (long long) nitems, (long long) first,
+                             (long long) last);
+    }
+  else
+    {
+      // some are selected
+      int index;
+      RangePair *rp;
+      Vec_loop (RangePair *, items, index, rp)
+      {
+       nselected += rp->last - rp->first + 1;
+      }
+      if (last == (uint64_t) - 1)
+       // range was not set
+       status = dbe_sprintf (GTXT ("(%lld items selected)"),
+                             (long long) nselected);
+      else
+       // range was set
+       status = dbe_sprintf (GTXT ("total %lld, range: %lld-%lld"),
+                             (long long) nitems, (long long) first,
+                             (long long) last);
+    }
+}
+
+// Add a range to the filter; called from set_pattern for each index,
+//     or index pair
+bool
+FilterNumeric::include_range (uint64_t findex, uint64_t lindex)
+{
+  int index;
+  RangePair *rp;
+  if (findex > lindex)
+    return true;
+
+  bool done = false;
+  if (items == NULL)
+    items = new Vector<RangePair *>(0);
+
+  Vec_loop (RangePair *, items, index, rp)
+  {
+    if (findex < rp->first)
+      {
+       // Case where the new pair starts before the old
+       if (lindex + 1 < rp->first)
+         {
+           // this pair comes cleanly in front of the current item
+           RangePair *rp2 = new RangePair ();
+           rp2->first = findex;
+           rp2->last = lindex;
+           items->insert (index, rp2);
+           done = true;
+           break;
+         }
+       // This new one extends the previous from the front
+       rp->first = findex;
+chkextend:
+       if (lindex <= rp->last)
+         {
+           // but does not extend the back
+           done = true;
+           break;
+         }
+       // extend this one out
+       rp->last = lindex;
+
+       // does it go into the next range?
+       if (index == items->size () - 1)
+         {
+           // this is the last range, so it does not
+           done = true;
+           break;
+         }
+       RangePair *next = items->fetch (index + 1);
+       if (lindex + 1 < next->first)
+         {
+           // no extension, we're done
+           done = true;
+           break;
+         }
+       // it does extend the next one
+       next->first = rp->first;
+       rp = next;
+       // remove the current one, promoting next
+       items->remove (index);
+       goto chkextend;
+      }
+    else if (findex > rp->last + 1)
+      // the new one is completely beyond the current
+      continue;
+    else
+      {
+       // the new one may start at or after the current, but it
+       // extends it out;  set the current
+       // this pair overlaps the current item
+       // rp-> first is OK -- it's equal or less than findex
+       goto chkextend;
+      }
+  }
+
+  if (done != true)
+    {
+      // fall through -- append to list
+      rp = new RangePair ();
+      rp->first = findex;
+      rp->last = lindex;
+      items->append (rp);
+    }
+
+  return false;
+}
+
+// Scan the filter to see if the number given is filtered in or out
+//     return true if number is in, false if it's out
+bool
+FilterNumeric::is_selected (uint64_t number)
+{
+  int index;
+  RangePair *rp;
+  if (items == NULL)
+    return true;
+  if (items->size () == 0)
+    return false;
+
+  Vec_loop (RangePair *, items, index, rp)
+  {
+    if (number >= rp->first && number <= rp->last)
+      return true;
+  }
+  return false;
+}
+
+// get_next_number
+//     Called from parser to extract a number from the current string position
+//     Sets fail true if there was an error, false otherwise
+//     returns the number as parsed
+uint64_t
+FilterNumeric::get_next_number (char *s, char **e, bool *fail)
+{
+  errno = 0;
+  *fail = false;
+  uint64_t val = strtoll (s, e, 10);
+  if (errno == EINVAL)
+    *fail = true;
+  return (val);
+}
diff --git a/gprofng/src/Filter.h b/gprofng/src/Filter.h
new file mode 100644 (file)
index 0000000..1338218
--- /dev/null
@@ -0,0 +1,111 @@
+/* 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 _FILTER_H
+#define _FILTER_H
+
+// A sample selection specifies a set of samples the user is interested in
+// viewing as a whole.
+
+#include "vec.h"
+#include "data_pckts.h"
+
+class Experiment;
+
+class FilterNumeric
+{
+public:
+  FilterNumeric (Experiment *, const char *, const char *);
+  ~FilterNumeric ();
+
+  // set or update the range of items first and last
+  void set_range (uint64_t findex, uint64_t lindex, uint64_t total);
+
+  // Return a string representation of the current ranges
+  //   E.g. "1-5,7,9,10,12-13,73"
+  char *get_pattern ();
+
+  // Return a string for the current status: %, range, ...
+  //   E.g. "100%" "100% [1-7]"  "25% [1-4]"
+  char *get_status ();
+
+  char *get_advanced_filter ();
+
+  // Sets selection according to the string representation
+  // See above for return values and error handling
+  bool set_pattern (char *, bool *);
+
+    // Return true if "number" is included in selection
+  bool is_selected (uint64_t number);
+
+  char *
+  get_cmd ()
+  {
+    return cmd;
+  };
+
+  char *
+  get_name ()
+  {
+    return name;
+  };
+
+  uint64_t
+  nelem ()
+  {
+    return nitems;
+  };
+
+  char *prop_name; // name in advanced filter
+
+private:
+
+  typedef struct
+  {
+    uint64_t first;
+    uint64_t last;
+  } RangePair;
+
+  void update_status ();
+  void update_range ();
+
+  // Include "range" in selection
+  bool include_range (uint64_t findex, uint64_t lindex);
+
+  // Parse a number from the string
+  uint64_t get_next_number (char *s, char **e, bool *fail);
+
+  // Data
+  Vector<RangePair *> *items; // sorted array of items
+  uint64_t nselected;
+  uint64_t nitems;
+
+  Experiment *exp;
+  char *cmd;
+  char *name;
+  char *pattern;
+  char *status;
+
+  // First and Last items in selection
+  uint64_t first;
+  uint64_t last;
+};
+
+#endif /* _FILTER_H */
diff --git a/gprofng/src/FilterExp.h b/gprofng/src/FilterExp.h
new file mode 100644 (file)
index 0000000..b186af1
--- /dev/null
@@ -0,0 +1,56 @@
+/* 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 _FILTEREXP_H
+#define _FILTEREXP_H
+
+#include "Expression.h"
+
+class FilterExp
+{
+public:
+
+  FilterExp (Expression *_expr, Expression::Context *_ctx, bool _noParFilter) :
+            expr (_expr), ctx (_ctx), noParFilter (_noParFilter) { };
+
+  ~FilterExp ()
+  {
+    delete ctx;
+  }
+
+  bool
+  passes ()
+  {
+    return expr ? expr->passes (ctx) : true;
+  }
+
+  void
+  put (DataView *dview, long eventId)
+  {
+    ctx->put (dview, eventId);
+  }
+
+  Expression *expr;
+  Expression::Context *ctx;
+  bool noParFilter;
+};
+
+
+#endif /* _FILTEREXP_H */
diff --git a/gprofng/src/FilterSet.cc b/gprofng/src/FilterSet.cc
new file mode 100644 (file)
index 0000000..29dc437
--- /dev/null
@@ -0,0 +1,106 @@
+/* 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 "Experiment.h"
+#include "StringBuilder.h"
+#include "FilterSet.h"
+#include "Filter.h"
+#include "i18n.h"
+
+FilterSet::FilterSet (DbeView *_dbev, Experiment *_exp)
+{
+  dbev = _dbev;
+  exp = _exp;
+  enbl = false;
+  dfilter = new Vector<FilterNumeric *>;
+  FilterNumeric *f;
+  f = new FilterNumeric (exp, "sample", GTXT ("Samples"));
+  f->prop_name = NTXT ("SAMPLE_MAP");
+  dfilter->append (f);
+  f = new FilterNumeric (exp, "thread", GTXT ("Threads"));
+  f->prop_name = NTXT ("THRID");
+  dfilter->append (f);
+  f = new FilterNumeric (exp, "LWP", GTXT ("LWPs"));
+  f->prop_name = NTXT ("LWPID");
+  dfilter->append (f);
+  f = new FilterNumeric (exp, "cpu", GTXT ("CPUs"));
+  f->prop_name = NTXT ("CPUID");
+  dfilter->append (f);
+  f = new FilterNumeric (exp, "gcevent", GTXT ("GCEvents"));
+  f->prop_name = NTXT ("GCEVENT_MAP");
+  dfilter->append (f); // must add new numeric below
+}
+
+FilterSet::~FilterSet ()
+{
+  dfilter->destroy ();
+  delete dfilter;
+}
+
+FilterNumeric *
+FilterSet::get_filter (int index)
+{
+  if (index < dfilter->size () && index >= 0)
+    return dfilter->fetch (index);
+  return NULL;
+}
+
+char *
+FilterSet::get_advanced_filter ()
+{
+  StringBuilder sb;
+  bool filtrIsFalse = false;
+
+  if (get_enabled ())
+    {
+      Vector<FilterNumeric*> *filts = get_all_filters ();
+      if (filts == NULL)
+       return NULL;
+      for (int i = 0; i < filts->size (); i++)
+       {
+         FilterNumeric *f = filts->fetch (i);
+         if (f == NULL)
+           continue;
+         char *s = f->get_advanced_filter ();
+         if (s == NULL)
+           continue;
+         if (streq (s, NTXT ("0")))
+           {
+             free (s);
+             sb.setLength (0);
+             filtrIsFalse = true;
+             break;
+           }
+         if (sb.length () != 0)
+           sb.append (NTXT (" && "));
+         sb.append (s);
+         free (s);
+       }
+    }
+  else
+    filtrIsFalse = true;
+  if (filtrIsFalse)
+    sb.append ('0');
+  else if (sb.length () == 0)
+    return NULL;
+  return sb.toString ();
+}
+
diff --git a/gprofng/src/FilterSet.h b/gprofng/src/FilterSet.h
new file mode 100644 (file)
index 0000000..6908565
--- /dev/null
@@ -0,0 +1,72 @@
+/* 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 _FILTERSET_H
+#define _FILTERSET_H
+
+#include "dbe_types.h"
+#include "vec.h"
+
+class Experiment;
+class FilterNumeric;
+class DbeView;
+
+#define SAMPLE_FILTER_IDX 0
+#define THREAD_FILTER_IDX 1
+#define LWP_FILTER_IDX 2
+#define CPU_FILTER_IDX 3
+
+class FilterSet
+{
+public:
+
+  FilterSet (DbeView *_dbev, Experiment *_exp);
+  ~FilterSet ();
+  char *get_advanced_filter ();
+  FilterNumeric *get_filter (int);
+
+  bool
+  get_enabled ()
+  {
+    return enbl;
+  }
+
+  void
+  set_enabled (bool b)
+  {
+    enbl = b;
+  }
+
+  Vector<FilterNumeric*> *
+  get_all_filters ()
+  {
+    return dfilter;
+  }
+
+private:
+
+  DbeView *dbev;
+  Experiment *exp;
+  bool enbl;
+  Vector<FilterNumeric*> *dfilter;
+};
+
+#endif /* _FILTERSET_H */
+
diff --git a/gprofng/src/Function.cc b/gprofng/src/Function.cc
new file mode 100644 (file)
index 0000000..b0e4a8f
--- /dev/null
@@ -0,0 +1,1160 @@
+/* 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 <assert.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "demangle.h"
+#include "util.h"
+#include "DbeSession.h"
+#include "Function.h"
+#include "Module.h"
+#include "LoadObject.h"
+#include "Settings.h"
+#include "DbeFile.h"
+#include "DbeView.h"
+
+struct SrcInfo
+{
+  DbeLine *src_line;
+  SrcInfo *included_from;
+  SrcInfo *next;
+};
+
+struct PCInfo
+{
+  int64_t offset;
+  int64_t size;
+  SrcInfo *src_info;
+};
+
+Function::Function (uint64_t _id)
+{
+  id = _id;
+  instr_id = id << 32;
+  derivedNode = NULL;
+  module = NULL;
+  line_first = line_last = -1;
+  isOutlineFunction = false;
+  name = NULL;
+  mangled_name = NULL;
+  match_name = NULL;
+  comparable_name = NULL;
+  img_fname = NULL;
+  img_offset = 0;
+  chksum = 0;
+  flags = 0;
+  size = 0;
+  save_addr = FUNC_NO_SAVE;
+  linetab = NULL;
+  def_source = NULL;
+  indexStabsLink = NULL;
+  elfSym = NULL;
+  sources = NULL;
+  instrs = new Vector<DbeInstr*>;
+  addrs = NULL;
+  name_buf = NULL;
+  current_name_format = Histable::NA;
+  curr_srcinfo = NULL;
+  curr_srcfile = NULL;
+  srcinfo_list = NULL;
+  defaultDbeLine = NULL;
+  usrfunc = NULL;
+  alias = NULL;
+  instHTable = NULL;
+  addrIndexHTable = NULL;
+  isUsed = false;
+  isHideFunc = false;
+  inlinedSubr = NULL;
+  inlinedSubrCnt = 0;
+}
+
+Function::~Function ()
+{
+  free (mangled_name);
+  free (match_name);
+  free (comparable_name);
+  free (name_buf);
+  Destroy (linetab);
+  Destroy (instrs);
+
+  while (srcinfo_list)
+    {
+      SrcInfo *t = srcinfo_list;
+      srcinfo_list = t->next;
+      delete t;
+    }
+  delete sources;
+  delete addrs;
+  delete[] instHTable;
+  delete[] addrIndexHTable;
+  if (indexStabsLink)
+    // Remove a link to the current function
+    indexStabsLink->indexStabsLink = NULL;
+}
+
+char *
+Function::get_name (NameFormat nfmt)
+{
+  if (nfmt == Histable::NA)
+    {
+      DbeView *dbeView = dbeSession->getView (0);
+      if (dbeView)
+       nfmt = dbeView->get_name_format ();
+    }
+  if (name_buf && (nfmt == current_name_format || nfmt == Histable::NA))
+    return name_buf;
+  free (name_buf);
+  current_name_format = nfmt;
+
+  bool soname_fmt = Histable::soname_fmt (nfmt);
+  int fname_fmt = Histable::fname_fmt (nfmt);
+  if (fname_fmt == Histable::MANGLED)
+    name_buf = strdup (mangled_name);
+  else
+    {
+      if (module && module->is_fortran ()
+         && (streq (name, "MAIN") || streq (name, "MAIN_")))
+       name_buf = strdup (match_name);
+      else
+       name_buf = strdup (name);
+
+      if (fname_fmt == Histable::SHORT)
+       {
+         int i = get_paren (name_buf);
+         if (i != -1)
+           name_buf[i] = (char) 0;
+       }
+    }
+  if (soname_fmt)
+    {
+      char *fname = dbe_sprintf (NTXT ("%s [%s]"), name_buf, module->loadobject->get_name ());
+      free (name_buf);
+      name_buf = fname;
+    }
+  return name_buf;
+}
+
+uint64_t
+Function::get_addr ()
+{
+  LoadObject *lo = module ? module->loadobject : NULL;
+  int seg_idx = lo ? lo->seg_idx : -1;
+  return MAKE_ADDRESS (seg_idx, img_offset);
+}
+
+Histable *
+Function::convertto (Histable_type type, Histable *obj)
+{
+  Histable *res = NULL;
+  SourceFile *source = (SourceFile*) obj;
+  switch (type)
+    {
+    case INSTR:
+      res = find_dbeinstr (0, 0);
+      break;
+    case LINE:
+      {
+       // mapPCtoLine will implicitly read line info if necessary
+       res = mapPCtoLine (0, source);
+       break;
+      }
+    case FUNCTION:
+      res = this;
+      break;
+    case SOURCEFILE:
+      res = def_source;
+      break;
+    default:
+      assert (0);
+    }
+  return res;
+}
+
+void
+Function::set_name (char *string)
+{
+  if (string == NULL)
+    return;
+  set_mangled_name (string);
+
+  // strip away any globalization prefix, and save result for matching
+  char *mname = string;
+  if (strncmp (string, "$X", 2) == 0 || strncmp (string, ".X", 2) == 0)
+    {
+      // name was globalized
+      char *n = strchr (string + 2, (int) '.');
+      if (n != NULL)
+       mname = n + 1;
+    }
+  set_match_name (mname);
+  name = NULL;
+  if (module)
+    {
+      if (name == NULL && *match_name == '_')
+       {
+         int flag = DMGL_PARAMS;
+         if (module->lang_code == Sp_lang_java)
+           flag |= DMGL_JAVA;
+         name = cplus_demangle (match_name, flag);
+       }
+    }
+  if (name == NULL)     // got demangled string
+    name = dbe_strdup (match_name);
+  set_comparable_name (name);
+}
+
+void
+Function::set_mangled_name (const char *string)
+{
+  if (string)
+    {
+      free (mangled_name);
+      mangled_name = dbe_strdup (string);
+    }
+}
+
+void
+Function::set_match_name (const char *string)
+{
+  if (string)
+    {
+      free (match_name);
+      match_name = dbe_strdup (string);
+    }
+}
+
+void
+Function::set_comparable_name (const char *string)
+{
+  if (string)
+    {
+      free (comparable_name);
+      comparable_name = dbe_strdup (string);
+
+      // remove blanks from comparable_name
+      for (char *s = comparable_name, *s1 = comparable_name;;)
+       {
+         if (*s == 0)
+           {
+             *s1 = 0;
+             break;
+           }
+         else if (*s != ' ')
+           {
+             *s1 = *s;
+             s1++;
+           }
+         s++;
+       }
+    }
+}
+
+//  This function looks at the name of a function, and determines whether
+//     or not it may be a derived function -- outline, mtask, or clone --
+//     If it is, it writes the function name as demangled,
+//     and sets a pointer to the function from which it was derived
+void
+Function::findDerivedFunctions ()
+
+{
+  MPFuncTypes ftype;
+  int index;
+  Function *fitem;
+  unsigned long long line_no;
+  char *namefmt;
+  char *subname = mangled_name;
+  char *demname;
+
+  // see if we've already done this
+  if ((flags & FUNC_FLAG_RESDER) != 0)
+      return;
+
+  // set flag for future
+  flags = flags | FUNC_FLAG_RESDER;
+  if (module == NULL)
+    return;
+  if (*subname != '_' || subname[1] != '$')   // Not a specially named function
+    return;
+
+  // look for the current versions of naming
+  if (strncmp (subname + 2, NTXT ("d1"), 2) == 0)    // doall function
+    ftype = MPF_DOALL;
+  else if (strncmp (subname + 2, "p1", 2) == 0)     // parallel region function
+    ftype = MPF_PAR;
+  else if (strncmp (subname + 2, "l1", 2) == 0)     // single thread loop setup
+    ftype = MPF_DOALL;
+  else if (strncmp (subname + 2, "s1", 2) == 0)     // parallel section function
+    ftype = MPF_SECT;
+  else if (strncmp (subname + 2, "t1", 2) == 0)     // task function
+    ftype = MPF_TASK;
+  else if (strncmp (subname + 2, "o1", 2) == 0)     // outline function
+    {
+      ftype = MPF_OUTL;
+      isOutlineFunction = true;
+   }
+  else if (strncmp (subname + 2, "c1", 2) == 0)     // clone function
+    ftype = MPF_CLONE;
+  else    // Not an encoded name, just return
+    return;
+
+  // we know it's one of the above prefixes
+  char *sub = dbe_strdup (name + 4); // starting with base-26 number
+  char *p = sub;
+
+  // skip the base-26 number, and extract the line number
+  while (isalpha ((int) (*p)) != 0 && *p != 0)
+    p++;
+  line_no = atoll (p);
+
+  // skip past the number to to the .
+  while (*p != '.' && *p != 0)
+    p++;
+  if (*p == 0)
+    {
+      // can't be right
+      free (sub);
+      return;
+    }
+  // skip the trailing .
+  p++;
+  subname = p;
+  bool foundmatch = false;
+
+  // Find the function from which it is derived -- the one that matched subname
+  Vec_loop (Function*, module->functions, index, fitem)
+  {
+    if (streq (subname, fitem->mangled_name))
+      { // found it
+       foundmatch = true;
+       usrfunc = fitem;
+
+       // set the derived node
+       if ((fitem->flags & FUNC_FLAG_RESDER) == 0)
+         // ensure that it, too, is resolved if derived
+         fitem->findDerivedFunctions ();
+
+       // Build a demangled name
+       switch (ftype)
+         {
+         case MPF_OUTL:
+           isOutlineFunction = true;
+           namefmt = GTXT ("%s -- outline code from line %lld [%s]");
+           derivedNode = fitem->find_dbeinstr (PCLineFlag, line_no);
+           break;
+         case MPF_PAR:
+           namefmt = GTXT ("%s -- OMP parallel region from line %lld [%s]");
+           break;
+         case MPF_DOALL:
+           namefmt = GTXT ("%s -- Parallel loop from line %lld [%s]");
+           break;
+         case MPF_SECT:
+           namefmt = GTXT ("%s -- OMP sections from line %lld [%s]");
+           break;
+         case MPF_CLONE:
+           // Note that clones are handled differently -- no line number and
+           //  clones are NOT shown as called from the original
+           //  so after constructing the name, just return
+           //  later, establish link from clone to parent
+           demname = dbe_sprintf (GTXT ("%s -- cloned version [%s]"),
+                                  fitem->get_name (), name);
+           free (name);
+           // set the name to the demangled version
+           name = demname;
+           free (sub);
+           derivedNode = fitem->find_dbeinstr (PCLineFlag, line_no);
+           return;
+         case MPF_TASK:
+           namefmt = GTXT ("%s -- OMP task from line %lld [%s]");
+           break;
+         default:
+           free (sub);
+           return;
+
+         }
+
+       // Finally, construct the demangled name
+       demname = dbe_sprintf (namefmt, fitem->get_name (), line_no, name);
+       free (name);
+       name = demname;
+       setLineFirst ((int) line_no);
+       break;
+      }
+  }
+
+  if (foundmatch == false && ftype == MPF_OUTL)
+    {
+      // Even if derived node was not found, we can demangle
+      demname = dbe_sprintf (GTXT ("%s -- outline code [%s]"), subname,
+                            mangled_name);
+      free (name);
+      name = demname;
+    }
+  free (sub);
+}
+
+SrcInfo *
+Function::new_srcInfo ()
+{
+  SrcInfo *t = new SrcInfo ();
+  t->next = srcinfo_list;
+  srcinfo_list = t;
+  return t;
+}
+
+void
+Function::pushSrcFile (SourceFile* source, int /*lineno*/)
+{
+  // create new file stack
+  if (curr_srcfile == NULL)
+    {
+      curr_srcfile = source;
+      return;
+    }
+
+  SrcInfo *src_info = new_srcInfo ();
+  // In the ideal world, we need a DbeLine(III) here,
+  // but right now it would make us later believe that there are
+  // instructions generated for #include lines. To avoid that,
+  // we ask for a DbeLine(II).
+  src_info->src_line = curr_srcfile->find_dbeline (this, 0 /*lineno*/);
+  if (src_info->src_line)
+    {
+      src_info->included_from = curr_srcinfo;
+      curr_srcinfo = src_info;
+    }
+  curr_srcfile = source;
+  setSource ();
+}
+
+SourceFile *
+Function::popSrcFile ()
+{
+  if (curr_srcinfo != NULL)
+    {
+      curr_srcfile = curr_srcinfo->src_line->sourceFile;
+      curr_srcinfo = curr_srcinfo->included_from;
+    }
+  else
+    curr_srcfile = NULL;
+  return curr_srcfile;
+}
+
+void
+Function::copy_PCInfo (Function *from)
+{
+  if (line_first <= 0)
+    line_first = from->line_first;
+  if (line_last <= 0)
+    line_last = from->line_last;
+  if (def_source == NULL)
+    def_source = from->def_source;
+  for (int i = 0, sz = from->linetab ? from->linetab->size () : 0; i < sz; i++)
+    {
+      PCInfo *pcinf = from->linetab->fetch (i);
+      DbeLine *dbeLine = pcinf->src_info->src_line;
+      add_PC_info (pcinf->offset, dbeLine->lineno, dbeLine->sourceFile);
+    }
+}
+
+void
+Function::add_PC_info (uint64_t offset, int lineno, SourceFile *cur_src)
+{
+  if (lineno <= 0 || size < 0 || offset >= (uint64_t) size)
+    return;
+  if (cur_src == NULL)
+    cur_src = curr_srcfile ? curr_srcfile : def_source;
+  if (linetab == NULL)
+    linetab = new Vector<PCInfo*>;
+
+  int left = 0;
+  int right = linetab->size () - 1;
+  DbeLine *dbeline;
+  while (left <= right)
+    {
+      int x = (left + right) / 2;
+      PCInfo *pcinf = linetab->fetch (x);
+      uint64_t pcinf_offset = ((uint64_t) pcinf->offset);
+      if (offset == pcinf_offset)
+       {
+         dbeline = cur_src->find_dbeline (this, lineno);
+         dbeline->init_Offset (offset);
+         pcinf->src_info->src_line = dbeline;
+         // Ignore duplicate offset
+         return;
+       }
+      else if (offset > pcinf_offset)
+       left = x + 1;
+      else
+       right = x - 1;
+    }
+  PCInfo *pcinfo = new PCInfo;
+  pcinfo->offset = offset;
+
+  // Form new SrcInfo
+  SrcInfo *srcInfo = new_srcInfo ();
+  dbeline = cur_src->find_dbeline (this, lineno);
+  dbeline->init_Offset (offset);
+  srcInfo->src_line = dbeline;
+  // For now don't build included_from list.
+  // We need better compiler support for that.
+  //srcInfo->included_from = curr_srcinfo;
+  srcInfo->included_from = NULL;
+  pcinfo->src_info = srcInfo;
+
+  // Update the size of the current line in both structures:
+  // current PCInfo and corresponding DbeLine.
+  if (left < linetab->size ())
+    pcinfo->size = linetab->fetch (left)->offset - offset;
+  else
+    pcinfo->size = size - offset;
+  pcinfo->src_info->src_line->size += pcinfo->size;
+
+  // If not the first line, update the size of the previous line
+  if (left > 0)
+    {
+      PCInfo *pcinfo_prev = linetab->fetch (left - 1);
+      int64_t delta = (offset - pcinfo_prev->offset) - pcinfo_prev->size;
+      pcinfo_prev->size += delta;
+      pcinfo_prev->src_info->src_line->size += delta;
+    }
+
+  linetab->insert (left, pcinfo);
+  if (cur_src == def_source)
+    {
+      if (line_first <= 0)
+       setLineFirst (lineno);
+      if (line_last <= 0 || lineno > line_last)
+       line_last = lineno;
+    }
+}
+
+PCInfo *
+Function::lookup_PCInfo (uint64_t offset)
+{
+  module->read_stabs ();
+  if (linetab == NULL)
+    linetab = new Vector<PCInfo*>;
+
+  int left = 0;
+  int right = linetab->size () - 1;
+  while (left <= right)
+    {
+      int x = (left + right) / 2;
+      PCInfo *pcinfo = linetab->fetch (x);
+      if (offset >= ((uint64_t) pcinfo->offset))
+       {
+         if (offset < (uint64_t) (pcinfo->offset + pcinfo->size))
+           return pcinfo;
+         left = x + 1;
+       }
+      else
+       right = x - 1;
+    }
+  return NULL;
+}
+
+DbeInstr*
+Function::mapLineToPc (DbeLine *dbeLine)
+{
+  if (dbeLine && linetab)
+    {
+      DbeLine *dbl = dbeLine->dbeline_base;
+      for (int i = 0, sz = linetab->size (); i < sz; i++)
+       {
+         PCInfo *pcinfo = linetab->get (i);
+         if (pcinfo->src_info
+             && (pcinfo->src_info->src_line->dbeline_base == dbl))
+           {
+             DbeInstr *dbeInstr = find_dbeinstr (PCLineFlag, pcinfo->offset);
+             if (dbeInstr)
+               {
+                 dbeInstr->lineno = dbeLine->lineno;
+                 return dbeInstr;
+               }
+           }
+       }
+    }
+  return NULL;
+}
+
+DbeLine*
+Function::mapPCtoLine (uint64_t addr, SourceFile *src)
+{
+  PCInfo *pcinfo = lookup_PCInfo (addr);
+  if (pcinfo == NULL)
+    {
+      if (defaultDbeLine == NULL)
+       defaultDbeLine = getDefSrc ()->find_dbeline (this, 0);
+      return defaultDbeLine;
+    }
+  DbeLine *dbeline = pcinfo->src_info->src_line;
+
+  // If source-context is not specified return the line
+  // from which this pc has been generated.
+  if (src == NULL)
+    return dbeline;
+  if (dbeline->sourceFile == src)
+    return dbeline->dbeline_base;
+  return src->find_dbeline (this, 0);
+}
+
+DbeInstr *
+Function::find_dbeinstr (int flag, uint64_t addr)
+{
+  DbeInstr *instr;
+
+  enum
+  {
+    FuncInstHTableSize = 128
+  };
+
+  int hash = (((int) addr) >> 2) & (FuncInstHTableSize - 1);
+  if (instHTable == NULL)
+    {
+      if (size > 2048)
+       {
+         instHTable = new DbeInstr*[FuncInstHTableSize];
+         for (int i = 0; i < FuncInstHTableSize; i++)
+           instHTable[i] = NULL;
+       }
+    }
+  else
+    {
+      instr = instHTable[hash];
+      if (instr && instr->addr == addr && instr->flags == flag)
+       return instr;
+    }
+
+  int left = 0;
+  int right = instrs->size () - 1;
+  while (left <= right)
+    {
+      int index = (left + right) / 2;
+      instr = instrs->fetch (index);
+      if (addr < instr->addr)
+       right = index - 1;
+      else if (addr > instr->addr)
+       left = index + 1;
+      else
+       {
+         if (flag == instr->flags)
+           {
+             if (instHTable)
+               instHTable[hash] = instr;
+             return instr;
+           }
+         else if (flag < instr->flags)
+           right = index - 1;
+         else
+           left = index + 1;
+       }
+    }
+
+  // None found, create a new one
+  instr = new DbeInstr (instr_id++, flag, this, addr);
+  instrs->insert (left, instr);
+  if (instHTable)
+    instHTable[hash] = instr;
+  return instr;
+}
+
+// LIBRARY_VISIBILITY
+DbeInstr *
+Function::create_hide_instr (DbeInstr *instr)
+{
+  DbeInstr *new_instr = new DbeInstr (instr_id++, 0, this, instr->addr);
+  return new_instr;
+}
+
+uint64_t
+Function::find_previous_addr (uint64_t addr)
+{
+  if (addrs == NULL)
+    {
+      addrs = module->getAddrs (this);
+      if (addrs == NULL)
+       return addr;
+    }
+
+  int index = -1, not_found = 1;
+
+  enum
+  {
+    FuncAddrIndexHTableSize = 128
+  };
+  int hash = (((int) addr) >> 2) & (FuncAddrIndexHTableSize - 1);
+  if (addrIndexHTable == NULL)
+    {
+      if (size > 2048)
+       {
+         addrIndexHTable = new int[FuncAddrIndexHTableSize];
+         for (int i = 0; i < FuncAddrIndexHTableSize; i++)
+           addrIndexHTable[i] = -1;
+       }
+    }
+  else
+    {
+      index = addrIndexHTable[hash];
+      if (index >= 0 && addrs->fetch (index) == addr)
+       not_found = 0;
+    }
+
+  int left = 0;
+  int right = addrs->size () - 1;
+  while (not_found && left <= right)
+    {
+      index = (left + right) / 2;
+      uint64_t addr_test = addrs->fetch (index);
+      if (addr < addr_test)
+       right = index - 1;
+      else if (addr > addr_test)
+       left = index + 1;
+      else
+       {
+         if (addrIndexHTable)
+           addrIndexHTable[hash] = index;
+         not_found = 0;
+       }
+    }
+  if (not_found)
+    return addr;
+  if (index > 0)
+    index--;
+  return addrs->fetch (index);
+}
+
+void
+Function::setSource ()
+{
+  SourceFile *sf = module->getIncludeFile ();
+  if (sf == NULL)
+    sf = getDefSrc ();
+  if (def_source == NULL)
+    setDefSrc (sf);
+  if (sf == def_source)
+    return;
+  if (sources == NULL)
+    {
+      sources = new Vector<SourceFile*>;
+      sources->append (def_source);
+      sources->append (sf);
+    }
+  else if (sources->find (sf) < 0)
+    sources->append (sf);
+}
+
+void
+Function::setDefSrc (SourceFile *sf)
+{
+  if (sf)
+    {
+      def_source = sf;
+      if (line_first > 0)
+       add_PC_info (0, line_first, def_source);
+    }
+}
+
+void
+Function::setLineFirst (int lineno)
+{
+  if (lineno > 0)
+    {
+      line_first = lineno;
+      if (line_last <= 0)
+       line_last = lineno;
+      if (def_source)
+       add_PC_info (0, line_first, def_source);
+    }
+}
+
+Vector<SourceFile*> *
+Function::get_sources ()
+{
+  if (module)
+    module->read_stabs ();
+  if (sources == NULL)
+    {
+      sources = new Vector<SourceFile*>;
+      sources->append (getDefSrc ());
+    }
+  return sources;
+}
+
+SourceFile*
+Function::getDefSrc ()
+{
+  if (module)
+    module->read_stabs ();
+  if (def_source == NULL)
+    setDefSrc (module->getMainSrc ());
+  return def_source;
+}
+
+char *
+Function::getDefSrcName ()
+{
+  SourceFile *sf = getDefSrc ();
+  if (sf)
+    return sf->dbeFile->getResolvedPath ();
+  if (module)
+    return module->file_name;
+  sf = dbeSession->get_Unknown_Source ();
+  return sf->get_name ();
+}
+
+#define cmpValue(a, b) ((a) > (b) ? 1 : (a) == (b) ? 0 : -1)
+
+int
+Function::func_cmp (Function *func, SourceFile *srcContext)
+{
+  if (def_source != func->def_source)
+    {
+      if (srcContext == NULL)
+       srcContext = getDefSrc ();
+      if (def_source == srcContext)
+       return -1;
+      if (func->def_source == srcContext)
+       return 1;
+      return cmpValue (img_offset, func->img_offset);
+    }
+
+  if (line_first == func->line_first)
+    return cmpValue (img_offset, func->img_offset);
+  if (line_first <= 0)
+    {
+      if (func->line_first > 0)
+       return 1;
+      return cmpValue (img_offset, func->img_offset);
+    }
+  if (func->line_first <= 0)
+    return -1;
+  return cmpValue (line_first, func->line_first);
+}
+
+Vector<Histable*> *
+Function::get_comparable_objs ()
+{
+  update_comparable_objs ();
+  if (comparable_objs || dbeSession->expGroups->size () <= 1 || module == NULL)
+    return comparable_objs;
+  if (module == NULL || module->loadobject == NULL)
+    return NULL;
+  Vector<Histable*> *comparableModules = module->get_comparable_objs ();
+  if (comparableModules == NULL)
+    {
+      return NULL;
+    }
+  comparable_objs = new Vector<Histable*>(comparableModules->size ());
+  for (long i = 0, sz = comparableModules->size (); i < sz; i++)
+    {
+      Function *func = NULL;
+      comparable_objs->store (i, func);
+      Module *mod = (Module*) comparableModules->fetch (i);
+      if (mod == NULL)
+       continue;
+      if (mod == module)
+       func = this;
+      else
+       {
+         for (long i1 = 0, sz1 = VecSize (mod->functions); i1 < sz1; i1++)
+           {
+             Function *f = mod->functions->get (i1);
+             if ((f->comparable_objs == NULL)
+                  && (strcmp (f->comparable_name, comparable_name) == 0))
+               {
+                 func = f;
+                 func->comparable_objs = comparable_objs;
+                 break;
+               }
+           }
+       }
+      comparable_objs->store (i, func);
+    }
+  Vector<Histable*> *comparableLoadObjs =
+         module->loadobject->get_comparable_objs ();
+  if (VecSize (comparableLoadObjs) == VecSize (comparable_objs))
+    {
+      for (long i = 0, sz = VecSize (comparableLoadObjs); i < sz; i++)
+       {
+         LoadObject *lo = (LoadObject *) comparableLoadObjs->get (i);
+         Function *func = (Function *) comparable_objs->get (i);
+         if (func || (lo == NULL))
+           continue;
+         if (module->loadobject == lo)
+           func = this;
+         else
+           {
+             for (long i1 = 0, sz1 = VecSize (lo->functions); i1 < sz1; i1++)
+               {
+                 Function *f = lo->functions->fetch (i1);
+                 if ((f->comparable_objs == NULL)
+                      && (strcmp (f->comparable_name, comparable_name) == 0))
+                   {
+                     func = f;
+                     func->comparable_objs = comparable_objs;
+                     break;
+                   }
+               }
+           }
+         comparable_objs->store (i, func);
+       }
+    }
+  dump_comparable_objs ();
+  return comparable_objs;
+}
+
+JMethod::JMethod (uint64_t _id) : Function (_id)
+{
+  mid = 0LL;
+  addr = (Vaddr) 0;
+  signature = NULL;
+  jni_function = NULL;
+}
+
+JMethod::~JMethod ()
+{
+  free (signature);
+}
+
+uint64_t
+JMethod::get_addr ()
+{
+  if (addr != (Vaddr) 0)
+    return addr;
+  else
+    return Function::get_addr ();
+}
+
+typedef struct
+{
+  size_t used_in;
+  size_t used_out;
+} MethodField;
+
+static void
+write_buf (char* buf, char* str)
+{
+  while ((*buf++ = *str++));
+}
+
+/** Translate one field from the nane buffer.
+ * return how many chars were read from name and how many bytes were used in buf.
+ */
+static MethodField
+translate_method_field (const char* name, char* buf)
+{
+  MethodField out, t;
+  switch (*name)
+    {
+    case 'L':
+      name++;
+      out.used_in = 1;
+      out.used_out = 0;
+      while (*name != ';')
+       {
+         *buf = *name++;
+         if (*buf == '/')
+           *buf = '.';
+         buf++;
+         out.used_in++;
+         out.used_out++;
+       }
+      out.used_in++; /* the ';' is also used. */
+      break;
+    case 'Z':
+      write_buf (buf, NTXT ("boolean"));
+      out.used_out = 7;
+      out.used_in = 1;
+      break;
+    case 'B':
+      write_buf (buf, NTXT ("byte"));
+      out.used_out = 4;
+      out.used_in = 1;
+      break;
+    case 'C':
+      write_buf (buf, NTXT ("char"));
+      out.used_out = 4;
+      out.used_in = 1;
+      break;
+    case 'S':
+      write_buf (buf, NTXT ("short"));
+      out.used_out = 5;
+      out.used_in = 1;
+      break;
+    case 'I':
+      write_buf (buf, NTXT ("int"));
+      out.used_out = 3;
+      out.used_in = 1;
+      break;
+    case 'J':
+      write_buf (buf, NTXT ("long"));
+      out.used_out = 4;
+      out.used_in = 1;
+      break;
+    case 'F':
+      write_buf (buf, NTXT ("float"));
+      out.used_out = 5;
+      out.used_in = 1;
+      break;
+    case 'D':
+      write_buf (buf, NTXT ("double"));
+      out.used_out = 6;
+      out.used_in = 1;
+      break;
+    case 'V':
+      write_buf (buf, NTXT ("void"));
+      out.used_out = 4;
+      out.used_in = 1;
+      break;
+    case '[':
+      t = translate_method_field (name + 1, buf);
+      write_buf (buf + t.used_out, NTXT ("[]"));
+      out.used_out = t.used_out + 2;
+      out.used_in = t.used_in + 1;
+      break;
+    default:
+      out.used_out = 0;
+      out.used_in = 0;
+    }
+  return out;
+}
+
+/**
+ * translate method name to full method signature
+ * into the output buffer (buf).
+ * ret_type - true for printing result type
+ */
+static bool
+translate_method (char* mname, char *signature, bool ret_type, char* buf)
+{
+  MethodField p;
+  size_t l;
+  int first = 1;
+  if (signature == NULL)
+    return false;
+
+  const char *c = strchr (signature, ')');
+  if (c == NULL)
+    return false;
+  if (ret_type)
+    {
+      p = translate_method_field (++c, buf);
+      buf += p.used_out;
+      *buf++ = ' ';
+    }
+
+  l = strlen (mname);
+  memcpy (buf, mname, l + 1);
+  buf += l;
+  // *buf++ = ' '; // space before ()
+  *buf++ = '(';
+
+  c = signature + 1;
+  while (*c != ')')
+    {
+      if (!first)
+       {
+         *buf++ = ',';
+         *buf++ = ' ';
+       }
+      first = 0;
+      p = translate_method_field (c, buf);
+      c += p.used_in;
+      buf += p.used_out;
+    }
+
+  *buf++ = ')';
+  *buf = '\0';
+  return true;
+}
+
+void
+JMethod::set_name (char *string)
+{
+  if (string == NULL)
+    return;
+  set_mangled_name (string);
+
+  char buf[MAXDBUF];
+  *buf = '\0';
+  if (translate_method (string, signature, false, buf))
+    {
+      name = dbe_strdup (buf); // got translated string
+      Dprintf (DUMP_JCLASS_READER,
+             "JMethod::set_name: true name=%s string=%s signature=%s\n",
+              STR (name), STR (string), STR (signature));
+    }
+  else
+    {
+      name = dbe_strdup (string);
+      Dprintf (DUMP_JCLASS_READER,
+              "JMethod::set_name: false name=%s signature=%s\n",
+              STR (name), STR (signature));
+    }
+  set_match_name (name);
+  set_comparable_name (name);
+}
+
+bool
+JMethod::jni_match (Function *func)
+{
+  if (func == NULL || (func->flags & FUNC_NOT_JNI) != 0)
+    return false;
+  if (jni_function == func)
+    return true;
+
+  char *fname = func->get_name ();
+  if ((func->flags & FUNC_JNI_CHECKED) == 0)
+    {
+      func->flags |= FUNC_JNI_CHECKED;
+      if (strncmp (func->get_name (), NTXT ("Java_"), 5) != 0)
+       {
+         func->flags |= FUNC_NOT_JNI;
+         return false;
+       }
+    }
+
+  char *d = name;
+  char *s = fname + 5;
+  while (*d && *d != '(' && *d != ' ')
+    {
+      if (*d == '.')
+       {
+         if (*s++ != '_')
+           return false;
+         d++;
+       }
+      else if (*d == '_')
+       {
+         if (*s++ != '_')
+           return false;
+         if (*s++ != '1')
+           return false;
+         d++;
+       }
+      else if (*d++ != *s++)
+       return false;
+    }
+  jni_function = func;
+  return true;
+}
diff --git a/gprofng/src/Function.h b/gprofng/src/Function.h
new file mode 100644 (file)
index 0000000..b0a856b
--- /dev/null
@@ -0,0 +1,222 @@
+/* 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 _DBE_FUNCTION_H
+#define _DBE_FUNCTION_H
+
+// A Function object represents an individual function in a .o file.
+
+#include "util.h"
+#include "Histable.h"
+#include "SourceFile.h"
+
+class Module;
+class Symbol;
+class InlinedSubr;
+struct SrcInfo;
+struct PCInfo;
+template <class ITEM> class Vector;
+
+const uint64_t FUNC_NO_SAVE = (uint64_t) - 1;
+const uint64_t FUNC_ROOT = (uint64_t) - 2;
+
+enum
+{
+  FUNC_FLAG_PLT = 1,
+  FUNC_FLAG_DYNAMIC = 2,
+  FUNC_FLAG_RESDER = 4, // set if derived function resolution has been done
+  FUNC_FLAG_NO_OFFSET = 8, // set if disassembly should not show offset from function
+  FUNC_FLAG_SIMULATED = 16, // not a real function like <Total>, <Unknown>, etc.
+  FUNC_FLAG_NATIVE = 32, // no byte code for JMethod
+  FUNC_NOT_JNI = 64, // a function name is not "Java_..."
+  FUNC_JNI_CHECKED = 128 // already checked for "Java_..."
+};
+
+const int MAXDBUF = 32768; // the longest demangled name handled
+
+class Function : public Histable
+{
+public:
+
+  enum MPFuncTypes
+  {
+    MPF_DOALL,
+    MPF_PAR,
+    MPF_SECT,
+    MPF_TASK,
+    MPF_CLONE,
+    MPF_OUTL
+  };
+
+  Function (uint64_t _id);
+  virtual ~Function ();
+
+  virtual uint64_t get_addr ();
+  virtual char *get_name (NameFormat = NA);
+  virtual Vector<Histable*> *get_comparable_objs ();
+  virtual void set_name (char *);   // Set the demangled name
+  virtual Histable *convertto (Histable_type type, Histable *obj = NULL);
+
+  virtual Histable_type
+  get_type ()
+  {
+    return FUNCTION;
+  };
+
+  virtual int64_t
+  get_size ()
+  {
+    return size;
+  };
+
+  void set_comparable_name (const char *string);
+  void set_mangled_name (const char *string);
+  void set_match_name (const char *string);
+
+  // Find any derived functions, and set their derivedNode
+  void findDerivedFunctions ();
+  void findKrakatoaDerivedFunctions ();
+  void add_PC_info (uint64_t offset, int lineno, SourceFile *cur_src = NULL);
+  void pushSrcFile (SourceFile* source, int lineno);
+  SourceFile *popSrcFile ();
+  int func_cmp (Function *func, SourceFile *srcContext = NULL);
+  void copy_PCInfo (Function *f);
+  DbeLine *mapPCtoLine (uint64_t addr, SourceFile *src = NULL);
+  DbeInstr *mapLineToPc (DbeLine *dbeLine);
+  DbeInstr *find_dbeinstr (int flag, uint64_t addr);
+  DbeInstr *create_hide_instr (DbeInstr *instr);
+  uint64_t find_previous_addr (uint64_t addr);
+  SourceFile *getDefSrc ();
+  char *getDefSrcName ();
+  void setDefSrc (SourceFile *sf);
+  void setLineFirst (int lineno);
+  Vector<SourceFile*> *get_sources ();
+
+  char *
+  get_mangled_name ()
+  {
+    return mangled_name;
+  }
+
+  char *
+  get_match_name ()
+  {
+    return match_name;
+  }
+
+  inline Function *
+  cardinal ()
+  {
+    return alias ? alias : this;
+  }
+
+  unsigned int flags;       // FUNC_FLAG_*
+  Module *module;           // pointer to module containing source
+  int line_first;           // range of line numbers for function
+  int line_last;
+  int64_t size;             // size of the function in bytes
+  uint64_t save_addr;       // used for detection of leaf routines
+  DbeInstr *derivedNode;    // If derived from another function
+  bool isOutlineFunction;   // if outline (save assumed)
+  unsigned int chksum;      // check sum of instructions
+  char *img_fname;          // file containing function image
+  uint64_t img_offset;      // file offset of the image
+  SourceFile *curr_srcfile;
+  DbeLine *defaultDbeLine;
+  Function *usrfunc;        // User function
+  Function *alias;
+  bool isUsed;
+  bool isHideFunc;
+  SourceFile *def_source;
+  Function *indexStabsLink; // correspondent function for the .o file
+  Symbol *elfSym;
+  InlinedSubr *inlinedSubr;
+  int inlinedSubrCnt;
+
+private:
+  DbeInstr **instHTable;    // hash table for DbeInstr
+  int *addrIndexHTable;     // hash table for addrs index
+  void setSource ();
+  PCInfo *lookup_PCInfo (uint64_t offset);
+  SrcInfo *new_srcInfo ();
+
+  char *mangled_name;
+  char *match_name;      // mangled name, with globalization stripped
+  char *comparable_name; // demangled name, with globalization and blanks stripped
+  char *name_buf;
+  NameFormat current_name_format;
+  Vector<PCInfo*> *linetab;
+  Vector<DbeInstr*> *instrs;
+  Vector<uint64_t> *addrs;
+  uint64_t instr_id;
+  Vector<SourceFile*> *sources;
+  SrcInfo *curr_srcinfo;    // the current source stack of the function
+  SrcInfo *srcinfo_list;    // master list for SrcInfo
+};
+
+class JMethod : public Function
+{
+public:
+  JMethod (uint64_t _id);
+  virtual ~JMethod ();
+  virtual void set_name (char *);
+  virtual uint64_t get_addr ();
+
+  void
+  set_addr (Vaddr _addr)
+  {
+    addr = _addr;
+  }
+
+  uint64_t
+  get_mid ()
+  {
+    return mid;
+  }
+
+  void
+  set_mid (uint64_t _mid)
+  {
+    mid = _mid;
+  }
+
+  char *
+  get_signature ()
+  {
+    return signature;
+  }
+
+  void
+  set_signature (const char *s)
+  {
+    signature = dbe_strdup (s);
+  }
+
+  // Returns true if func's name matches method's as its JNI implementation
+  bool jni_match (Function *func);
+
+private:
+  uint64_t mid;
+  Vaddr addr;
+  char *signature;
+  Function *jni_function;
+};
+
+#endif /* _DBE_FUNCTION_H */
diff --git a/gprofng/src/HashMap.h b/gprofng/src/HashMap.h
new file mode 100644 (file)
index 0000000..f66a6fe
--- /dev/null
@@ -0,0 +1,435 @@
+/* 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.  */
+
+// java.util.HashMap
+
+#ifndef _DBE_HASHMAP_H
+#define _DBE_HASHMAP_H
+
+#include "vec.h"
+#include "util.h"
+#include "StringBuilder.h"
+#include "Histable.h"
+#include "MemObject.h"
+
+template <typename Key_t> inline int get_hash_code (Key_t a);
+template <typename Key_t> inline bool is_equals (Key_t a, Key_t b);
+template <typename Key_t> inline Key_t copy_key (Key_t a);
+template <typename Key_t> inline void delete_key (Key_t a);
+
+// Specialization for char*
+template<> inline int
+get_hash_code (char *a)
+{
+  return (int) (crc64 (a, strlen (a)) & 0x7fffffff);
+}
+
+template<> inline bool
+is_equals (char *a, char *b)
+{
+  return dbe_strcmp (a, b) == 0;
+}
+
+template<> inline char *
+copy_key (char *a)
+{
+  return dbe_strdup (a);
+}
+
+template<> inline void
+delete_key (char *a)
+{
+  return free (a);
+}
+
+template<> inline int
+get_hash_code (uint64_t a)
+{
+  return (int) (a & 0x7fffffff);
+}
+
+template<> inline bool
+is_equals (uint64_t a, uint64_t b)
+{
+  return a == b;
+}
+
+template<> inline uint64_t
+copy_key (uint64_t a)
+{
+  return a;
+}
+
+template<> inline void
+delete_key (uint64_t a)
+{
+  a = a;
+}
+
+template<> inline int
+get_hash_code (Histable* a)
+{
+  return (int) (a->id & 0x7fffffff);
+}
+
+template<> inline bool
+is_equals (Histable* a, Histable* b)
+{
+  return a == b;
+}
+
+template<> inline Histable*
+copy_key (Histable* a)
+{
+  return a;
+}
+
+template<> inline void
+delete_key (Histable* a)
+{
+  a->id = a->id;
+}
+
+template<> inline int
+get_hash_code (MemObj* a)
+{
+  return (int) (a->id & 0x7fffffff);
+}
+
+template<> inline bool
+is_equals (MemObj* a, MemObj* b)
+{
+  return a == b;
+}
+
+template<> inline MemObj*
+copy_key (MemObj* a)
+{
+  return a;
+}
+
+template<> inline void
+delete_key (MemObj* a)
+{
+  a->id = a->id;
+}
+
+template <typename Key_t, typename Value_t>
+class HashMap
+{
+public:
+  HashMap (int initialCapacity = 0);
+
+  ~HashMap ()
+  {
+    clear ();
+    delete vals;
+    delete[] hashTable;
+  }
+
+  Value_t put (Key_t key, Value_t val);
+  Value_t get (Key_t key);
+  Value_t get (Key_t key, Value_t val); // Create a new map if key is not here
+  void clear ();
+  Value_t remove (Key_t);
+  Vector<Value_t> *values (Key_t key);  // Return a list of values for 'key'
+
+  bool
+  containsKey (Key_t key)
+  {
+    Value_t p = get (key);
+    return p != NULL;
+  };
+
+  Vector<Value_t> *
+  values ()
+  {
+    return vals;
+  }
+
+  void
+  reset ()
+  {
+    clear ();
+  }
+
+  int
+  get_phaseIdx ()
+  {
+    return phaseIdx;
+  }
+
+  void
+  set_phaseIdx (int phase)
+  {
+    if (phase == 0) clear ();
+    phaseIdx = phase;
+  }
+  char *dump ();
+
+private:
+
+  enum
+  {
+    HASH_SIZE       = 511,
+    MAX_HASH_SIZE   = 1048575
+  };
+
+  typedef struct Hash
+  {
+    Key_t key;
+    Value_t val;
+    struct Hash *next;
+  } Hash_t;
+
+  void resize ();
+
+  int
+  hashCode (Key_t key)
+  {
+    return get_hash_code (key) % hash_sz;
+  }
+
+  bool
+  equals (Key_t a, Key_t b)
+  {
+    return is_equals (a, b);
+  }
+
+  Key_t
+  copy (Key_t key)
+  {
+    return copy_key (key);
+  }
+
+  Hash_t **hashTable;
+  Vector<Value_t> *vals;
+  int phaseIdx;
+  int hash_sz;
+  int nelem;
+};
+
+template <typename Key_t, typename Value_t>
+HashMap<Key_t, Value_t>
+::HashMap (int initialCapacity)
+{
+  if (initialCapacity > 0)
+    vals = new Vector<Value_t>(initialCapacity);
+  else
+    vals = new Vector<Value_t>();
+  phaseIdx = 0;
+  nelem = 0;
+  hash_sz = HASH_SIZE;
+  hashTable = new Hash_t*[hash_sz];
+  for (int i = 0; i < hash_sz; i++)
+    hashTable[i] = NULL;
+}
+
+template <typename Key_t, typename Value_t>
+void
+HashMap<Key_t, Value_t>::clear ()
+{
+  vals->reset ();
+  phaseIdx = 0;
+  nelem = 0;
+  for (int i = 0; i < hash_sz; i++)
+    {
+      Hash_t *next;
+      for (Hash_t *p = hashTable[i]; p; p = next)
+       {
+         next = p->next;
+         delete_key (p->key);
+         delete p;
+       }
+      hashTable[i] = NULL;
+    }
+}
+
+template <typename Key_t, typename Value_t>
+void
+HashMap<Key_t, Value_t>::resize ()
+{
+  int old_hash_sz = hash_sz;
+  hash_sz = old_hash_sz * 2 + 1;
+  Hash_t **old_hash_table = hashTable;
+  hashTable = new Hash_t*[hash_sz];
+  for (int i = 0; i < hash_sz; i++)
+    hashTable[i] = NULL;
+  nelem = 0;
+  for (int i = 0; i < old_hash_sz; i++)
+    {
+      if (old_hash_table[i] != NULL)
+       {
+         Hash_t *old_p;
+         Hash_t *p = old_hash_table[i];
+         while (p != NULL)
+           {
+             put (p->key, p->val);
+             old_p = p;
+             p = p->next;
+             delete old_p;
+           }
+       }
+    }
+  delete[] old_hash_table;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+HashMap<Key_t, Value_t>::get (Key_t key)
+{
+  int hash_code = hashCode (key);
+  for (Hash_t *p = hashTable[hash_code]; p; p = p->next)
+    if (equals (key, p->key))
+      return p->val;
+  return NULL;
+}
+
+template <typename Key_t, typename Value_t>
+Vector<Value_t> *
+HashMap<Key_t, Value_t>::values (Key_t key)
+{
+  Vector<Value_t> *list = new Vector<Value_t>();
+  int hash_code = hashCode (key);
+  for (Hash_t *p = hashTable[hash_code]; p; p = p->next)
+    {
+      if (equals (key, p->key))
+       list->append (p->val);
+    }
+  return list;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+HashMap<Key_t, Value_t>::get (const Key_t key, Value_t val)
+{
+  int hash_code = hashCode (key);
+  Hash_t *p, *first = NULL;
+  for (p = hashTable[hash_code]; p; p = p->next)
+    {
+      if (equals (key, p->key))
+       {
+         if (first == NULL)
+           first = p;
+         if (val == p->val)
+           return first->val; // Always return the first value
+       }
+    }
+  vals->append (val);
+  p = new Hash_t ();
+  p->val = val;
+  p->key = copy (key);
+  if (first)
+    {
+      p->next = first->next;
+      first->next = p;
+      return first->val; // Always return the first value
+    }
+  else
+    {
+      p->next = hashTable[hash_code];
+      hashTable[hash_code] = p;
+      return val;
+    }
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+HashMap<Key_t, Value_t>::remove (Key_t key)
+{
+  int hash_code = hashCode (key);
+  Value_t val = NULL;
+  for (Hash_t *prev = NULL, *p = hashTable[hash_code]; p != NULL;)
+    {
+      if (equals (key, p->key))
+       {
+         if (prev == NULL)
+           hashTable[hash_code] = p->next;
+         else
+           prev->next = p->next;
+         if (val == NULL)
+           val = p->val;
+         delete_key (p->key);
+         delete p;
+       }
+      else
+       {
+         prev = p;
+         p = p->next;
+       }
+    }
+  return val;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+HashMap<Key_t, Value_t>::put (Key_t key, Value_t val)
+{
+  int hash_code = hashCode (key);
+  vals->append (val);
+  for (Hash_t *p = hashTable[hash_code]; p != NULL; p = p->next)
+    {
+      if (equals (key, p->key))
+       {
+         Value_t v = p->val;
+         p->val = val;
+         return v;
+       }
+    }
+  Hash_t *p = new Hash_t ();
+  p->val = val;
+  p->key = copy (key);
+  p->next = hashTable[hash_code];
+  hashTable[hash_code] = p;
+  nelem++;
+  if (nelem == hash_sz)
+    resize ();
+  return val;
+}
+
+template <typename Key_t, typename Value_t>
+char *
+HashMap<Key_t, Value_t>::dump ()
+{
+  StringBuilder sb;
+  char buf[128];
+  snprintf (buf, sizeof (buf), "HashMap: size=%d ##########\n", vals->size ());
+  sb.append (buf);
+  for (int i = 0; i < hash_sz; i++)
+    {
+      if (hashTable[i] == NULL)
+       continue;
+      snprintf (buf, sizeof (buf), "%3d:", i);
+      sb.append (buf);
+      char *s = NTXT (" ");
+      for (Hash_t *p = hashTable[i]; p; p = p->next)
+       {
+         sb.append (s);
+         s = NTXT ("     ");
+         sb.append (p->key);
+         snprintf (buf, sizeof (buf), " --> 0x%p '%s'\n",
+                   p->val, p->val->get_name ());
+         sb.append (buf);
+       }
+    }
+  return sb.toString ();
+}
+
+#endif // _DBE_HASHMAP_H
diff --git a/gprofng/src/HeapActivity.cc b/gprofng/src/HeapActivity.cc
new file mode 100644 (file)
index 0000000..943183d
--- /dev/null
@@ -0,0 +1,408 @@
+/* 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 "DbeSession.h"
+#include "HeapData.h"
+#include "StringBuilder.h"
+#include "i18n.h"
+#include "util.h"
+#include "HeapActivity.h"
+#include "MetricList.h"
+#include "Application.h"
+#include "Experiment.h"
+#include "DbeView.h"
+#include "Exp_Layout.h"
+#include "i18n.h"
+
+HeapActivity::HeapActivity (DbeView *_dbev)
+{
+  dbev = _dbev;
+  hDataTotal = NULL;
+  hDataObjs = NULL;
+  hDataObjsCallStack = NULL;
+  hasCallStack = false;
+  hDataCalStkMap = NULL;
+  hist_data_callstack_all = NULL;
+}
+
+void
+HeapActivity::reset ()
+{
+  delete hDataTotal;
+  hDataTotal = NULL;
+  delete hDataObjsCallStack;
+  hDataObjsCallStack = NULL;
+  hasCallStack = false;
+  hDataObjs = NULL;
+  delete hDataCalStkMap;
+  hDataCalStkMap = NULL;
+  hist_data_callstack_all = NULL;
+}
+
+void
+HeapActivity::createHistItemTotals (Hist_data *hist_data, MetricList *mlist,
+                                   Histable::Type hType, bool empty)
+{
+  int mIndex;
+  Metric *mtr;
+  Hist_data::HistItem *hi;
+  HeapData *hData = NULL;
+  if (hDataTotal == NULL)
+    {
+      hDataTotal = new HeapData (TOTAL_HEAPNAME);
+      hDataTotal->setHistType (hType);
+      hDataTotal->setStackId (TOTAL_STACK_ID);
+      hDataTotal->id = 0;
+    }
+
+  hData = new HeapData (hDataTotal);
+  hData->setHistType (hType);
+  hi = hist_data->append_hist_item (hData);
+
+  Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
+  {
+    if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
+      continue;
+
+    Metric::Type mtype = mtr->get_type ();
+    ValueTag vType = mtr->get_vtype ();
+
+    hist_data->total->value[mIndex].tag = vType;
+    hi->value[mIndex].tag = vType;
+    switch (mtype)
+      {
+      case BaseMetric::HEAP_ALLOC_BYTES:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].ll = hDataTotal->getAllocBytes ();
+           hi->value[mIndex].ll = hDataTotal->getAllocBytes ();
+         }
+       else
+         {
+           hist_data->total->value[mIndex].ll = 0;
+           hi->value[mIndex].ll = 0;
+         }
+       break;
+      case BaseMetric::HEAP_ALLOC_CNT:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].ll = hDataTotal->getAllocCnt ();
+           hi->value[mIndex].ll = hDataTotal->getAllocCnt ();
+         }
+       else
+         {
+           hist_data->total->value[mIndex].ll = 0;
+           hi->value[mIndex].ll = 0;
+         }
+       break;
+      case BaseMetric::HEAP_LEAK_BYTES:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].ll = hDataTotal->getLeakBytes ();
+           hi->value[mIndex].ll = hDataTotal->getLeakBytes ();
+         }
+       else
+         {
+           hist_data->total->value[mIndex].ll = 0;
+           hi->value[mIndex].ll = 0;
+         }
+       break;
+      case BaseMetric::HEAP_LEAK_CNT:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].ll = hDataTotal->getLeakCnt ();
+           hi->value[mIndex].ll = hDataTotal->getLeakCnt ();
+         }
+       else
+         {
+           hist_data->total->value[mIndex].ll = 0;
+           hi->value[mIndex].ll = 0;
+         }
+       break;
+      default:
+       break;
+      }
+  }
+}
+
+void
+HeapActivity::computeHistTotals (Hist_data *hist_data, MetricList *mlist)
+{
+  int mIndex;
+  Metric *mtr;
+  Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
+  {
+    if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
+      continue;
+
+    Metric::Type mtype = mtr->get_type ();
+    ValueTag vType = mtr->get_vtype ();
+
+    hist_data->total->value[mIndex].tag = vType;
+    switch (mtype)
+      {
+      case BaseMetric::HEAP_ALLOC_BYTES:
+       hist_data->total->value[mIndex].ll = hDataTotal->getAllocBytes ();
+       break;
+      case BaseMetric::HEAP_ALLOC_CNT:
+       hist_data->total->value[mIndex].ll = hDataTotal->getAllocCnt ();
+       break;
+      case BaseMetric::HEAP_LEAK_BYTES:
+       hist_data->total->value[mIndex].ll = hDataTotal->getLeakBytes ();
+       break;
+      case BaseMetric::HEAP_LEAK_CNT:
+       hist_data->total->value[mIndex].ll = hDataTotal->getLeakCnt ();
+       break;
+      default:
+       break;
+      }
+  }
+}
+
+void
+HeapActivity::computeHistData (Hist_data *hist_data, MetricList *mlist,
+                              Hist_data::Mode mode, Histable *selObj)
+{
+
+  Hist_data::HistItem *hi = NULL;
+
+  int numObjs = hDataObjs->size ();
+  int numMetrics = mlist->get_items ()->size ();
+  for (int i = 0; i < numObjs; i++)
+    {
+      HeapData *hData = hDataObjs->fetch (i);
+      if (mode == Hist_data::ALL)
+       hi = hist_data->append_hist_item (hData);
+      else if (mode == Hist_data::SELF)
+       {
+         if (hData->id == selObj->id)
+           hi = hist_data->append_hist_item (hData);
+         else
+           continue;
+       }
+
+      for (int mIndex = 0; mIndex < numMetrics; mIndex++)
+       {
+         Metric *mtr = mlist->get_items ()->fetch (mIndex);
+         if (!mtr->is_visible () && !mtr->is_tvisible ()
+             && !mtr->is_pvisible ())
+           continue;
+
+         Metric::Type mtype = mtr->get_type ();
+         ValueTag vType = mtr->get_vtype ();
+         hi->value[mIndex].tag = vType;
+         switch (mtype)
+           {
+           case BaseMetric::HEAP_ALLOC_BYTES:
+             hi->value[mIndex].ll = hData->getAllocBytes ();
+             break;
+           case BaseMetric::HEAP_ALLOC_CNT:
+             hi->value[mIndex].ll = hData->getAllocCnt ();
+             break;
+           case BaseMetric::HEAP_LEAK_BYTES:
+             hi->value[mIndex].ll = hData->getLeakBytes ();
+             break;
+           case BaseMetric::HEAP_LEAK_CNT:
+             hi->value[mIndex].ll = hData->getLeakCnt ();
+             break;
+           default:
+             break;
+           }
+       }
+    }
+}
+
+Hist_data *
+HeapActivity::compute_metrics (MetricList *mlist, Histable::Type type,
+                              Hist_data::Mode mode, Histable *selObj)
+{
+  // it's already there, just return it
+  if (mode == Hist_data::ALL && type == Histable::HEAPCALLSTACK
+      && hist_data_callstack_all != NULL)
+    return hist_data_callstack_all;
+
+  bool has_data = false;
+  Hist_data *hist_data = NULL;
+  VMode viewMode = dbev->get_view_mode ();
+  switch (type)
+    {
+    case Histable::HEAPCALLSTACK:
+      if (!hasCallStack)    // It is not computed yet
+       computeCallStack (type, viewMode);
+
+      // computeCallStack() creates hDataObjsCallStack
+      // hDataObjsCallStack contains the list of call stack objects
+      if (hDataObjsCallStack != NULL)
+       {
+         hDataObjs = hDataObjsCallStack;
+         has_data = true;
+       }
+      else
+       has_data = false;
+
+      if (has_data && mode == Hist_data::ALL && hist_data_callstack_all == NULL)
+       {
+         hist_data_callstack_all = new Hist_data (mlist, type, mode, true);
+         hist_data = hist_data_callstack_all;
+       }
+      else if (has_data)
+       hist_data = new Hist_data (mlist, type, mode, false);
+      else
+       {
+         hist_data = new Hist_data (mlist, type, mode, false);
+         createHistItemTotals (hist_data, mlist, type, true);
+         return hist_data;
+       }
+      break;
+    default:
+      fprintf (stderr,
+              "HeapActivity cannot process data due to wrong Histable (type=%d) \n",
+              type);
+      abort ();
+    }
+
+  if (mode == Hist_data::ALL || (mode == Hist_data::SELF && selObj->id == 0))
+    createHistItemTotals (hist_data, mlist, type, false);
+  else
+    computeHistTotals (hist_data, mlist);
+  computeHistData (hist_data, mlist, mode, selObj);
+
+  // Determine by which metric to sort if any
+  bool rev_sort = mlist->get_sort_rev ();
+  int sort_ind = -1;
+  int nmetrics = mlist->get_items ()->size ();
+
+  for (int mind = 0; mind < nmetrics; mind++)
+    if (mlist->get_sort_ref_index () == mind)
+      sort_ind = mind;
+
+  hist_data->sort (sort_ind, rev_sort);
+  hist_data->compute_minmax ();
+
+  return hist_data;
+}
+
+void
+HeapActivity::computeCallStack (Histable::Type type, VMode viewMode)
+{
+  bool has_data = false;
+  reset ();
+  uint64_t stackIndex = 0;
+  HeapData *hData = NULL;
+
+  delete hDataCalStkMap;
+  hDataCalStkMap = new DefaultMap<uint64_t, HeapData*>;
+
+  delete hDataTotal;
+  hDataTotal = new HeapData (TOTAL_HEAPNAME);
+  hDataTotal->setHistType (type);
+
+  // There is no call stack for total, use the index for id
+  hDataTotal->id = stackIndex++;
+
+  // get the list of io events from DbeView
+  int numExps = dbeSession->nexps ();
+
+  for (int k = 0; k < numExps; k++)
+    {
+      // Investigate the performance impact of processing the heap events twice.
+      // This is a 2*n performance issue
+      dbev->get_filtered_events (k, DATA_HEAPSZ);
+
+      DataView *heapPkts = dbev->get_filtered_events (k, DATA_HEAP);
+      if (heapPkts == NULL)
+       continue;
+
+      Experiment *exp = dbeSession->get_exp (k);
+      long sz = heapPkts->getSize ();
+      int pid = 0;
+      int userExpId = 0;
+      if (sz > 0)
+       {
+         pid = exp->getPID ();
+         userExpId = exp->getUserExpId ();
+       }
+      for (long i = 0; i < sz; ++i)
+       {
+         uint64_t nByte = heapPkts->getULongValue (PROP_HSIZE, i);
+         uint64_t stackId = (uint64_t) getStack (viewMode, heapPkts, i);
+         Heap_type heapType = (Heap_type) heapPkts->getIntValue (PROP_HTYPE, i);
+         uint64_t leaked = heapPkts->getULongValue (PROP_HLEAKED, i);
+         int64_t heapSize = heapPkts->getLongValue (PROP_HCUR_ALLOCS, i);
+         hrtime_t packetTimestamp = heapPkts->getLongValue (PROP_TSTAMP, i);
+         hrtime_t timestamp = packetTimestamp - exp->getStartTime () +
+                 exp->getRelativeStartTime ();
+
+         switch (heapType)
+           {
+           case MMAP_TRACE:
+           case MALLOC_TRACE:
+           case REALLOC_TRACE:
+             if (stackId != 0)
+               {
+                 hData = hDataCalStkMap->get (stackId);
+                 if (hData == NULL)
+                   {
+                     char *stkName = dbe_sprintf (GTXT ("Stack 0x%llx"),
+                                                 (unsigned long long) stackId);
+                     hData = new HeapData (stkName);
+                     hDataCalStkMap->put (stackId, hData);
+                     hData->id = (int64_t) stackId;
+                     hData->setStackId (stackIndex);
+                     stackIndex++;
+                     hData->setHistType (type);
+                   }
+               }
+             else
+               continue;
+
+             hData->addAllocEvent (nByte);
+             hDataTotal->addAllocEvent (nByte);
+             hDataTotal->setAllocStat (nByte);
+             hDataTotal->setPeakMemUsage (heapSize, hData->getStackId (),
+                                          timestamp, pid, userExpId);
+             if (leaked > 0)
+               {
+                 hData->addLeakEvent (leaked);
+                 hDataTotal->addLeakEvent (leaked);
+                 hDataTotal->setLeakStat (leaked);
+               }
+             break;
+           case MUNMAP_TRACE:
+           case FREE_TRACE:
+             if (hData == NULL)
+               hData = new HeapData (TOTAL_HEAPNAME);
+             hDataTotal->setPeakMemUsage (heapSize, hData->getStackId (),
+                                          timestamp, pid, userExpId);
+             break;
+           case HEAPTYPE_LAST:
+             break;
+           }
+         has_data = true;
+       }
+    }
+
+  if (has_data)
+    {
+      hDataObjsCallStack = hDataCalStkMap->values ()->copy ();
+      hasCallStack = true;
+    }
+}
diff --git a/gprofng/src/HeapActivity.h b/gprofng/src/HeapActivity.h
new file mode 100644 (file)
index 0000000..582b0b7
--- /dev/null
@@ -0,0 +1,76 @@
+/* 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 _HEAPACTIVITY_H
+#define _HEAPACTIVITY_H
+
+
+#include <stdio.h>
+
+#include "vec.h"
+#include "Histable.h"
+#include "Hist_data.h"
+#include "Metric.h"
+#include "HeapData.h"
+#include "DefaultMap.h"
+#include "dbe_types.h"
+
+class Experiment;
+class Expression;
+class DataView;
+class DbeView;
+
+class HeapActivity
+{
+public:
+
+  HeapActivity (DbeView *_dbev);
+
+  ~HeapActivity ()
+  {
+    this->reset ();
+  }
+
+  void reset (void);
+  Hist_data *compute_metrics (MetricList *, Histable::Type,
+                             Hist_data::Mode, Histable*);
+
+private:
+
+  void computeCallStack (Histable::Type, VMode viewMode);
+  void createHistItemTotals (Hist_data *, MetricList *, Histable::Type, bool);
+  void computeHistTotals (Hist_data *, MetricList *);
+  void computeHistData (Hist_data *, MetricList *, Hist_data::Mode, Histable *);
+
+  Vector<HeapData*> *hDataObjs;
+  Vector<HeapData*> *hDataObjsCallStack;
+  bool hasCallStack;
+  HeapData *hDataTotal;
+
+  // list of HeapData objects using the stack id as the key
+  DefaultMap<uint64_t, HeapData*> *hDataCalStkMap;
+
+  // the cached data for mode=Hist_Data::ALL
+  Hist_data *hist_data_callstack_all;
+
+  DbeView *dbev;
+};
+
+#endif /* _HEAPACTIVITY_H */
diff --git a/gprofng/src/HeapData.cc b/gprofng/src/HeapData.cc
new file mode 100644 (file)
index 0000000..5f001ad
--- /dev/null
@@ -0,0 +1,284 @@
+/* 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 <assert.h>
+#include <string.h>
+
+#include "util.h"
+#include "HeapData.h"
+
+void
+HeapData::init ()
+{
+  allocBytes = 0;
+  leakBytes = 0;
+  allocCnt = 0;
+  leakCnt = 0;
+  stackId = 0;
+  histType = Histable::HEAPCALLSTACK;
+  peakMemUsage = 0;
+  timestamp = 0;
+  pid = 0;
+  userExpId = 0;
+  aSmallestBytes = _10TB;
+  aLargestBytes = 0;
+  a0KB1KBCnt = 0;
+  a1KB8KBCnt = 0;
+  a8KB32KBCnt = 0;
+  a32KB128KBCnt = 0;
+  a128KB256KBCnt = 0;
+  a256KB512KBCnt = 0;
+  a512KB1000KBCnt = 0;
+  a1000KB10MBCnt = 0;
+  a10MB100MBCnt = 0;
+  a100MB1GBCnt = 0;
+  a1GB10GBCnt = 0;
+  a10GB100GBCnt = 0;
+  a100GB1TBCnt = 0;
+  a1TB10TBCnt = 0;
+
+  lSmallestBytes = _10TB;
+  lLargestBytes = 0;
+  l0KB1KBCnt = 0;
+  l1KB8KBCnt = 0;
+  l8KB32KBCnt = 0;
+  l32KB128KBCnt = 0;
+  l128KB256KBCnt = 0;
+  l256KB512KBCnt = 0;
+  l512KB1000KBCnt = 0;
+  l1000KB10MBCnt = 0;
+  l10MB100MBCnt = 0;
+  l100MB1GBCnt = 0;
+  l1GB10GBCnt = 0;
+  l10GB100GBCnt = 0;
+  l100GB1TBCnt = 0;
+  l1TB10TBCnt = 0;
+}
+
+HeapData::HeapData (char *sName)
+{
+  stackName = dbe_strdup (sName);
+  peakStackIds = new Vector<uint64_t>;
+  peakTimestamps = new Vector<hrtime_t>;
+  init ();
+}
+
+HeapData::HeapData (HeapData *hData)
+{
+  stackName = dbe_strdup (hData->stackName);
+  stackId = hData->stackId;
+  histType = hData->histType;
+  allocBytes = hData->allocBytes;
+  leakBytes = hData->leakBytes;
+  allocCnt = hData->allocCnt;
+  leakCnt = hData->leakCnt;
+  peakMemUsage = hData->peakMemUsage;
+  timestamp = hData->timestamp;
+  pid = hData->getPid ();
+  userExpId = hData->getUserExpId ();
+  peakStackIds = new Vector<uint64_t>;
+  Vector<uint64_t> *sIds = hData->peakStackIds;
+  uint64_t sId;
+  if (sIds != NULL)
+    for (int i = 0; i < sIds->size (); i++)
+      {
+       sId = sIds->fetch (i);
+       peakStackIds->append (sId);
+      }
+
+  peakTimestamps = new Vector<hrtime_t>;
+  Vector<hrtime_t> *pts = hData->peakTimestamps;
+  hrtime_t ts;
+  if (pts != NULL)
+    for (int i = 0; i < pts->size (); i++)
+      {
+       ts = pts->fetch (i);
+       peakTimestamps->append (ts);
+      }
+
+  aSmallestBytes = hData->aSmallestBytes;
+  aLargestBytes = hData->aLargestBytes;
+  a0KB1KBCnt = hData->a0KB1KBCnt;
+  a1KB8KBCnt = hData->a1KB8KBCnt;
+  a8KB32KBCnt = hData->a8KB32KBCnt;
+  a32KB128KBCnt = hData->a32KB128KBCnt;
+  a128KB256KBCnt = hData->a128KB256KBCnt;
+  a256KB512KBCnt = hData->a256KB512KBCnt;
+  a512KB1000KBCnt = hData->a512KB1000KBCnt;
+  a1000KB10MBCnt = hData->a1000KB10MBCnt;
+  a10MB100MBCnt = hData->a10MB100MBCnt;
+  a100MB1GBCnt = hData->a100MB1GBCnt;
+  a1GB10GBCnt = hData->a1GB10GBCnt;
+  a10GB100GBCnt = hData->a10GB100GBCnt;
+  a100GB1TBCnt = hData->a100GB1TBCnt;
+  a1TB10TBCnt = hData->a1TB10TBCnt;
+
+  lSmallestBytes = hData->lSmallestBytes;
+  lLargestBytes = hData->lLargestBytes;
+  l0KB1KBCnt = hData->l0KB1KBCnt;
+  l1KB8KBCnt = hData->l1KB8KBCnt;
+  l8KB32KBCnt = hData->l8KB32KBCnt;
+  l32KB128KBCnt = hData->l32KB128KBCnt;
+  l128KB256KBCnt = hData->l128KB256KBCnt;
+  l256KB512KBCnt = hData->l256KB512KBCnt;
+  l512KB1000KBCnt = hData->l512KB1000KBCnt;
+  l1000KB10MBCnt = hData->l1000KB10MBCnt;
+  l10MB100MBCnt = hData->l10MB100MBCnt;
+  l100MB1GBCnt = hData->l100MB1GBCnt;
+  l1GB10GBCnt = hData->l1GB10GBCnt;
+  l10GB100GBCnt = hData->l10GB100GBCnt;
+  l100GB1TBCnt = hData->l100GB1TBCnt;
+  l1TB10TBCnt = hData->l1TB10TBCnt;
+}
+
+HeapData::~HeapData ()
+{
+  free (stackName);
+  delete peakStackIds;
+  delete peakTimestamps;
+}
+
+Histable*
+HeapData::convertto (Histable_type type, Histable*)
+{
+  return type == histType ? this : NULL;
+}
+
+char*
+HeapData::get_name (Histable::NameFormat /*_nfmt*/)
+{
+  return stackName;
+}
+
+char*
+HeapData::get_raw_name (Histable::NameFormat /*_nfmt*/)
+{
+  return stackName;
+}
+
+void
+HeapData::set_name (char* _name)
+{
+  free (stackName);
+  stackName = dbe_strdup (_name);
+}
+
+void
+HeapData::setPeakMemUsage (int64_t pmu, uint64_t sId, hrtime_t ts, int procId, int uei)
+{
+  if (peakMemUsage < pmu)
+    {
+      peakMemUsage = pmu;
+      peakStackIds->reset ();
+      peakStackIds->append (sId);
+      peakTimestamps->reset ();
+      peakTimestamps->append (ts);
+      pid = procId;
+      userExpId = uei;
+    }
+  else if (peakMemUsage == pmu)
+    {
+      for (int i = 0; i < peakStackIds->size (); i++)
+       {
+         uint64_t curSId = peakStackIds->fetch (i);
+         if (curSId == sId)
+           return;
+       }
+      peakStackIds->append (sId);
+      peakTimestamps->append (ts);
+      pid = procId;
+      userExpId = uei;
+    }
+}
+
+void
+HeapData::setAllocStat (int64_t nb)
+{
+  if (aSmallestBytes > nb)
+    aSmallestBytes = nb;
+  if (aLargestBytes < nb)
+    aLargestBytes = nb;
+  if (nb >= 0 && nb <= _1KB)
+    a0KB1KBCnt++;
+  else if (nb <= _8KB)
+    a1KB8KBCnt++;
+  else if (nb <= _32KB)
+    a8KB32KBCnt++;
+  else if (nb <= _128KB)
+    a32KB128KBCnt++;
+  else if (nb <= _256KB)
+    a128KB256KBCnt++;
+  else if (nb <= _512KB)
+    a256KB512KBCnt++;
+  else if (nb <= _1000KB)
+    a512KB1000KBCnt++;
+  else if (nb <= _10MB)
+    a1000KB10MBCnt++;
+  else if (nb <= _100MB)
+    a10MB100MBCnt++;
+  else if (nb <= _1GB)
+    a100MB1GBCnt++;
+  else if (nb <= _10GB)
+    a1GB10GBCnt++;
+  else if (nb <= _100GB)
+    a10GB100GBCnt++;
+  else if (nb <= _1TB)
+    a100GB1TBCnt++;
+  else if (nb <= _10TB)
+    a1TB10TBCnt++;
+}
+
+void
+HeapData::setLeakStat (int64_t nb)
+{
+  if (lSmallestBytes > nb)
+    lSmallestBytes = nb;
+  if (lLargestBytes < nb)
+    lLargestBytes = nb;
+  if (nb >= 0 && nb <= _1KB)
+    l0KB1KBCnt++;
+  else if (nb <= _8KB)
+    l1KB8KBCnt++;
+  else if (nb <= _32KB)
+    l8KB32KBCnt++;
+  else if (nb <= _128KB)
+    l32KB128KBCnt++;
+  else if (nb <= _256KB)
+    l128KB256KBCnt++;
+  else if (nb <= _512KB)
+    l256KB512KBCnt++;
+  else if (nb <= _1000KB)
+    l512KB1000KBCnt++;
+  else if (nb <= _10MB)
+    l1000KB10MBCnt++;
+  else if (nb <= _100MB)
+    l10MB100MBCnt++;
+  else if (nb <= _1GB)
+    l100MB1GBCnt++;
+  else if (nb <= _10GB)
+    l1GB10GBCnt++;
+  else if (nb <= _100GB)
+    l10GB100GBCnt++;
+  else if (nb <= _1TB)
+    l100GB1TBCnt++;
+  else if (nb <= _10TB)
+    l1TB10TBCnt++;
+}
diff --git a/gprofng/src/HeapData.h b/gprofng/src/HeapData.h
new file mode 100644 (file)
index 0000000..7ff68e9
--- /dev/null
@@ -0,0 +1,450 @@
+/* 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 _HEAPDATA_H
+#define _HEAPDATA_H
+
+#include "gp-defs.h"
+#include "gp-time.h"
+
+#include "vec.h"
+#include "data_pckts.h"
+#include "Histable.h"
+
+#define TOTAL_HEAPNAME      NTXT("<Total>")
+#define TOTAL_STACK_ID      0
+#define _1KB                1024
+#define _8KB                8192
+#define _32KB               32768
+#define _128KB              131072
+#define _256KB              262144
+#define _512KB              524288
+#define _1000KB             1048576
+#define _10MB               10485760
+#define _100MB              104857600
+#define _1GB                1073741824
+#define _10GB               10737418240
+#define _100GB              107374182400
+#define _1TB                1099511627776
+#define _10TB               10995116277760
+
+class HeapData : public Histable
+{
+  friend class HeapActivity;
+public:
+  HeapData (char *sName);
+  HeapData (HeapData *hData);
+  ~HeapData ();
+  char *get_raw_name (Histable::NameFormat nfmt);
+  void init ();
+  void setStackName (char* sName);
+  void setPeakMemUsage (int64_t pmu, uint64_t sId, hrtime_t ts, int procId, int uei);
+
+  virtual char *get_name (Histable::NameFormat nfmt);
+  virtual void set_name (char * _name);
+  virtual Histable *convertto (Histable_type, Histable* = NULL);
+
+  virtual Histable_type
+  get_type ()
+  {
+    return histType;
+  }
+
+  virtual uint64_t
+  get_addr ()
+  {
+    return stackId;
+  }
+
+  uint64_t
+  get_index ()
+  {
+    return stackId;
+  }
+
+  char *
+  getStackName ()
+  {
+    return stackName;
+  }
+
+  void
+  addAllocEvent (uint64_t nb)
+  {
+    allocBytes += nb;
+    allocCnt++;
+  }
+
+  uint64_t
+  getAllocBytes ()
+  {
+    return allocBytes;
+  }
+
+  int32_t
+  getAllocCnt ()
+  {
+    return allocCnt;
+  }
+
+  void
+  addLeakEvent (uint64_t nb)
+  {
+    leakBytes += nb;
+    leakCnt++;
+  }
+
+  uint64_t
+  getLeakBytes ()
+  {
+    return leakBytes;
+  }
+
+  int32_t
+  getLeakCnt ()
+  {
+    return leakCnt;
+  }
+
+  void
+  setStackId (uint64_t sId)
+  {
+    stackId = sId;
+  }
+
+  uint64_t
+  getStackId ()
+  {
+    return stackId;
+  }
+
+  void
+  setTimestamp (hrtime_t ts)
+  {
+    timestamp = ts;
+  }
+
+  hrtime_t
+  getTimestamp ()
+  {
+    return timestamp;
+  }
+
+  void
+  setHistType (Histable::Type hType)
+  {
+    histType = hType;
+  }
+
+  Histable::Type
+  getHistType ()
+  {
+    return histType;
+  }
+
+  int64_t
+  getPeakMemUsage ()
+  {
+    return peakMemUsage;
+  }
+
+  Vector<uint64_t> *
+  getPeakStackIds ()
+  {
+    return peakStackIds;
+  }
+
+  Vector<hrtime_t> *
+  getPeakTimestamps ()
+  {
+    return peakTimestamps;
+  }
+
+  void
+  setPid (int procId)
+  {
+    pid = procId;
+  }
+
+  int
+  getPid ()
+  {
+    return pid;
+  }
+
+  void
+  setUserExpId (int uei)
+  {
+    userExpId = uei;
+  }
+
+  int
+  getUserExpId ()
+  {
+    return userExpId;
+  }
+
+  void setAllocStat (int64_t nb);
+
+  int64_t
+  getASmallestBytes ()
+  {
+    return aSmallestBytes;
+  }
+
+  int64_t
+  getALargestBytes ()
+  {
+    return aLargestBytes;
+  }
+
+  int32_t
+  getA0KB1KBCnt ()
+  {
+    return a0KB1KBCnt;
+  }
+
+  int32_t
+  getA1KB8KBCnt ()
+  {
+    return a1KB8KBCnt;
+  }
+
+  int32_t
+  getA8KB32KBCnt ()
+  {
+    return a8KB32KBCnt;
+  }
+
+  int32_t
+  getA32KB128KBCnt ()
+  {
+    return a32KB128KBCnt;
+  }
+
+  int32_t
+  getA128KB256KBCnt ()
+  {
+    return a128KB256KBCnt;
+  }
+
+  int32_t
+  getA256KB512KBCnt ()
+  {
+    return a256KB512KBCnt;
+  }
+
+  int32_t
+  getA512KB1000KBCnt ()
+  {
+    return a512KB1000KBCnt;
+  }
+
+  int32_t
+  getA1000KB10MBCnt ()
+  {
+    return a1000KB10MBCnt;
+  }
+
+  int32_t
+  getA10MB100MBCnt ()
+  {
+    return a10MB100MBCnt;
+  }
+
+  int32_t
+  getA100MB1GBCnt ()
+  {
+    return a100MB1GBCnt;
+  }
+
+  int32_t
+  getA1GB10GBCnt ()
+  {
+    return a1GB10GBCnt;
+  }
+
+  int32_t
+  getA10GB100GBCnt ()
+  {
+    return a10GB100GBCnt;
+  }
+
+  int32_t
+  getA100GB1TBCnt ()
+  {
+    return a100GB1TBCnt;
+  }
+
+  int32_t
+  getA1TB10TBCnt ()
+  {
+    return a1TB10TBCnt;
+  }
+
+  void setLeakStat (int64_t nb);
+
+  int64_t
+  getLSmallestBytes ()
+  {
+    return lSmallestBytes;
+  }
+
+  int64_t
+  getLLargestBytes ()
+  {
+    return lLargestBytes;
+  }
+
+  int32_t
+  getL0KB1KBCnt ()
+  {
+    return l0KB1KBCnt;
+  }
+
+  int32_t
+  getL1KB8KBCnt ()
+  {
+    return l1KB8KBCnt;
+  }
+
+  int32_t
+  getL8KB32KBCnt ()
+  {
+    return l8KB32KBCnt;
+  }
+
+  int32_t
+  getL32KB128KBCnt ()
+  {
+    return l32KB128KBCnt;
+  }
+
+  int32_t
+  getL128KB256KBCnt ()
+  {
+    return l128KB256KBCnt;
+  }
+
+  int32_t
+  getL256KB512KBCnt ()
+  {
+    return l256KB512KBCnt;
+  }
+
+  int32_t
+  getL512KB1000KBCnt ()
+  {
+    return l512KB1000KBCnt;
+  }
+
+  int32_t
+  getL1000KB10MBCnt ()
+  {
+    return l1000KB10MBCnt;
+  }
+
+  int32_t
+  getL10MB100MBCnt ()
+  {
+    return l10MB100MBCnt;
+  }
+
+  int32_t
+  getL100MB1GBCnt ()
+  {
+    return l100MB1GBCnt;
+  }
+
+  int32_t
+  getL1GB10GBCnt ()
+  {
+    return l1GB10GBCnt;
+  }
+
+  int32_t
+  getL10GB100GBCnt ()
+  {
+    return l10GB100GBCnt;
+  }
+
+  int32_t
+  getL100GB1TBCnt ()
+  {
+    return l100GB1TBCnt;
+  }
+
+  int32_t
+  getL1TB10TBCnt ()
+  {
+    return l1TB10TBCnt;
+  }
+
+private:
+  char *stackName;                  // stack name
+  uint64_t allocBytes;              // The total bytes allocated
+  uint64_t leakBytes;               // The total bytes leaked
+  int32_t allocCnt;                 // The alloc count
+  int32_t leakCnt;                  // The leak count
+  Histable::Type histType;          // The Histable type: HEAPCALLSTACK
+  int64_t peakMemUsage;             // Keep track of peak memory usage
+  uint64_t stackId;
+  Vector<uint64_t> *peakStackIds;   // The peak memory usage stack ids
+  hrtime_t timestamp;
+  Vector<hrtime_t> *peakTimestamps; // The peak data
+  int pid;                          // The process id
+  int userExpId;                    // The experiment id
+
+  int64_t aSmallestBytes;
+  int64_t aLargestBytes;
+  int32_t a0KB1KBCnt;
+  int32_t a1KB8KBCnt;
+  int32_t a8KB32KBCnt;
+  int32_t a32KB128KBCnt;
+  int32_t a128KB256KBCnt;
+  int32_t a256KB512KBCnt;
+  int32_t a512KB1000KBCnt;
+  int32_t a1000KB10MBCnt;
+  int32_t a10MB100MBCnt;
+  int32_t a100MB1GBCnt;
+  int32_t a1GB10GBCnt;
+  int32_t a10GB100GBCnt;
+  int32_t a100GB1TBCnt;
+  int32_t a1TB10TBCnt;
+
+  int64_t lSmallestBytes;
+  int64_t lLargestBytes;
+  int32_t l0KB1KBCnt;
+  int32_t l1KB8KBCnt;
+  int32_t l8KB32KBCnt;
+  int32_t l32KB128KBCnt;
+  int32_t l128KB256KBCnt;
+  int32_t l256KB512KBCnt;
+  int32_t l512KB1000KBCnt;
+  int32_t l1000KB10MBCnt;
+  int32_t l10MB100MBCnt;
+  int32_t l100MB1GBCnt;
+  int32_t l1GB10GBCnt;
+  int32_t l10GB100GBCnt;
+  int32_t l100GB1TBCnt;
+  int32_t l1TB10TBCnt;
+};
+
+#endif
diff --git a/gprofng/src/HeapMap.cc b/gprofng/src/HeapMap.cc
new file mode 100644 (file)
index 0000000..8e6c009
--- /dev/null
@@ -0,0 +1,325 @@
+/* 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 "util.h"
+#include "HeapMap.h"
+
+#define HEAPCHUNKSZ     1024 // number of HeapObj's in a chunk
+#define HEAPCHAINS      9192 // number of address-based chains
+#define hash(x)         (((x) >> 6) % HEAPCHAINS)
+
+typedef struct HeapObj
+{
+  uint64_t addr;
+  uint64_t size;
+  long val;
+  HeapObj *next;
+} HeapObj;
+
+typedef struct HeapChunk
+{
+  void *addr;
+  HeapChunk *next;
+} HeapChunk;
+
+HeapMap::HeapMap ()
+{
+  chunks = NULL;
+  empty = NULL;
+  chain = new HeapObj*[HEAPCHAINS];
+  for (int i = 0; i < HEAPCHAINS; i++)
+    chain[i] = NULL;
+
+  mmaps = new HeapObj;
+  mmaps->addr = (uint64_t) 0;
+  mmaps->size = (uint64_t) 0;
+  mmaps->val = -1;
+  mmaps->next = NULL;
+}
+
+HeapMap::~HeapMap ()
+{
+  // free up all the chunks
+  HeapChunk *c = chunks;
+  while (c != NULL)
+    {
+      HeapChunk *next = c->next;
+      delete c;
+      c = next;
+    }
+  delete[] chain;
+  delete mmaps;
+}
+
+void
+HeapMap::allocate (uint64_t addr, long val)
+{
+  // get a HeapObj, and set it up for the allocated block
+  HeapObj *incoming = getHeapObj ();
+  incoming->addr = addr;
+  incoming->val = val;
+  incoming->next = NULL;
+
+  // determine which chain the block belongs on
+  int ichain = (int) hash (addr);
+
+  // if this is the first, just set it up and return
+  if (chain[ichain] == NULL)
+    {
+      chain[ichain] = incoming;
+      return;
+    }
+  // chain is non-empty -- find the slot for this one
+  //  chain is maintained in reverse address order
+  HeapObj *prev = NULL;
+  HeapObj *next = chain[ichain];
+
+  for (;;)
+    {
+      if ((next == NULL) || (next->addr < incoming->addr))
+       {
+         // we've found the spot
+         incoming->next = next;
+         if (prev == NULL)
+           chain[ichain] = incoming;
+         else
+           prev->next = incoming;
+         return;
+       }
+      if (next->addr == incoming->addr)
+       {
+         // error -- two blocks with same address active
+         //   ignore the new one
+         releaseHeapObj (incoming);
+         return;
+       }
+      // not yet, keep looking
+      prev = next;
+      next = next->next;
+    }
+}
+
+long
+HeapMap::deallocate (uint64_t addr)
+{
+  int ichain = (int) hash (addr);
+  HeapObj *cur = chain[ichain];
+  HeapObj *prev = NULL;
+  while (cur != NULL)
+    {
+      if (cur->addr == addr)
+       {
+         // we've found the block
+         long val = cur->val;
+
+         // delete the block from the chain
+         if (prev == NULL)
+           chain[ichain] = cur->next;
+         else
+           prev->next = cur->next;
+         releaseHeapObj (cur);
+         return val;
+       }
+      prev = cur;
+      cur = cur->next;
+    }
+
+  // block not found
+  return 0;
+}
+
+void
+HeapMap::allocateChunk ()
+{
+  // allocate the memory
+  HeapChunk *c = new HeapChunk;
+  HeapObj *newc = new HeapObj[HEAPCHUNKSZ];
+
+  // set up the chunk, and queue it for destructor's use
+  c->addr = (void *) newc;
+  c->next = chunks;
+  chunks = c;
+
+  // Initialize the HeapObj's in the chunk to one chain
+  // last entry is left NULL, terminating the chain
+  for (int i = 0; i < (HEAPCHUNKSZ - 1); i++)
+    newc[i].next = newc + i + 1;
+  newc[HEAPCHUNKSZ - 1].next = NULL;
+
+  // put that chain on the empty queue
+  empty = newc;
+}
+
+HeapObj *
+HeapMap::getHeapObj ()
+{
+  if (empty == NULL)
+    allocateChunk ();
+  HeapObj *ret = empty;
+  empty = ret->next;
+  return ret;
+}
+
+void
+HeapMap::releaseHeapObj (HeapObj *obj)
+{
+  obj->next = empty;
+  empty = obj;
+}
+
+UnmapChunk*
+HeapMap::mmap (uint64_t addr, int64_t size, long val)
+{
+  HeapObj *incoming = getHeapObj ();
+  incoming->addr = addr;
+  incoming->size = size;
+  incoming->val = val;
+  incoming->next = NULL;
+  UnmapChunk* list = process (incoming, addr, size);
+  return list;
+}
+
+UnmapChunk*
+HeapMap::munmap (uint64_t addr, int64_t size)
+{
+  UnmapChunk* list = process (NULL, addr, size);
+  return list;
+}
+
+UnmapChunk*
+HeapMap::process (HeapObj *obj, uint64_t addr, int64_t size)
+{
+  // Some graphics are used to clarify the alignment of mmap regions
+  // obj, shown as consecutive pages: "NNNNNN"
+  // cur, shown as consecutive pages: "CCCCCC"
+
+  // Find the first overlap, start of N is before end of C.  Examples:
+  //   CCCCC
+  //     NNNNN
+  // or
+  //   CCCCC
+  //    NNN
+  // or
+  //   CCCCC
+  //  NNNNN
+  // or
+  //   CCCCC
+  //  NNNNNNN
+  HeapObj *prev = mmaps;
+  HeapObj *cur = prev->next;
+  while (cur)
+    {
+      if (addr < cur->addr + cur->size)
+       break;
+      prev = cur;
+      cur = prev->next;
+    }
+
+  // None found
+  if (cur == NULL)
+    {
+      prev->next = obj;
+      return NULL;
+    }
+
+  UnmapChunk* list = NULL;
+  if (addr > cur->addr)
+    {
+      if (cur->addr + cur->size <= addr + size)
+       {
+         // Process overlap on the left (low side) of new allocation
+         // New range: N-start to C-end (gets freed below)
+         prev = cur;
+         cur = getHeapObj ();
+         cur->addr = addr;
+         cur->size = prev->addr + prev->size - addr;
+         cur->val = prev->val;
+         cur->next = prev->next;
+
+         // Truncate range: C-start to N-start
+         prev->size = addr - prev->addr;
+       }
+      else
+       {
+         // Process new allocation that fits completely within old allocation
+         // New range: N-start to N-end (freed below)
+         int64_t c_end = cur->addr + cur->size;
+         prev = cur;
+         cur = getHeapObj ();
+         cur->addr = addr;
+         cur->size = size;
+         cur->val = prev->val;
+         cur->next = prev->next;
+
+         // Truncate range: C-start to N-start
+         prev->size = addr - prev->addr;
+
+         // New range: N-end to C-end.
+         HeapObj *next = getHeapObj ();
+         next->addr = addr + size;
+         next->size = c_end - next->addr;
+         next->val = cur->val;
+         next->next = cur->next;
+         cur->next = next;
+       }
+    }
+
+  // Process all full overlaps.
+  // Copy details of cur to UnmapChunk list, remove cur from mmaps
+  while (cur && cur->addr + cur->size <= addr + size)
+    {
+
+      UnmapChunk* uc = new UnmapChunk;
+      uc->val = cur->val;
+      uc->size = cur->size;
+      uc->next = list;
+      list = uc;
+
+      HeapObj *t = cur;
+      cur = cur->next;
+      releaseHeapObj (t);
+    }
+
+  if (cur && cur->addr < addr + size)
+    {
+      // Process the last overlap (right side of new allocation)
+      // Copy details of cur to UnmapChunk list
+      UnmapChunk* uc = new UnmapChunk;
+      uc->val = cur->val;
+      uc->size = addr + size - cur->addr;
+      uc->next = list;
+      list = uc;
+
+      // Truncate left side of cur
+      cur->size -= uc->size;
+      cur->addr = addr + size;
+    }
+
+  // Insert new allocation
+  if (obj)
+    {
+      prev->next = obj;
+      obj->next = cur;
+    }
+  else
+    prev->next = cur;
+  return list;
+}
diff --git a/gprofng/src/HeapMap.h b/gprofng/src/HeapMap.h
new file mode 100644 (file)
index 0000000..c46129d
--- /dev/null
@@ -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 _HEAPMAP_H
+#define _HEAPMAP_H
+
+#include "dbe_types.h"
+#include "vec.h"
+
+struct HeapObj;
+struct HeapChunk;
+
+typedef struct UnmapChunk
+{
+  long val;
+  int64_t size;
+  UnmapChunk *next;
+} UnmapChunk;
+
+class HeapMap
+{
+public:
+  HeapMap ();
+  ~HeapMap ();
+  void allocate (uint64_t addr, long val);
+  long deallocate (uint64_t addr);
+  UnmapChunk *mmap (uint64_t addr, int64_t size, long val);
+  UnmapChunk *munmap (uint64_t addr, int64_t size);
+
+private:
+  void allocateChunk ();
+  HeapObj *getHeapObj ();
+  void releaseHeapObj (HeapObj*);
+  UnmapChunk *process (HeapObj *obj, uint64_t addr, int64_t size);
+
+  HeapChunk *chunks;
+  HeapObj *empty;
+  HeapObj **chain;
+  HeapObj *mmaps;
+};
+
+#endif /* _HEAPMAP_H */
diff --git a/gprofng/src/Hist_data.cc b/gprofng/src/Hist_data.cc
new file mode 100644 (file)
index 0000000..4412203
--- /dev/null
@@ -0,0 +1,1886 @@
+/* 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 <assert.h>
+
+#include "util.h"
+#include "DefaultMap.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "DataObject.h"
+#include "Function.h"
+#include "Hist_data.h"
+#include "Histable.h"
+#include "MemObject.h"
+#include "IndexObject.h"
+#include "MetricList.h"
+#include "Metric.h"
+#include "Module.h"
+#include "LoadObject.h"
+#include "Settings.h"
+#include "StringBuilder.h"
+#include "ExpGroup.h"
+#include "PathTree.h"
+#include "DbeView.h"
+#include "FileData.h"
+
+Hist_data::HistItem::HistItem (long n)
+{
+  obj = NULL;
+  type = 0;
+  size = n;
+  value = new TValue[n];
+  memset (value, 0, sizeof (TValue) * n);
+}
+
+Hist_data::HistItem::~HistItem ()
+{
+  for (long i = 0; i < size; i++)
+    if (value[i].tag == VT_LABEL)
+      free (value[i].l);
+  delete[] value;
+}
+
+long
+Hist_data::size ()
+{
+  // If the data values have not been computed, do so
+  // Return the total number of items
+  return hist_items->size ();
+}
+
+Hist_data::HistItem *
+Hist_data::fetch (long index)
+{
+  return (index < VecSize (hist_items)) ? hist_items->get (index) : NULL;
+}
+
+int
+Hist_data::sort_compare (HistItem *hi_1, HistItem *hi_2, Sort_type stype,
+                        long ind, Hist_data *hdata)
+{
+  // Sort the data depending upon order and type
+  int result = 0;
+  Histable::Type type = hi_1->obj->get_type ();
+  if (stype == ALPHA)
+    {
+      if (type != Histable::MEMOBJ && type != Histable::INDEXOBJ
+             && type != Histable::IOACTVFD && type != Histable::IOACTFILE
+             && type != Histable::IOCALLSTACK)
+       {
+         char *nm1 = hi_1->obj->get_name ();
+         char *nm2 = hi_2->obj->get_name ();
+         if (nm1 != NULL && nm2 != NULL)
+           result = strcoll (nm1, nm2);
+       }
+      else if (type == Histable::IOCALLSTACK || type == Histable::IOACTVFD
+              || type == Histable::IOACTFILE)
+       {
+         uint64_t idx1, idx2;
+         idx1 = ((FileData *) (hi_1->obj))->get_index ();
+         idx2 = ((FileData *) (hi_2->obj))->get_index ();
+         if (idx1 < idx2)
+           result = -1;
+         else if (idx1 > idx2)
+           result = 1;
+         else
+           result = 0;
+       }
+      else
+       {
+         // for memory and index objects, "alphabetic" is really by index
+         // <Total> has index -2, and always comes first
+         // <Unknown> has index -1, and always comes second.
+         uint64_t i1, i2;
+         bool needsStringCompare = false;
+         if (type == Histable::MEMOBJ)
+           {
+             i1 = ((MemObj *) (hi_1->obj))->get_index ();
+             i2 = ((MemObj *) (hi_2->obj))->get_index ();
+           }
+         else if (type == Histable::INDEXOBJ)
+           {
+             i1 = ((IndexObject *) (hi_1->obj))->get_index ();
+             i2 = ((IndexObject *) (hi_2->obj))->get_index ();
+             needsStringCompare =
+                     ((IndexObject *) (hi_1->obj))->requires_string_sort ();
+           }
+         else
+           abort ();
+         if (i1 == (uint64_t) - 2)
+           result = -1;
+         else if (i2 == (uint64_t) - 2)
+           result = 1;
+         else if (i1 == (uint64_t) - 1)
+           result = -1;
+         else if (i2 == (uint64_t) - 1)
+           result = 1;
+         else if (needsStringCompare)
+           {
+             char *nm1 = hi_1->obj->get_name ();
+             char *nm2 = hi_2->obj->get_name ();
+             if (nm1 != NULL && nm2 != NULL)
+               {
+                 char nm1_lead = nm1[0];
+                 char nm2_lead = nm2[0];
+                 // put "(unknown)" and friends at end of list
+                 if (nm1_lead == '(' && nm1_lead != nm2_lead)
+                   result = 1;
+                 else if (nm2_lead == '(' && nm1_lead != nm2_lead)
+                   result = -1;
+                 else
+                   result = strcoll (nm1, nm2);
+               }
+           }
+         if (result == 0)
+           { // matches, resolve by index
+             if (i1 < i2)
+               result = -1;
+             else if (i1 > i2)
+               result = 1;
+           }
+       }
+    }
+  else if (stype == AUX)
+    {
+      switch (type)
+       {
+       case Histable::INSTR:
+         {
+           DbeInstr *instr1 = (DbeInstr*) hi_1->obj;
+           DbeInstr *instr2 = (DbeInstr*) hi_2->obj;
+           result = instr1 ? instr1->pc_cmp (instr2) : instr2 ? 1 : 0;
+           break;
+         }
+       case Histable::LINE:
+         {
+           DbeLine *dbl1 = (DbeLine*) hi_1->obj;
+           DbeLine *dbl2 = (DbeLine*) hi_2->obj;
+           result = dbl1->line_cmp (dbl2);
+         }
+         break;
+       default:
+         assert (0);
+       }
+    }
+  else if (stype == VALUE)
+    {
+      Metric *m = hdata->get_metric_list ()->get (ind);
+      if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0)
+       {
+         TValue v1, v2;
+         int first_ind = hdata->hist_metrics[ind].indFirstExp;
+         if ((m->get_visbits () & VAL_DELTA) != 0)
+           {
+             v1.make_delta (hi_1->value + ind, hi_1->value + first_ind);
+             v2.make_delta (hi_2->value + ind, hi_2->value + first_ind);
+           }
+         else
+           {
+             v1.make_ratio (hi_1->value + ind, hi_1->value + first_ind);
+             v2.make_ratio (hi_2->value + ind, hi_2->value + first_ind);
+           }
+         result = v1.compare (&v2);
+       }
+      else
+       result = hi_1->value[ind].compare (hi_2->value + ind);
+    }
+  return result;
+}
+
+int
+Hist_data::sort_compare_all (const void *a, const void *b, const void *arg)
+{
+  HistItem *hi_1 = *((HistItem **) a);
+  HistItem *hi_2 = *((HistItem **) b);
+
+  Hist_data *hdata = (Hist_data*) arg;
+  int result = sort_compare (hi_1, hi_2, hdata->sort_type, hdata->sort_ind, hdata);
+  if (hdata->sort_order == DESCEND)
+    result = -result;
+
+  // Use the name as the 2d sort key (always ASCEND)
+  // except for MemoryObjects and  IndexObjects, where the index is used
+  // For the Alphabetic sort
+  if (result == 0)
+    {
+      result = sort_compare (hi_1, hi_2, ALPHA, 0, NULL);
+      if (result == 0)
+       {
+         for (long i = 0, sz = hdata->metrics->size (); i < sz; i++)
+           {
+             Metric *m = hdata->metrics->get (i);
+             if (m->get_type () != Metric::ONAME)
+               {
+                 result = sort_compare (hi_1, hi_2, VALUE, i, hdata);
+                 if (result != 0)
+                   {
+                     if (hdata->sort_order == DESCEND)
+                       result = -result;
+                     break;
+                   }
+               }
+           }
+       }
+    }
+
+  // Use the address as the 3d sort key
+  // ( FUNCTION only, always ASCEND )
+  if (result == 0 && hi_1->obj->get_type () == Histable::FUNCTION)
+    {
+      Function *f1 = (Function*) hi_1->obj;
+      Function *f2 = (Function*) hi_2->obj;
+      if (f1->get_addr () < f2->get_addr ())
+       result = -1;
+      else if (f1->get_addr () > f2->get_addr ())
+       result = 1;
+    }
+
+  // Use the Histable id (ID of function, line, etc.) as the 4th sort key
+  // Note that IDs are not guaranteed to be stable,
+  if (result == 0)
+    {
+      if (hi_1->obj->id < hi_2->obj->id)
+       result = -1;
+      else if (hi_1->obj->id > hi_2->obj->id)
+       result = 1;
+    }
+
+  if (result == 0)
+    return result; // shouldn't happen in most cases; line allows for breakpoint
+  if (hdata->rev_sort)
+    result = -result;
+  return result;
+}
+
+int
+Hist_data::sort_compare_dlayout (const void *a, const void *b, const void *arg)
+{
+  assert ((a != (const void *) NULL));
+  assert ((b != (const void *) NULL));
+  HistItem *hi_1 = *((HistItem **) a);
+  HistItem *hi_2 = *((HistItem **) b);
+  DataObject * dobj1 = (DataObject *) (hi_1->obj);
+  DataObject * dobj2 = (DataObject *) (hi_2->obj);
+  DataObject * parent1 = dobj1->parent;
+  DataObject * parent2 = dobj2->parent;
+
+  Hist_data *hdata = (Hist_data*) arg;
+
+  // are the two items members of the same object?
+  if (parent1 == parent2)
+    {
+      // yes
+      if (parent1)
+       {
+         // and they have real parents...
+         if (parent1->get_typename ())
+           { // element
+             // use dobj1/dobj2 offset for sorting
+             uint64_t off1 = dobj1->get_offset ();
+             uint64_t off2 = dobj2->get_offset ();
+             if (off1 < off2)
+               return -1;
+             if (off1 > off2)
+               return 1;
+             return 0;
+           }
+       }
+    }
+  else
+    { // parents differ
+      if (parent1)
+       {
+         if (parent1 == dobj2)
+           // sorting an object and its parent: parent always first
+           return 1;
+         dobj1 = parent1;
+       }
+      if (parent2)
+       {
+         if (parent2 == dobj1)
+           return -1;
+         dobj2 = parent2;
+       }
+    }
+  //  Either two unknowns, or two scalars, or two parents
+  hi_1 = hdata->hi_map->get (dobj1);
+  hi_2 = hdata->hi_map->get (dobj2);
+  return sort_compare_all ((const void*) &hi_1, (const void*) &hi_2, hdata);
+}
+
+Hist_data::Hist_data (MetricList *_metrics, Histable::Type _type,
+                     Hist_data::Mode _mode, bool _viewowned)
+{
+  hist_items = new Vector<HistItem*>;
+  metrics = _metrics;
+  nmetrics = metrics->get_items ()->size ();
+  type = _type;
+  mode = _mode;
+  gprof_item = new_hist_item (NULL);
+  viewowned = _viewowned;
+  sort_ind = -1;
+  rev_sort = false;
+
+  Histable *tobj = new Other;
+  tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"));
+  minimum = new_hist_item (tobj);
+
+  tobj = new Other;
+  tobj->name = dbe_strdup (NTXT (""));
+  maximum = new_hist_item (tobj);
+
+  tobj = new Other;
+  tobj->name = dbe_strdup (NTXT ("xxxxxxxxxxxxxxxxxxxxxx"));
+  maximum_inc = new_hist_item (tobj);
+
+  tobj = new Other;
+  tobj->name = dbe_strdup (NTXT ("<Total>"));
+  total = new_hist_item (tobj);
+
+  tobj = new Other;
+  tobj->name = dbe_strdup (NTXT ("XXXX Threshold XXXX"));
+  threshold = new_hist_item (tobj);
+
+  hi_map = new HashMap<Histable*, HistItem*>;
+  callsite_mark = new DefaultMap<Histable*, int>;
+  hist_metrics = new Metric::HistMetric[metrics->size ()];
+  for (long i = 0, sz = metrics->size (); i < sz; i++)
+    {
+      Metric::HistMetric *h = hist_metrics + i;
+      h->init ();
+      Metric *m = metrics->get (i);
+      if (0 != (m->get_visbits () & (VAL_DELTA | VAL_RATIO)))
+       h->indFirstExp =
+             metrics->get_listorder (m->get_cmd (),
+                                     m->get_subtype (), "EXPGRID==1");
+      if (m->is_tvisible () && m->get_type () == BaseMetric::HWCNTR
+         && m->get_dependent_bm ())
+       h->indTimeVal =
+             metrics->get_listorder (m->get_dependent_bm ()->get_cmd (),
+                                     m->get_subtype (), m->get_expr_spec ());
+    }
+  status = NO_DATA;
+}
+
+Hist_data::~Hist_data ()
+{
+  delete[] hist_metrics;
+  if (hist_items)
+    {
+      hist_items->destroy ();
+      delete hist_items;
+      hist_items = NULL;
+    }
+  if (gprof_item)
+    {
+      delete gprof_item;
+      gprof_item = NULL;
+    }
+  if (maximum)
+    {
+      delete maximum->obj;
+      delete maximum;
+      maximum = NULL;
+    }
+  if (maximum_inc)
+    {
+      delete maximum_inc->obj;
+      delete maximum_inc;
+      maximum_inc = NULL;
+    }
+  if (minimum)
+    {
+      delete minimum->obj;
+      delete minimum;
+      minimum = NULL;
+    }
+  if (total)
+    {
+      delete total->obj;
+      delete total;
+      total = NULL;
+    }
+  if (threshold)
+    {
+      delete threshold->obj;
+      delete threshold;
+      threshold = NULL;
+    }
+  delete metrics;
+  delete hi_map;
+  delete callsite_mark;
+}
+
+void
+Hist_data::dump (char *msg, FILE *f)
+{
+  fprintf (f, "   Hist_data dump:  %s\n", msg);
+  fprintf (f, "      %d=%d metrics\n", (int) nmetrics, (int) metrics->size ());
+  for (int i = 0; i < nmetrics; i++)
+    {
+      Metric *m = metrics->get_items ()->fetch (i);
+      char *s = m->get_expr_spec ();
+      fprintf (f, "          %4d %15s %4d %15s\n", i, m->get_mcmd (0),
+              m->get_id (), s ? s : "(NULL)");
+    }
+
+  fprintf (f, NTXT ("      HistItem listing\n"));
+  int n = hist_items->size ();
+  for (int j = -1; j < n; j++)
+    {
+      HistItem *hi;
+      if (j < 0)
+       {
+         hi = total;
+         fprintf (f, NTXT ("                         total"));
+       }
+      else
+       {
+         hi = hist_items->fetch (j);
+         fprintf (f, NTXT ("%30s"), hi->obj->get_name ());
+       }
+      for (int i = 0; i < nmetrics; i++)
+       {
+         char *stmp = hi->value[i].l;
+         switch (hi->value[i].tag)
+           {
+           case VT_SHORT: fprintf (f, NTXT (" %d"), hi->value[i].s);
+             break;
+           case VT_INT: fprintf (f, NTXT (" %d"), hi->value[i].i);
+             break;
+           case VT_LLONG: fprintf (f, NTXT (" %12lld"), hi->value[i].ll);
+             break;
+           case VT_FLOAT: fprintf (f, NTXT (" %f"), hi->value[i].f);
+             break;
+           case VT_DOUBLE: fprintf (f, NTXT (" %12.6lf"), hi->value[i].d);
+             break;
+           case VT_HRTIME: fprintf (f, NTXT (" %12llu"), hi->value[i].ull);
+             break;
+           case VT_LABEL: fprintf (f, NTXT (" %s"), stmp ? stmp: "(unnamed)");
+             break;
+           case VT_ADDRESS: fprintf (f, NTXT (" %12lld"), hi->value[i].ll);
+             break;
+           case VT_OFFSET: fprintf (f, NTXT (" %p"), hi->value[i].p);
+             break;
+           case VT_ULLONG: fprintf (f, NTXT (" %12llu"), hi->value[i].ull);
+             break;
+           default: fprintf (f, NTXT ("     "));
+             break;
+           }
+       }
+      fprintf (f, NTXT ("\n"));
+    }
+}
+
+void
+Hist_data::sort (long ind, bool reverse)
+{
+  if (mode != MODL && ind != -1 && ind == sort_ind && reverse == rev_sort)
+    // there's no change to the sorting
+    return;
+
+  if (mode == MODL)
+    {
+      sort_type = AUX;
+      sort_order = ASCEND;
+    }
+  else
+    {
+      if (ind == -1)
+       return;
+      Metric::Type mtype = metrics->get_items ()->fetch (ind)->get_type ();
+      sort_type = mtype == Metric::ONAME ? ALPHA : VALUE;
+      sort_order = (mtype == Metric::ONAME || mtype == Metric::ADDRESS) ?
+             ASCEND : DESCEND;
+      sort_ind = ind;
+      rev_sort = reverse;
+    }
+
+  if (mode == Hist_data::LAYOUT || mode == Hist_data::DETAIL)
+    hist_items->sort ((CompareFunc) sort_compare_dlayout, this);
+  else
+    hist_items->sort ((CompareFunc) sort_compare_all, this);
+
+  // ensure that <Total> comes first/last
+  char *tname = NTXT ("<Total>");
+  for (int i = 0; i < hist_items->size (); ++i)
+    {
+      HistItem *hi = hist_items->fetch (i);
+      char *name = hi->obj->get_name ();
+      if (name != NULL && streq (name, tname))
+       {
+         int idx0 = rev_sort ? hist_items->size () - 1 : 0;
+         if (i != idx0)
+           {
+             hist_items->remove (i);
+             hist_items->insert (idx0, hi);
+           }
+         break;
+       }
+    }
+}
+
+void
+Hist_data::resort (MetricList *mlist)
+{
+  if (mlist->get_type () != metrics->get_type ())
+    if (metrics->get_type () == MET_CALL)
+      // wrong type of list -- internal error
+      abort ();
+
+  // get the new sort order
+  int ind = mlist->get_sort_ref_index ();
+  bool reverse = mlist->get_sort_rev ();
+  sort (ind, reverse);
+}
+
+void
+Hist_data::compute_minmax ()
+{
+  HistItem *hi;
+  int index;
+
+  for (int mind = 0; mind < nmetrics; mind++)
+    {
+      Metric *mtr = metrics->get_items ()->fetch (mind);
+      if (mtr->get_subtype () == Metric::STATIC)
+       continue;
+      if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
+       continue;
+      ValueTag vtype = mtr->get_vtype2 ();
+
+      switch (vtype)
+       {
+       case VT_INT:
+         minimum->value[mind].tag = VT_INT;
+         minimum->value[mind].i = 0;
+         maximum->value[mind].tag = VT_INT;
+         maximum->value[mind].i = 0;
+         maximum_inc->value[mind].tag = VT_INT;
+         maximum_inc->value[mind].i = 0;
+
+         Vec_loop (HistItem *, hist_items, index, hi)
+         {
+           if (metrics->get_type () == MET_SRCDIS
+               && callsite_mark->get (hi->obj))
+             {
+               if (hi->value[mind].i > maximum_inc->value[mind].i)
+                 maximum_inc->value[mind].i = hi->value[mind].i;
+               // ignore ones that has inclusive time for src/dis view
+             }
+           else if (hi->value[mind].i > maximum->value[mind].i)
+             maximum->value[mind].i = hi->value[mind].i;
+           if (hi->value[mind].i < minimum->value[mind].i)
+             minimum->value[mind].i = hi->value[mind].i;
+         }
+         break;
+       case VT_DOUBLE:
+         minimum->value[mind].tag = VT_DOUBLE;
+         minimum->value[mind].d = 0.0;
+         maximum->value[mind].tag = VT_DOUBLE;
+         maximum->value[mind].d = 0.0;
+         maximum_inc->value[mind].tag = VT_DOUBLE;
+         maximum_inc->value[mind].d = 0.0;
+         Vec_loop (HistItem*, hist_items, index, hi)
+         {
+           if (metrics->get_type () == MET_SRCDIS && callsite_mark->get (hi->obj))
+             {
+               if (hi->value[mind].d > maximum_inc->value[mind].d)
+                 {
+                   maximum_inc->value[mind].d = hi->value[mind].d;
+                   maximum_inc->value[mind].sign = hi->value[mind].sign;
+                 }
+               // ignore ones that has inclusive time for src/dis view
+             }
+           else
+             {
+               if (hi->value[mind].d > maximum->value[mind].d)
+                 {
+                   maximum->value[mind].d = hi->value[mind].d;
+                   maximum->value[mind].sign = hi->value[mind].sign;
+                 }
+               if (hi->value[mind].d < minimum->value[mind].d)
+                 {
+                   minimum->value[mind].d = hi->value[mind].d;
+                   minimum->value[mind].sign = hi->value[mind].sign;
+                 }
+             }
+         }
+         break;
+       case VT_LLONG:
+       case VT_ULLONG:
+       case VT_ADDRESS:
+         minimum->value[mind].tag = vtype;
+         minimum->value[mind].ll = 0;
+         maximum->value[mind].tag = vtype;
+         maximum->value[mind].ll = 0;
+         maximum_inc->value[mind].tag = vtype;
+         maximum_inc->value[mind].ll = 0;
+         Vec_loop (HistItem*, hist_items, index, hi)
+         {
+           if (metrics->get_type () == MET_SRCDIS && callsite_mark->get (hi->obj))
+             {
+               if (hi->value[mind].ll > maximum_inc->value[mind].ll)
+                 {
+                   maximum_inc->value[mind].ll = hi->value[mind].ll;
+                   maximum_inc->value[mind].sign = hi->value[mind].sign;
+                 }
+               // ignore ones that has inclusive time for src/dis view
+             }
+           else
+             {
+               if (hi->value[mind].ll > maximum->value[mind].ll)
+                 {
+                   maximum->value[mind].ll = hi->value[mind].ll;
+                   maximum->value[mind].sign = hi->value[mind].sign;
+                 }
+               if (hi->value[mind].ll < minimum->value[mind].ll)
+                 {
+                   minimum->value[mind].ll = hi->value[mind].ll;
+                   minimum->value[mind].sign = hi->value[mind].sign;
+                 }
+             }
+         }
+         break;
+       default:
+         break;
+       }
+    }
+}
+
+Hist_data::HistItem *
+Hist_data::new_hist_item (Histable *obj)
+{
+  long sz = get_metric_list ()->size ();
+  HistItem *hi = new HistItem (sz);
+  hi->obj = obj;
+
+  // We precalculate all metrics as integer values
+  // and convert them to appropriate types later.
+  for (long i = 0; i < sz; i++)
+    {
+      hi->value[i].tag = VT_INT;
+      hi->value[i].i = 0;
+    }
+  return hi;
+}
+
+Hist_data::HistItem *
+Hist_data::new_hist_item (Histable *obj, int itype, TValue *value)
+{
+  long sz = get_metric_list ()->size ();
+  HistItem *hi = new HistItem (sz);
+  hi->obj = obj;
+  hi->type = itype;
+  if (value)
+    for (long i = 0; i < sz; i++)
+      hi->value[i] = value[i];
+
+  return hi;
+}
+
+Hist_data::HistItem *
+Hist_data::find_hist_item (Histable *obj)
+{
+  if (obj == NULL)
+    return NULL;
+  return hi_map->get (obj);
+}
+
+Hist_data::HistItem *
+Hist_data::append_hist_item (Histable *obj)
+{
+  if (obj == NULL)
+    return NULL;
+  HistItem *hi = hi_map->get (obj);
+  if (hi == NULL)
+    {
+      hi = new_hist_item (obj);
+      hist_items->append (hi);
+      hi_map->put (obj, hi);
+    }
+  if (status == NO_DATA)
+    status = SUCCESS;
+  return hi;
+}
+
+void
+Hist_data::append_hist_item (HistItem *hi)
+{
+  hist_items->append (hi);
+}
+
+bool
+Hist_data::above_threshold (HistItem* hi)
+{
+  bool mark = false;
+  int index;
+  Metric *mitem;
+
+  Vec_loop (Metric*, metrics->get_items (), index, mitem)
+  {
+    if (mitem->get_subtype () == Metric::STATIC)
+      continue;
+    switch (hi->value[index].tag)
+      {
+      case VT_DOUBLE:
+       if (hi->value[index].d > threshold->value[index].d)
+         mark = true;
+       break;
+      case VT_INT:
+       if (hi->value[index].i > threshold->value[index].i)
+         mark = true;
+       break;
+      case VT_LLONG:
+       if (hi->value[index].ll > threshold->value[index].ll)
+         mark = true;
+       break;
+      case VT_ULLONG:
+       if (hi->value[index].ull > threshold->value[index].ull)
+         mark = true;
+       break;
+       // ignoring the following cases (why?)
+      case VT_SHORT:
+      case VT_FLOAT:
+      case VT_HRTIME:
+      case VT_LABEL:
+      case VT_ADDRESS:
+      case VT_OFFSET:
+       break;
+      }
+  }
+  return mark;
+}
+
+void
+Hist_data::set_threshold (double proportion)
+{
+  int index;
+  Metric *mitem;
+  Vec_loop (Metric*, metrics->get_items (), index, mitem)
+  {
+    TValue *thresh = &threshold->value[index];
+    TValue *mtotal = &total->value[index];
+    thresh->tag = mitem->get_vtype ();
+
+    if (mitem->get_subtype () == Metric::STATIC)
+      continue;
+    switch (thresh->tag)
+      {
+      case VT_INT:
+       thresh->i = (int) (proportion * (double) mtotal->i);
+       break;
+      case VT_DOUBLE:
+       thresh->d = proportion * mtotal->d;
+       break;
+      case VT_LLONG:
+      case VT_ULLONG:
+       thresh->ull = (unsigned long long) (proportion * (double) mtotal->ll);
+       break;
+      case VT_SHORT:
+      case VT_FLOAT:
+      case VT_HRTIME:
+      case VT_LABEL:
+      case VT_ADDRESS:
+      case VT_OFFSET:
+       break;
+      }
+  }
+}
+
+double
+Hist_data::get_percentage (double value, int mindex)
+{
+  double total_value;
+  if (value == 0.0)
+    return 0.0;
+
+  // Get the total value of this sample set.
+  // The value must be greater than 0.
+  total_value = total->value[mindex].to_double ();
+
+  // Find out what percentage of the total value this item is.
+  // Make sure we don't divide by zero.
+  if (total_value == 0.0)
+    return 0.0;
+  return value / total_value;
+}
+
+int
+Hist_data::print_label (FILE *out_file, Metric::HistMetric *hist_metric,
+                       int space)
+{
+  int name_offset = 0;
+  StringBuilder sb, sb1, sb2, sb3;
+  if (space > 0)
+    {
+      char *fmt = NTXT ("%*s");
+      sb.appendf (fmt, space, NTXT (""));
+      sb1.appendf (fmt, space, NTXT (""));
+      sb2.appendf (fmt, space, NTXT (""));
+      sb3.appendf (fmt, space, NTXT (""));
+    }
+  for (int i = 0; i < nmetrics; i++)
+    {
+      Metric *m = metrics->get (i);
+      Metric::HistMetric *hm = &hist_metric[i];
+      int len = hm->width;
+      char *fmt = NTXT ("%-*s");
+      if ((i > 0) && (m->get_type () == Metric::ONAME))
+       {
+         name_offset = sb1.length ();
+         fmt = NTXT (" %-*s");
+         len--;
+       }
+      sb.appendf (fmt, len, m->legend ? m->legend : NTXT (""));
+      sb1.appendf (fmt, len, hm->legend1);
+      sb2.appendf (fmt, len, hm->legend2);
+      sb3.appendf (fmt, len, hm->legend3);
+    }
+  sb.trim ();
+  if (sb.length () != 0)
+    {
+      sb.toFileLn (out_file);
+    }
+  sb1.toFileLn (out_file);
+  sb2.toFileLn (out_file);
+  sb3.toFileLn (out_file);
+  return name_offset;
+}
+
+void
+Hist_data::print_content (FILE *out_file, Metric::HistMetric *hist_metric, int limit)
+{
+  StringBuilder sb;
+  int cnt = VecSize (hist_items);
+  if (cnt > limit && limit > 0)
+    cnt = limit;
+  for (int i = 0; i < cnt; i++)
+    {
+      sb.setLength (0);
+      print_row (&sb, i, hist_metric, NTXT (" "));
+      sb.toFileLn (out_file);
+    }
+}
+
+static void
+append_str (StringBuilder *sb, char *s, size_t len, int vis_bits)
+{
+  if ((vis_bits & VAL_RATIO) != 0)
+    {
+      if (*s != 'N')    // Nan
+       sb->appendf (NTXT ("x "));
+      else
+       sb->appendf (NTXT ("  "));
+      sb->appendf (NTXT ("%*s"), (int) (len - 2), s);
+    }
+  else
+    sb->appendf (NTXT ("%*s"), (int) len, s);
+}
+
+void
+Hist_data::print_row (StringBuilder *sb, int row, Metric::HistMetric *hmp, char *mark)
+{
+  TValue res;
+  char buf[256];
+  // Print only a list of user's metrics. ( nmetrics <= mlist->size() )
+  for (long i = 0; i < nmetrics; i++)
+    {
+      // Print only a list of user's metrics.
+      Metric *m = metrics->get (i);
+      if (!m->is_any_visible ())
+       continue;
+      Metric::HistMetric *hm = hmp + i;
+      int len = sb->length ();
+      if (m->is_tvisible ())
+       {
+         TValue *v = get_value (&res, hist_metrics[i].indTimeVal, row);
+         char *s = v->to_str (buf, sizeof (buf));
+         append_str (sb, s, hm->maxtime_width, m->get_visbits ());
+       }
+      if (m->is_visible ())
+       {
+         TValue *v = get_value (&res, i, row);
+         char *s = v->to_str (buf, sizeof (buf));
+         if (m->get_type () == BaseMetric::ONAME)
+           {
+             sb->append (mark);
+             if (i + 1 == nmetrics)
+               sb->appendf (NTXT ("%s"), s);
+             else
+               sb->appendf (NTXT ("%-*s "), (int) hm->maxvalue_width, s);
+             continue;
+           }
+         else
+           {
+             if (len != sb->length ())
+               sb->append (' ');
+             append_str (sb, s, hm->maxvalue_width, m->get_visbits ());
+           }
+       }
+      if (m->is_pvisible ())
+       {
+         if (len != sb->length ())
+           sb->append (' ');
+         long met_ind = i;
+         if (m->is_tvisible () && !m->is_visible ())
+           met_ind = hist_metrics[i].indTimeVal;
+         TValue *v = get_real_value (&res, met_ind, row);
+         double percent = get_percentage (v->to_double (), met_ind);
+         if (percent == 0.0)
+           // adjust to change format from xx.yy%
+           sb->append (NTXT ("  0.  "));
+         else
+           // adjust format below to change format from xx.yy%
+           sb->appendf (NTXT ("%6.2f"), (100.0 * percent));
+       }
+      len = sb->length () - len;
+      if (hm->width > len && i + 1 != nmetrics)
+       sb->appendf (NTXT ("%*s"), (int) (hm->width - len), NTXT (" "));
+    }
+}
+
+TValue *
+Hist_data::get_real_value (TValue *res, int met_index, int row)
+{
+  HistItem *hi = hist_items->get (row);
+  Metric *m = metrics->get (met_index);
+  if (m->get_type () == BaseMetric::ONAME)
+    {
+      res->l = dbe_strdup (hi->obj->get_name ());
+      res->tag = VT_LABEL;
+      return res;
+    }
+  return hi->value + met_index;
+}
+
+TValue *
+Hist_data::get_value (TValue *res, int met_index, int row)
+{
+  HistItem *hi = hist_items->get (row);
+  Metric *m = metrics->get (met_index);
+  if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0)
+    {
+      int ind = hist_metrics[met_index].indFirstExp;
+      if ((m->get_visbits () & VAL_DELTA) != 0)
+       res->make_delta (hi->value + met_index, hi->value + ind);
+      else
+       res->make_ratio (hi->value + met_index, hi->value + ind);
+      return res;
+    }
+  return get_real_value (res, met_index, row);
+}
+
+TValue *
+Hist_data::get_value (TValue *res, int met_index, HistItem *hi)
+{
+  Metric *m = metrics->get (met_index);
+  if ((m->get_visbits () & (VAL_DELTA | VAL_RATIO)) != 0)
+    {
+      int ind = hist_metrics[met_index].indFirstExp;
+      if ((m->get_visbits () & VAL_DELTA) != 0)
+       res->make_delta (hi->value + met_index, hi->value + ind);
+      else
+       res->make_ratio (hi->value + met_index, hi->value + ind);
+      return res;
+    }
+  if (m->get_type () == BaseMetric::ONAME)
+    {
+      res->l = dbe_strdup (hi->obj->get_name ());
+      res->tag = VT_LABEL;
+      return res;
+    }
+  return hi->value + met_index;
+}
+
+Metric::HistMetric *
+Hist_data::get_histmetrics ()
+{
+  // find the width for each column.
+  for (long i = 0, sz = metrics->size (); i < sz; i++)
+    {
+      Metric *m = metrics->get (i);
+      Metric::HistMetric *hm = hist_metrics + i;
+      if (m->is_value_visible ())
+       {
+         TValue res;
+         for (long i1 = 0, sz1 = VecSize(hist_items); i1 < sz1; i1++)
+           {
+             TValue *v = get_value (&res, i, i1);
+             long len = v->get_len ();
+             if (hm->maxvalue_width < len)
+               hm->maxvalue_width = len;
+           }
+         if ((m->get_visbits () & VAL_RATIO) != 0)
+           hm->maxvalue_width += 2; // "x "
+       }
+    }
+
+  for (long i = 0, sz = metrics->size (); i < sz; i++)
+    {
+      Metric *m = metrics->get (i);
+      Metric::HistMetric *hm = hist_metrics + i;
+      if (m->is_time_visible ())
+       // take a value from depended metric
+       hm->maxtime_width = hist_metrics[hm->indTimeVal].maxvalue_width;
+      m->legend_width (hm, 2);
+    }
+  return hist_metrics;
+}
+
+void
+Hist_data::update_total (Hist_data::HistItem *new_total)
+{
+  for (long i = 0, sz = metrics->size (); i < sz; i++)
+    total->value[i] = new_total->value[i];
+}
+
+void
+Hist_data::update_max (Metric::HistMetric *hm_tmp)
+{
+  Metric::HistMetric *hms = get_histmetrics ();
+  for (int i = 0; i < nmetrics; i++)
+    {
+      Metric::HistMetric *hm = hms + i;
+      Metric::HistMetric *hm1 = hm_tmp + i;
+      if (hm1->maxtime_width < hm->maxtime_width)
+       hm1->maxtime_width = hm->maxtime_width;
+      if (hm1->maxvalue_width < hm->maxvalue_width)
+       hm1->maxvalue_width = hm->maxvalue_width;
+    }
+}
+
+void
+Hist_data::update_legend_width (Metric::HistMetric *hm_tmp)
+{
+  for (int i = 0; i < nmetrics; i++)
+    {
+      Metric *m = metrics->get (i);
+      m->legend_width (hm_tmp + i, 2);
+    }
+}
+
+void
+Metric::HistMetric::update_max (Metric::HistMetric *hm)
+{
+  if (maxtime_width < hm->maxtime_width)
+    maxtime_width = hm->maxtime_width;
+  if (maxvalue_width < hm->maxvalue_width)
+    maxvalue_width = hm->maxvalue_width;
+}
+
+void
+Metric::HistMetric::init ()
+{
+  width = 0;
+  maxvalue_width = 0;
+  maxtime_width = 0;
+  legend1[0] = 0;
+  legend2[0] = 0;
+  legend3[0] = 0;
+  indFirstExp = -1;
+  indTimeVal = -1;
+}
+
+size_t
+Hist_data::value_maxlen (int mindex)
+{
+  size_t maxlen = maximum->value[mindex].get_len ();
+  size_t minlen = minimum->value[mindex].get_len ();
+  // minlen can be bigger than maxlen only for negative value
+  return minlen > maxlen ? minlen : maxlen;
+}
+
+size_t
+Hist_data::time_len (TValue *value, int clock)
+{
+  TValue tm_value;
+  tm_value.tag = VT_DOUBLE;
+  tm_value.sign = value->sign;
+  tm_value.d = 1.e-6 * value->ll / clock;
+  return tm_value.get_len ();
+}
+
+size_t
+Hist_data::time_maxlen (int mindex, int clock)
+{
+  size_t maxlen = time_len (&(maximum->value[mindex]), clock);
+  size_t minlen = time_len (&(minimum->value[mindex]), clock);
+  // minlen can be bigger than maxlen only for negative value
+  return minlen > maxlen ? minlen : maxlen;
+}
+
+size_t
+Hist_data::name_len (HistItem *item)
+{
+  char *name = item->obj->get_name ();
+  return strlen (name);
+}
+
+size_t
+Hist_data::name_maxlen ()
+{
+  size_t res = 0;
+  for (long i = 0; i < size (); i++)
+    {
+      HistItem *hi = fetch (i);
+      size_t len = name_len (hi);
+      if (res < len)
+       res = len;
+    }
+  return res;
+}
+
+// Returns vector of object ids for the vector of selections
+//     returns NULL if no valid selections
+Vector<uint64_t> *
+Hist_data::get_object_indices (Vector<int> *selections)
+{
+  // if no selections, return NULL
+  if (selections == NULL || selections->size () == 0)
+    return NULL;
+
+  Vector<uint64_t> *indices = new Vector<uint64_t>;
+  for (long i = 0, sz = selections->size (); i < sz; i++)
+    {
+      int sel = selections->get (i);
+      HistItem *hi = hist_items->get (sel);
+      if (hi == NULL || hi->obj == NULL)
+       continue;
+      Vector<Histable*> *v = hi->obj->get_comparable_objs ();
+      for (long i1 = 0, sz1 = v ? v->size () : 0; i1 < sz1; i1++)
+       {
+         Histable *h1 = v->get (i1);
+         if (h1 && (indices->find_r (h1->id) < 0))
+           indices->append (h1->id);
+       }
+      if (indices->find_r (hi->obj->id) < 0)
+       indices->append (hi->obj->id);
+    }
+  return indices;
+}
+
+DbeInstr::DbeInstr (uint64_t _id, int _flags, Function *_func, uint64_t _addr)
+{
+  id = _id;
+  flags = _flags;
+  addr = _addr;
+  func = _func;
+  img_offset = addr + func->img_offset;
+  lineno = -1;
+  size = 0;
+  current_name_format = NA;
+  isUsed = false;
+  inlinedInd = -1;
+}
+
+int
+DbeInstr::pc_cmp (DbeInstr *instr2)
+{
+  int result = 0;
+  if (instr2 == NULL)
+    return -1;
+
+  // All PC's with the Line flag go to the
+  // end of the list. See Module::init_index()
+  if (flags & PCLineFlag)
+    {
+      if (instr2->flags & PCLineFlag)
+       {
+         if (addr < instr2->addr)
+           result = -1;
+         else if (addr > instr2->addr)
+           result = 1;
+         else
+           result = 0;
+       }
+      else
+       result = 1;
+    }
+  else if (instr2->flags & PCLineFlag)
+    result = -1;
+  else if (func == instr2->func)
+    {
+      if (size == 0)
+       {
+         if (addr < instr2->addr)
+           result = -1;
+         else if (addr == instr2->addr)
+           result = 0;
+         else if (addr >= instr2->addr + instr2->size)
+           result = 1;
+         else
+           result = 0;
+       }
+      else if (instr2->size == 0)
+       {
+         if (addr > instr2->addr)
+           result = 1;
+         else if (addr + size <= instr2->addr)
+           result = -1;
+         else
+           result = 0;
+       }
+      else if (addr < instr2->addr)
+       result = -1;
+      else if (addr > instr2->addr)
+       result = 1;
+      else
+       result = 0;
+
+      if (result == 0)
+       {
+         if (flags & PCTrgtFlag)
+           {
+             if (!(instr2->flags & PCTrgtFlag))
+               result = -1;
+           }
+         else if (instr2->flags & PCTrgtFlag)
+           result = 1;
+       }
+    }
+  else
+    result = func->func_cmp (instr2->func);
+  return result;
+}
+
+char *
+DbeInstr::get_name (NameFormat nfmt)
+{
+  if (name && (nfmt == current_name_format || nfmt == Histable::NA))
+    return name;
+
+  free (name);
+  name = NULL;
+  current_name_format = nfmt;
+  char *fname = func->get_name (nfmt);
+
+  if (func->flags & FUNC_FLAG_NO_OFFSET)
+    name = dbe_strdup (fname);
+  else if (addr == (uint64_t) - 1
+          && func != dbeSession->get_JUnknown_Function ())
+    // We use three heuristics above to recognize this special case.
+    // Once the original problem with bci == -1 is fixed, we don't
+    // need it any more.
+    name = dbe_sprintf (GTXT ("<Function %s: HotSpot-compiled leaf instructions>"),
+                       fname);
+  else if (addr == (uint64_t) - 3)
+    name = dbe_sprintf (GTXT ("%s <Java native method>"), fname);
+  else
+    {
+      char buf[64], *typetag = NTXT (""), *alloc_typetag = NULL;
+      StringBuilder sb;
+      sb.append (fname);
+      if (func != dbeSession->get_JUnknown_Function ())
+       {
+         if (addr <= 0xFFFFFFFFU)
+           snprintf (buf, sizeof (buf), " + 0x%08X", (unsigned int) addr);
+         else
+           snprintf (buf, sizeof (buf), " + 0x%016llX",
+                     (unsigned long long) addr);
+       }
+      else
+       {
+         char *subname;
+         switch ((long int) addr)
+           {
+           case -1:
+             subname = GTXT ("agent error");
+             break;
+           case -2:
+             subname = GTXT ("GC active");
+             break;
+           case -3:
+             subname = GTXT ("unknown non-Java frame");
+             break;
+           case -4:
+             subname = GTXT ("unwalkable non-Java frame");
+             break;
+           case -5:
+             subname = GTXT ("unknown Java frame");
+             break;
+           case -6:
+             subname = GTXT ("unwalkable Java frame");
+             break;
+           case -7:
+             subname = GTXT ("unknown thread state");
+             break;
+           case -8:
+             subname = GTXT ("thread in exit");
+             break;
+           case -9:
+             subname = GTXT ("deopt in process ticks");
+             break;
+           case -10:
+             subname = GTXT ("safepoint synchronizing ticks");
+             break;
+           default:
+             subname = GTXT ("unexpected error");
+             break;
+           }
+         snprintf (buf, sizeof (buf), "<%s (%d)>", subname, (int) addr);
+       }
+      sb.append (buf);
+      if (flags & PCTrgtFlag)
+       // annotate synthetic instruction
+       sb.append ('*'); // special distinguishing marker
+
+      DbeLine *dbeline = mapPCtoLine (NULL);
+      char *str = NULL;
+      if (dbeline && dbeline->lineno > 0)
+       str = strrchr (dbeline->get_name (nfmt), ',');
+      if (str)
+       sb.append (str);
+      if (strlen (typetag) > 0)
+       { // include padding for alignment
+         do
+           {
+             sb.append (' ');
+           }
+         while (sb.length () < 40);
+         sb.append (typetag);
+         delete alloc_typetag;
+       }
+      if (inlinedInd >= 0)
+       add_inlined_info (&sb);
+      name = sb.toString ();
+    }
+  return name;
+}
+
+DbeLine*
+DbeInstr::mapPCtoLine (SourceFile *sf)
+{
+  if (inlinedInd == -1)
+    {
+      inlinedInd = -2;
+      for (int i = 0; i < func->inlinedSubrCnt; i++)
+       {
+         InlinedSubr *p = func->inlinedSubr + i;
+         if (p->level == 0)
+           {
+             if (addr < p->low_pc)
+               break;
+             if (p->contains (addr))
+               {
+                 inlinedInd = i;
+                 break;
+               }
+           }
+       }
+    }
+  if (inlinedInd >= 0)
+    {
+      DbeLine *dl = func->inlinedSubr[inlinedInd].dbeLine;
+      return dl->sourceFile->find_dbeline (func, dl->lineno);
+    }
+  return func->mapPCtoLine (addr, sf);
+}
+
+void
+DbeInstr::add_inlined_info (StringBuilder *sb)
+{
+  do
+    {
+      sb->append (' ');
+    }
+  while (sb->length () < 40);
+  sb->append (NTXT ("<-- "));
+
+  InlinedSubr *last = NULL;
+  for (int i = inlinedInd; i < func->inlinedSubrCnt; i++)
+    {
+      InlinedSubr *p = func->inlinedSubr + i;
+      if (p->level == 0 && i > inlinedInd)
+       break;
+      if (!p->contains (addr))
+       continue;
+      if (last)
+       {
+         if (last->fname)
+           {
+             sb->append (last->fname);
+             sb->append (' ');
+           }
+         DbeLine *dl = p->dbeLine;
+         sb->appendf (NTXT ("%s:%lld <-- "), get_basename (dl->sourceFile->get_name ()), (long long) dl->lineno);
+       }
+      last = p;
+    }
+  if (last)
+    {
+      if (last->fname)
+       {
+         sb->append (last->fname);
+         sb->append (' ');
+       }
+    }
+  DbeLine *dl = func->mapPCtoLine (addr, NULL);
+  sb->appendf ("%s:%lld ", get_basename (dl->sourceFile->get_name ()),
+              (long long) dl->lineno);
+}
+
+char *
+DbeInstr::get_descriptor ()
+{
+  char *typetag = NTXT ("");
+  if ((flags & PCTrgtFlag) == 0)  // not synthetic instruction
+    { // use memop descriptor, if available
+      Module *mod = func->module;
+      if (mod->hwcprof  && mod->infoList)
+       {
+         long i;
+         inst_info_t *info = NULL;
+         Vec_loop (inst_info_t*, mod->infoList, i, info)
+         {
+           if (info->offset == func->img_offset + addr) break;
+         }
+         if (info)
+           {
+             long t;
+             datatype_t *dtype = NULL;
+             Vec_loop (datatype_t*, mod->datatypes, t, dtype)
+             {
+               if (dtype->datatype_id == info->memop->datatype_id)
+                 break;
+             }
+             if (dtype && dtype->dobj)
+               typetag = dtype->dobj->get_name ();
+           }
+       }
+    }
+  return dbe_strdup (typetag);
+}
+
+int64_t
+DbeInstr::get_size ()
+{
+  //    Function *func = (Function*)dbeSession->get_hobj( pc );
+  //    Module   *mod  = func ? func->module : NULL;
+  //    return mod ? mod->instrSize( func->img_offset + addr ) : 0;
+  return size;
+}
+
+uint64_t
+DbeInstr::get_addr ()
+{
+  return func->get_addr () + addr;
+}
+
+Histable *
+DbeInstr::convertto (Type type, Histable *obj)
+{
+  Histable *res = NULL;
+  SourceFile *source = (SourceFile*) obj;
+  switch (type)
+    {
+    case INSTR:
+      res = this;
+      break;
+    case LINE:
+      res = mapPCtoLine (source);
+      break;
+    case SOURCEFILE:
+      res = mapPCtoLine (source);
+      if (res)
+       res = ((DbeLine*) res)->sourceFile;
+      break;
+    case FUNCTION:
+      res = func;
+      break;
+    default:
+      assert (0);
+    }
+  return res;
+}
+
+char *
+DbeEA::get_name (NameFormat)
+{
+  if (name == NULL)
+    // generate one
+    name = dbe_strdup (dbeSession->localized_SP_UNKNOWN_NAME);
+  return name;
+}
+
+Histable *
+DbeEA::convertto (Type type, Histable *obj)
+{
+  Histable *res = NULL;
+  assert (obj == NULL);
+  switch (type)
+    {
+    case EADDR:
+      res = this;
+      break;
+    case DOBJECT:
+      res = dobj;
+      break;
+    default:
+      assert (0);
+    }
+  return res;
+}
+
+DbeLine::DbeLine (Function *_func, SourceFile *sf, int _lineno)
+{
+  func = _func;
+  lineno = _lineno;
+  sourceFile = sf;
+  id = sf->id + _lineno;
+  offset = 0;
+  size = 0;
+  flags = 0;
+  include = NULL;
+  dbeline_func_next = NULL;
+  dbeline_base = this;
+  current_name_format = Histable::NA;
+}
+
+DbeLine::~DbeLine ()
+{
+  delete dbeline_func_next;
+}
+
+int
+DbeLine::line_cmp (DbeLine *dbl)
+{
+  return lineno - dbl->lineno;
+}
+
+void
+DbeLine::init_Offset (uint64_t p_offset)
+{
+  if (offset == 0)
+    offset = p_offset;
+  if (dbeline_base && dbeline_base->offset == 0)
+    dbeline_base->offset = p_offset;
+}
+
+char *
+DbeLine::get_name (NameFormat nfmt)
+{
+  char *srcname = NULL, *basename, *fname;
+
+  if (func == NULL)
+    {
+      if (name)
+       return name;
+      srcname = sourceFile->get_name ();
+      basename = get_basename (srcname);
+      name = dbe_sprintf (GTXT ("line %u in \"%s\""), lineno, basename);
+      return name;
+    }
+
+  if (name && (nfmt == current_name_format || nfmt == Histable::NA))
+    return name;
+
+  current_name_format = nfmt;
+  free (name);
+  fname = func->get_name (nfmt);
+  if (func->flags & (FUNC_FLAG_SIMULATED | FUNC_FLAG_NO_OFFSET))
+    {
+      name = dbe_strdup (fname);
+      return name;
+    }
+
+  if (sourceFile)
+    srcname = sourceFile->get_name ();
+  if (!srcname || strlen (srcname) == 0)
+    srcname = func->getDefSrcName ();
+  basename = get_basename (srcname);
+
+  if (lineno != 0)
+    {
+      if (sourceFile == func->getDefSrc ())
+       name = dbe_sprintf (GTXT ("%s, line %u in \"%s\""), fname, lineno,
+                           basename);
+      else
+       name = dbe_sprintf (GTXT ("%s, line %u in alternate source context \"%s\""),
+                           fname, lineno, basename);
+    }
+  else if (sourceFile == NULL || (sourceFile->flags & SOURCE_FLAG_UNKNOWN) != 0)
+    name = dbe_sprintf (GTXT ("<Function: %s, instructions without line numbers>"),
+                       fname);
+  else
+    name = dbe_sprintf (GTXT ("<Function: %s, instructions from source file %s>"),
+                         fname, basename);
+  return name;
+}
+
+int64_t
+DbeLine::get_size ()
+{
+  return size;
+}
+
+uint64_t
+DbeLine::get_addr ()
+{
+  if (func == NULL && dbeline_func_next == NULL)
+    return (uint64_t) 0;
+  Function *f = func ? func : dbeline_func_next->func;
+  return f->get_addr () + offset;
+}
+
+Histable *
+DbeLine::convertto (Type type, Histable *obj)
+{
+  Histable *res = NULL;
+  switch (type)
+    {
+    case INSTR:
+      {
+       Function *f = (Function *) convertto (FUNCTION, NULL);
+       if (f)
+         res = f->find_dbeinstr (0, offset);
+       break;
+      }
+    case LINE:
+      res = dbeline_base;
+      break;
+    case FUNCTION:
+      if (func)
+       {
+         res = func;
+         break;
+       }
+      else
+       {
+         int not_found = 1;
+         for (DbeLine *dl = dbeline_base; dl; dl = dl->dbeline_func_next)
+           {
+             Function *f = dl->func;
+             not_found = (obj == NULL // XXXX pass dbeview as Histable*
+                          || ((DbeView*) obj)->get_path_tree ()->get_func_nodeidx (f) == 0);
+             if (f && f->def_source == sourceFile && (!not_found))
+               {
+                 res = f;
+                 break;
+               }
+           }
+         if (res == NULL && dbeline_func_next)
+           {
+             for (DbeLine *dl = dbeline_base; dl; dl = dl->dbeline_func_next)
+               {
+                 Function *f = dl->func;
+                 if (f && f->def_source == sourceFile)
+                   {
+                     res = f;
+                     break;
+                   }
+               }
+           }
+         if (res == NULL && dbeline_func_next)
+           res = dbeline_func_next->func;
+       }
+      break;
+    case SOURCEFILE:
+      res = (include) ? include : sourceFile;
+      break;
+    default:
+      assert (0);
+    }
+  return res;
+}
+
+CStack_data::CStack_data (MetricList *_metrics)
+{
+  metrics = _metrics;
+  total = new_cstack_item ();
+  cstack_items = new Vector<CStack_item*>;
+}
+
+CStack_data::CStack_item::CStack_item (long n)
+{
+  stack = NULL;
+  count = 0;
+  val = 0;
+  value = new TValue[n];
+  memset (value, 0, sizeof (TValue) * n);
+}
+
+CStack_data::CStack_item::~CStack_item ()
+{
+  delete stack;
+  delete[] value;
+}
+
+CStack_data::CStack_item *
+CStack_data::new_cstack_item ()
+{
+  int nmetrics = metrics->get_items ()->size ();
+  CStack_item *item = new CStack_item (nmetrics);
+
+  // We precalculate all metrics as integer values
+  // and convert them to appropriate types later.
+  for (int i = 0; i < nmetrics; i++)
+    item->value[i].tag = metrics->get_items ()->fetch (i)->get_vtype ();
+  return item;
+}
+
+HistableFile::HistableFile ()
+{
+  dbeFile = NULL;
+  isUsed = false;
+}
+
+Histable::Histable ()
+{
+  name = NULL;
+  id = 0;
+  comparable_objs = NULL;
+  phaseCompareIdx = -1;
+}
+
+Histable::~Histable ()
+{
+  delete_comparable_objs ();
+  free (name);
+}
+
+void
+Histable::delete_comparable_objs ()
+{
+  if (comparable_objs)
+    {
+      Vector<Histable*> *v = comparable_objs;
+      for (int i = 0; i < v->size (); i++)
+       {
+         Histable *h = v->fetch (i);
+         if (h)
+           {
+             h->comparable_objs = NULL;
+             h->phaseCompareIdx = phaseCompareIdx;
+           }
+       }
+      delete v;
+    }
+}
+
+void
+Histable::update_comparable_objs ()
+{
+  if (phaseCompareIdx != ExpGroup::phaseCompareIdx)
+    {
+      phaseCompareIdx = ExpGroup::phaseCompareIdx;
+      delete_comparable_objs ();
+    }
+}
+
+Vector<Histable*> *
+Histable::get_comparable_objs ()
+{
+  return comparable_objs;
+}
+
+Histable *
+Histable::get_compare_obj ()
+{
+  Vector<Histable*> *v = get_comparable_objs ();
+  for (long i = 0, sz = VecSize (v); i < sz; i++)
+    {
+      Histable *h = v->get (i);
+      if (h)
+       return h;
+    }
+  return this;
+}
+
+#define CASE_S(x)   case x: return (char *) #x
+
+char *
+Histable::type_to_string ()
+{
+  switch (get_type ())
+    {
+      CASE_S (INSTR);
+      CASE_S (LINE);
+      CASE_S (FUNCTION);
+      CASE_S (MODULE);
+      CASE_S (LOADOBJECT);
+      CASE_S (EADDR);
+      CASE_S (MEMOBJ);
+      CASE_S (INDEXOBJ);
+      CASE_S (PAGE);
+      CASE_S (DOBJECT);
+      CASE_S (SOURCEFILE);
+      CASE_S (EXPERIMENT);
+      CASE_S (OTHER);
+    default:
+      break;
+    }
+  return NTXT ("ERROR");
+}
+
+void
+Histable::dump_comparable_objs ()
+{
+  Dprintf (DEBUG_COMPARISON,
+          "# Histable::dump_comparable_objs type=%s(%d) 0x%lx id=%lld %s\n",
+          type_to_string (), get_type (), (unsigned long) this, (long long) id,
+          STR (get_name ()));
+  for (int i = 0, sz = comparable_objs ? comparable_objs->size () : 0; i < sz; i++)
+    {
+      Histable *h = comparable_objs->fetch (i);
+      Dprintf (DEBUG_COMPARISON, "  %d type=%s(%d) 0x%lx id=%lld %s\n", i,
+              h ? h->type_to_string () : "", h ? h->get_type () : -1,
+              (unsigned long) h, (long long) (h ? h->id : 0),
+              h ? STR (h->get_name ()) : NTXT (""));
+    }
+}
+
+char *
+Histable::dump ()
+{
+  StringBuilder sb;
+  sb.appendf (sizeof (long) == 32
+             ? " 0x%08lx : type=%s(%d) id=%lld %s"
+             : " 0x%016lx : type=%s(%d) id=%lld %s",
+             (unsigned long) this, type_to_string (), get_type (),
+             (long long) id, STR (get_name ()));
+  switch (get_type ())
+    {
+    case INSTR:
+      {
+       DbeInstr *o = (DbeInstr *) this;
+       sb.appendf (sizeof (long) == 32
+                   ? "   func=0x%08lx lineno=%lld"
+                   : "   func=0x%016lx lineno=%lld",
+                   (unsigned long) o->func, (long long) o->lineno);
+       break;
+      }
+    case LINE:
+      {
+       DbeLine *o = (DbeLine *) this;
+       sb.appendf (sizeof (long) == 32
+                   ? "   func=0x%08lx sourceFile=0x%08lx lineno=%lld"
+                   : "   func=0x%016lx sourceFile=0x%016lx lineno=%lld",
+                   (unsigned long) o->func, (unsigned long) o->sourceFile,
+                   (long long) o->lineno);
+       break;
+      }
+    default:
+      break;
+    }
+  return sb.toString ();
+}
diff --git a/gprofng/src/Hist_data.h b/gprofng/src/Hist_data.h
new file mode 100644 (file)
index 0000000..c5f7281
--- /dev/null
@@ -0,0 +1,292 @@
+/* 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 _HIST_DATA_H
+#define _HIST_DATA_H
+
+// A Hist_data object is used to obtain data used for constructing
+// a histogram display.
+
+#include <sys/types.h>
+
+#include <vec.h>
+#include <Map.h>
+#include <HashMap.h>
+
+#include "dbe_structs.h"
+#include "Histable.h"
+#include "DerivedMetrics.h"
+
+class DbeLine;
+class MetricList;
+
+class Hist_data
+{
+public:
+  friend class DbeView;
+  friend class er_print_histogram;
+  friend class PathTree;
+  friend class DataSpace;
+  friend class MemorySpace;
+  friend class IOActivity;
+  friend class HeapActivity;
+
+  // HistItem contains all the data about a single histogram item.
+  struct HistItem
+  {
+    HistItem (long n);
+    ~HistItem ();
+    Histable *obj;  // info on the object
+    int type;       // annotated src/dis: type
+    TValue *value;  // numeric values
+    long size;
+  };
+
+  enum Hist_status
+  {
+    SUCCESS = 0,
+    NO_DATA
+  };
+
+  enum Mode
+  {
+    ALL,
+    CALLERS,
+    CALLEES,
+    SELF,
+    MODL,
+    LAYOUT,
+    DETAIL
+  };
+
+  enum Sort_order
+  {
+    ASCEND,
+    DESCEND
+  };
+
+  enum Sort_type
+  {
+    ALPHA,
+    VALUE,
+    AUX
+  };
+
+  Hist_data (MetricList *, Histable::Type, Mode, bool _viewowned = false);
+
+  virtual ~Hist_data ();
+  void dump (char *msg, FILE *f);
+
+  Hist_status
+  get_status (void)
+  {
+    return status;
+  }
+
+  // Return the view ownership flag
+  bool
+  isViewOwned (void)
+  {
+    return viewowned;
+  }
+
+  // Return the total number of items
+  long size (void);
+
+  // Append a new HistItem for the specified Histable
+  HistItem *append_hist_item (Histable *obj);
+  void append_hist_item (HistItem *hi);
+  TValue *get_real_value (TValue *res, int met_index, int row);
+  TValue *get_value (TValue *res, int met_index, int row);
+  TValue *get_value (TValue *res, int met_index, HistItem *hi);
+  void print_row (StringBuilder *sb, int row, Metric::HistMetric *hist_metric, char *mark);
+  void print_content (FILE *out_file, Metric::HistMetric *hist_metric, int limit);
+  int print_label (FILE *out_file, Metric::HistMetric *hist_metric, int space);
+  void update_total (Hist_data::HistItem *new_total);
+  void update_max (Metric::HistMetric *hm_tmp);
+  void update_legend_width (Metric::HistMetric *hm_tmp);
+
+  // Find an existing HistItem
+  HistItem *find_hist_item (Histable *obj);
+
+  // sort the data
+  void sort (long ind, bool reverse);
+
+  // resort the data, if metric sort or direction has changed
+  void resort (MetricList *mlist);
+
+  // compute minima and maxima
+  void compute_minmax (void);
+
+  // fetch() takes a hist item index and returns a ptr to the item
+  HistItem *fetch (long index);
+
+  HistItem *
+  get_maximums (void)
+  {
+    return maximum;
+  }
+
+  HistItem *
+  get_maximums_inc (void)
+  {
+    return maximum_inc;
+  }
+
+  HistItem *
+  get_minimums (void)
+  {
+    return minimum;
+  }
+
+  HistItem *
+  get_totals (void)
+  {
+    return total;
+  }
+
+  Vector<HistItem*> *
+  get_hist_items (void)
+  {
+    return hist_items;
+  }
+
+  void
+  set_status (Hist_status st)
+  {
+    status = st;
+  }
+
+  MetricList *
+  get_metric_list (void)
+  {
+    return metrics;
+  }
+
+  Map<Histable*, int> *
+  get_callsite_mark ()
+  {
+    return callsite_mark;
+  }
+
+  Metric::HistMetric *get_histmetrics ();
+  void set_threshold (double proportion);
+  bool above_threshold (HistItem *hi);
+  double get_percentage (double value, int mindex);
+  size_t value_maxlen (int mindex); // Return the drawing length
+  size_t time_len (TValue *value, int clock);
+  size_t time_maxlen (int mindex, int clock);
+  size_t name_len (HistItem *item);
+  size_t name_maxlen ();
+  HistItem *new_hist_item (Histable *obj, int itype, TValue *value);
+  HistItem *update_hist_item (HistItem *hi, TValue *value);
+  Vector<uint64_t> *get_object_indices (Vector<int> *selections);
+
+private:
+
+  Metric::HistMetric *hist_metrics;
+  Vector<HistItem*> *hist_items;        // Actual histogram values
+  HashMap<Histable*, HistItem*>*hi_map; // map: Histable -> HistItem
+  Map<Histable*, int>*callsite_mark;
+  Hist_status status;
+  int nmetrics;             // number of metrics
+  MetricList *metrics;
+  Histable::Type type;
+  Sort_order sort_order;
+  Sort_type sort_type;
+  int sort_ind;
+  bool rev_sort;            // true if sort is reversed
+
+  Mode mode;
+  HistItem *gprof_item;     // used for gprof-style info
+  Histable *spontaneous;
+
+  // Private state variables
+  HistItem *maximum;
+  HistItem *minimum;
+  HistItem *maximum_inc;
+  HistItem *total;
+  HistItem *threshold;
+
+  // Perform the sort operation with this function
+  static int sort_compare_all (const void *a, const void *b, const void *arg);
+  static int sort_compare_dlayout (const void *a, const void *b, const void *arg);
+  static int sort_compare (HistItem *hi_1, HistItem *hi_2, Sort_type stype,
+                          long ind, Hist_data *hdata);
+
+  // Allocate a new structure of dynamic size
+  HistItem *new_hist_item (Histable *obj);
+
+  // Flag indicating whether or not the Hist_data structure
+  //   is owned by a DbeView, which has responsibility for
+  //   deleting it, or not, in which case the last user deletes it.
+  //   XXX this is very ugly, and arises from the inconsistent handling
+  //   XXX of the Hist_data structure in various bits of code.
+  bool viewowned;
+};
+
+// This structure is destined to merge with Hist_data.
+// We currently use it to present callstack data such as
+// leak and allocation lists.
+
+class DbeInstr;
+
+struct CStack_data
+{
+
+  struct CStack_item
+  {
+    CStack_item (long n);
+    ~CStack_item ();
+    long count;
+    int64_t val;
+    Vector<DbeInstr*> *stack;
+    TValue *value;      // numeric values
+  };
+
+  Vector<CStack_item*> *cstack_items;
+  CStack_item *total;
+
+  CStack_item *new_cstack_item ();
+  CStack_data (MetricList *);
+
+  long
+  size ()
+  {
+    return cstack_items->size ();
+  }
+
+  CStack_item *
+  fetch (long i)
+  {
+    return cstack_items->fetch (i);
+  }
+
+  ~CStack_data ()
+  {
+    cstack_items->destroy ();
+    delete cstack_items;
+    delete total;
+  }
+
+  MetricList *metrics;
+};
+
+#endif /* _HIST_DATA_H */
diff --git a/gprofng/src/Histable.h b/gprofng/src/Histable.h
new file mode 100644 (file)
index 0000000..c4cf854
--- /dev/null
@@ -0,0 +1,333 @@
+/* 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 _HISTABLE_H
+#define _HISTABLE_H
+
+//
+// The Histable class hierarchy is used to build up a representation of
+// the codeobjects (functions, modules, loadObjects, etc.) that make up the
+// text address space of a program.  The hierarchy is as follows:
+//
+//     Histable (public)
+//             LoadObject (public)
+//             Module (public)
+//             Function (public)
+//
+// Dataobjects are objects from the data address space of a program.
+// The reason for calling the base class "Histable" is because these
+// objects are all valid objects for computing histograms on.
+
+// A Histable object represents an object in the program text or data.
+
+#include "dbe_structs.h"
+#include "Emsg.h"
+#include "Expression.h"
+
+class DataObject;
+class Function;
+class SourceFile;
+class DbeFile;
+class DbeLine;
+template <class ITEM> class Vector;
+
+class Histable
+{
+  friend class Hist_data;
+public:
+
+  enum Type
+  {
+    INSTR, LINE, FUNCTION, MODULE, LOADOBJECT,
+    EADDR, MEMOBJ, INDEXOBJ, PAGE, DOBJECT,
+    SOURCEFILE, IOACTFILE, IOACTVFD, IOCALLSTACK,
+    HEAPCALLSTACK, EXPERIMENT, OTHER
+  };
+
+  // NameFormat for functions and function based objects
+
+  enum NameFormat
+  {
+    NA, LONG, SHORT, MANGLED, SONAME = 0x10
+  };
+
+  static NameFormat
+  make_fmt (int fnfmt, bool sofmt = false)
+  {
+    return (NameFormat) (sofmt ? fnfmt | SONAME : fnfmt);
+  }
+
+  static int
+  fname_fmt (NameFormat fmt)
+  {
+    return (fmt & ~SONAME);
+  }
+
+  static bool
+  soname_fmt (NameFormat fmt)
+  {
+    return (fmt & SONAME);
+  }
+
+  Histable ();
+  char *dump ();
+
+  virtual ~Histable ();
+
+  virtual char *
+  get_name (NameFormat = NA)
+  {
+    return name;    // Return the name of the object
+  }
+
+  virtual void
+  set_name (char * _name)
+  {
+    name = _name;
+  }
+
+  virtual void set_name_from_context (Expression::Context *) { }
+  virtual Type get_type () = 0;
+
+  virtual int64_t
+  get_size ()
+  {
+    return 0;
+  }
+
+  virtual uint64_t
+  get_addr ()
+  {
+    return 0ULL;
+  }
+
+  virtual Vector<Histable*> *get_comparable_objs ();
+  Histable *get_compare_obj ();
+
+  virtual Histable *
+  convertto (Type, Histable* = NULL)
+  {
+    return this;
+  }
+
+  Vector<Histable*> *comparable_objs;
+  int64_t id;       // A unique id of this object, within its specific Type
+
+protected:
+  char *name;       // Object name
+  int phaseCompareIdx;
+  void update_comparable_objs ();
+  void dump_comparable_objs ();
+  char *type_to_string ();
+  void delete_comparable_objs ();
+};
+
+typedef Histable::Type Histable_type;
+
+// An Other object represents some random histable object
+class Other : public Histable
+{
+public:
+
+  virtual Type
+  get_type ()
+  {
+    return OTHER;
+  }
+
+  uint64_t value64;
+  uint32_t tag;
+};
+
+// DbeInstr represents an instruction.
+//
+//   Used by Analyzer for: Disassembly, PCs, Timeline, and Event tabs.
+//
+class DbeInstr : public Histable
+{
+public:
+  DbeInstr (uint64_t _id, int _flags, Function *_func, uint64_t _addr);
+
+  virtual Type
+  get_type ()
+  {
+    return INSTR;
+  }
+
+  virtual char *get_name (NameFormat = NA);
+  virtual int64_t get_size ();
+  virtual uint64_t get_addr ();
+  virtual Histable *convertto (Type type, Histable *obj = NULL);
+  DbeLine *mapPCtoLine (SourceFile *sf);
+  void add_inlined_info (StringBuilder *sb);
+  char *get_descriptor ();
+  int pc_cmp (DbeInstr *instr2);
+
+  uint64_t addr;
+  uint64_t img_offset;      // file offset of the image
+  int flags;
+  Function *func;
+  int lineno;
+  int inlinedInd;
+  int64_t size;
+  bool isUsed;
+
+private:
+  NameFormat current_name_format;
+};
+
+class DbeEA : public Histable
+{
+public:
+
+  DbeEA (DataObject *_dobj, Vaddr _eaddr)
+  {
+    dobj = _dobj;
+    eaddr = _eaddr;
+  };
+
+  virtual Type
+  get_type ()
+  {
+    return EADDR;
+  };
+
+  virtual int64_t
+  get_size ()
+  {
+    return 1;
+  };
+
+  virtual uint64_t
+  get_addr ()
+  {
+    return eaddr;
+  };
+
+  virtual char *get_name (NameFormat = NA);
+  virtual Histable *convertto (Type type, Histable *obj = NULL);
+
+  DataObject *dobj;
+  Vaddr eaddr;
+};
+
+// DbeLine represents a line in a source file.
+//
+//   For each top-level DbeLine instance, there are three DbeLine subtypes:
+//
+//   A The top-level DbeLine is associated with a sourceFile & lineno, but
+//     not any particular function.  This form of DbeLine is used
+//     to represent Analyzer Source tab lines.
+//
+//   B Function-specific lines, those associated with a function in addition
+//     to the the sourceFile & lineno, are stored in a linked list.
+//     (see "dbeline_func_next").
+//     This subtype is used to differentiate a line found in #included source
+//     that is referenced by multiple functions.
+//     It is used in the Analyzer Lines tab.
+//
+//   C Function-specific "lines" that don't have line number info are referenced
+//     from each linked-list element's "dbeline_func_pseudo" field.
+//     This subtype is needed when a binary doesn't identify line numbers.
+//     It is used in the Analyzer Lines tab.
+//
+//   When the user switches views between tabs, a selected object in the old
+//   tab must be translated to an approprate object in the new tab.
+//   When switching to the Source Tab, the top-level DbeLine (dbeline_base)
+//     should be used.
+//   When switching to the Lines Tab, a function-specific dbeline_func_*
+//     should be used.
+//
+
+class DbeLine : public Histable
+{
+public:
+
+  enum Flag
+  {
+    OMPPRAGMA = 1
+  };
+
+  DbeLine (Function *_func, SourceFile *sf, int _lineno);
+  virtual ~DbeLine ();
+  virtual char *get_name (NameFormat = NA);
+  virtual int64_t get_size ();
+  virtual uint64_t get_addr ();
+  virtual Histable *convertto (Type type, Histable *obj = NULL);
+
+  void init_Offset (uint64_t p_offset);
+  int line_cmp (DbeLine *dbl);
+
+  virtual Type
+  get_type ()
+  {
+    return LINE;
+  }
+
+  void
+  set_flag (Flag flag)
+  {
+    flags |= flag;
+  }
+
+  bool
+  is_set (Flag flag)
+  {
+    return (flags & flag) != 0;
+  }
+
+  Function *func;           // note: will be NULL in the base (head) dbeline
+  int lineno;
+  int64_t size;
+  SourceFile *sourceFile;   // Default source file
+  SourceFile *include;      // included source file or NULL
+
+  DbeLine *dbeline_base;
+  // Head of list, a dbeline associated with sourceFile & lineno, but not func:
+  //   dbeline_base->lineno:                 non-zero
+  //   dbeline_base->sourceFile:             non-null
+  //   dbeline_base->func:                   NULL
+  //   dbeline_base->dbeline_base:           this
+  //   dbeline_base->dbeline_func_next:      first func-specific dbeline
+
+  DbeLine *dbeline_func_next;
+  // If non-null, pointer to a function-specific dbeline where:
+  //   dbeline_func_next->lineno:            same as dbeline_base->lineno
+  //   dbeline_func_next->sourceFile:        same as dbeline_base->sourceFile
+  //   dbeline_func_next->func:              pointer to unique function
+  //   dbeline_func_next->dbeline_base:      head of the linked list.
+  //   dbeline_func_next->dbeline_func_next: next function-specific dbeline.
+
+private:
+  int current_name_format;
+  int64_t offset;
+  int flags;
+};
+
+class HistableFile : public Histable, public DbeMessages
+{
+public:
+  HistableFile ();
+
+  bool isUsed;
+  DbeFile *dbeFile;
+};
+
+#endif /* _HISTABLE_H */
diff --git a/gprofng/src/IOActivity.cc b/gprofng/src/IOActivity.cc
new file mode 100644 (file)
index 0000000..401cab5
--- /dev/null
@@ -0,0 +1,825 @@
+/* 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 "DbeSession.h"
+#include "FileData.h"
+#include "StringBuilder.h"
+#include "i18n.h"
+#include "util.h"
+#include "IOActivity.h"
+#include "MetricList.h"
+#include "Application.h"
+#include "Experiment.h"
+#include "DbeView.h"
+#include "Exp_Layout.h"
+#include "i18n.h"
+
+IOActivity::IOActivity (DbeView *_dbev)
+{
+  dbev = _dbev;
+  fDataHash = NULL;
+  fDataTotal = NULL;
+  fDataObjs = NULL;
+  fDataObjsFile = NULL;
+  hasFile = false;
+  fDataObjsVfd = NULL;
+  hasVfd = false;
+  fDataObjsCallStack = NULL;
+  hasCallStack = false;
+  fDataCalStkMap = NULL;
+  fDataVfdMap = NULL;
+  hist_data_file_all = NULL;
+  hist_data_vfd_all = NULL;
+  hist_data_callstack_all = NULL;
+}
+
+void
+IOActivity::reset ()
+{
+  int numExps = dbeSession->nexps ();
+  FileData *fData = NULL;
+  DefaultMap<int64_t, FileData*>* fDataMap;
+  for (int k = 0; k < numExps; k++)
+    {
+      Experiment *exp = dbeSession->get_exp (k);
+      fDataMap = exp->getFDataMap ();
+      if (fDataMap == NULL)
+       continue;
+
+      fDataObjs = fDataMap->values ();
+      if (fDataObjs == NULL)
+       continue;
+      int numFiles = fDataObjs->size ();
+      for (int j = 0; j < numFiles; j++)
+       {
+         fData = fDataObjs->fetch (j);
+         fData->init ();
+       }
+    }
+
+  delete fDataHash;
+  fDataHash = NULL;
+  delete fDataTotal;
+  fDataTotal = NULL;
+
+  delete fDataObjsFile;
+  fDataObjsFile = NULL;
+  hasFile = false;
+
+  delete fDataObjsVfd;
+  fDataObjsVfd = NULL;
+  hasVfd = false;
+
+  delete fDataObjsCallStack;
+  fDataObjsCallStack = NULL;
+  hasCallStack = false;
+
+  delete fDataObjs;
+  fDataObjs = NULL;
+  delete fDataCalStkMap;
+  fDataCalStkMap = NULL;
+  delete fDataVfdMap;
+  fDataVfdMap = NULL;
+
+  // These three pointers are deleted by DbeView
+  // They are named iofile_data, iovfd_data, and iocs_data
+  hist_data_file_all = NULL;
+  hist_data_vfd_all = NULL;
+  hist_data_callstack_all = NULL;
+}
+
+void
+IOActivity::createHistItemTotals (Hist_data *hist_data, MetricList *mlist,
+                                 Histable::Type hType, bool empty)
+{
+  int mIndex;
+  Metric *mtr;
+  Hist_data::HistItem *hi;
+  FileData *fData = NULL;
+
+  if (fDataTotal == NULL)
+    {
+      fDataTotal = new FileData (TOTAL_FILENAME);
+      fDataTotal->setHistType (hType);
+      fDataTotal->setVirtualFd (VIRTUAL_FD_TOTAL);
+      fDataTotal->id = 0;
+    }
+
+  fData = new FileData (fDataTotal);
+  fData->setHistType (hType);
+  hi = hist_data->append_hist_item (fData);
+  Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
+  {
+    if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
+      continue;
+
+    Metric::Type mtype = mtr->get_type ();
+    ValueTag vType = mtr->get_vtype ();
+    hist_data->total->value[mIndex].tag = vType;
+    hi->value[mIndex].tag = vType;
+    double prec = (double) NANOSEC;
+    switch (mtype)
+      {
+      case BaseMetric::IO_READ_BYTES:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].ll = fDataTotal->getReadBytes ();
+           hi->value[mIndex].ll = fDataTotal->getReadBytes ();
+         }
+       else
+         {
+           hist_data->total->value[mIndex].ll = 0;
+           hi->value[mIndex].ll = 0;
+         }
+       break;
+      case BaseMetric::IO_READ_CNT:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].ll = fDataTotal->getReadCnt ();
+           hi->value[mIndex].ll = fDataTotal->getReadCnt ();
+         }
+       else
+         {
+           hist_data->total->value[mIndex].ll = 0;
+           hi->value[mIndex].ll = 0;
+         }
+       break;
+      case BaseMetric::IO_READ_TIME:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].d =
+                   (double) fDataTotal->getReadTime () / prec;
+           hi->value[mIndex].d = hist_data->total->value[mIndex].d;
+         }
+       else
+         {
+           hist_data->total->value[mIndex].d = 0.0;
+           hi->value[mIndex].d = 0.0;
+         }
+       break;
+      case BaseMetric::IO_WRITE_BYTES:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].ll = fDataTotal->getWriteBytes ();
+           hi->value[mIndex].ll = fDataTotal->getWriteBytes ();
+         }
+       else
+         {
+           hist_data->total->value[mIndex].ll = 0;
+           hi->value[mIndex].ll = 0;
+         }
+       break;
+      case BaseMetric::IO_WRITE_CNT:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].ll = fDataTotal->getWriteCnt ();
+           hi->value[mIndex].ll = fDataTotal->getWriteCnt ();
+         }
+       else
+         {
+           hist_data->total->value[mIndex].ll = 0;
+           hi->value[mIndex].ll = 0;
+         }
+       break;
+      case BaseMetric::IO_WRITE_TIME:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].d =
+                   (double) fDataTotal->getWriteTime () / prec;
+           hi->value[mIndex].d = hist_data->total->value[mIndex].d;
+         }
+       else
+         {
+           hist_data->total->value[mIndex].d = 0.0;
+           hi->value[mIndex].d = 0.0;
+         }
+       break;
+      case BaseMetric::IO_OTHER_CNT:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].ll = fDataTotal->getOtherCnt ();
+           hi->value[mIndex].ll = fDataTotal->getOtherCnt ();
+         }
+       else
+         {
+           hist_data->total->value[mIndex].ll = 0;
+           hi->value[mIndex].ll = 0;
+         }
+       break;
+      case BaseMetric::IO_OTHER_TIME:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].d =
+                   (double) fDataTotal->getOtherTime () / prec;
+           hi->value[mIndex].d = hist_data->total->value[mIndex].d;
+         }
+       else
+         {
+           hist_data->total->value[mIndex].d = 0.0;
+           hi->value[mIndex].d = 0.0;
+         }
+       break;
+      case BaseMetric::IO_ERROR_CNT:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].ll = fDataTotal->getErrorCnt ();
+           hi->value[mIndex].ll = fDataTotal->getErrorCnt ();
+         }
+       else
+         {
+           hist_data->total->value[mIndex].ll = 0;
+           hi->value[mIndex].ll = 0;
+         }
+       break;
+      case BaseMetric::IO_ERROR_TIME:
+       if (!empty)
+         {
+           hist_data->total->value[mIndex].d = (double) fDataTotal->getErrorTime () / prec;
+           hi->value[mIndex].d = hist_data->total->value[mIndex].d;
+         }
+       else
+         {
+           hist_data->total->value[mIndex].d = 0.0;
+           hi->value[mIndex].d = 0.0;
+         }
+       break;
+      default:
+       break;
+      }
+  }
+}
+
+void
+IOActivity::computeHistTotals (Hist_data *hist_data, MetricList *mlist)
+{
+  int mIndex;
+  Metric *mtr;
+  Vec_loop (Metric *, mlist->get_items (), mIndex, mtr)
+  {
+    if (!mtr->is_visible () && !mtr->is_tvisible () && !mtr->is_pvisible ())
+      continue;
+
+    Metric::Type mtype = mtr->get_type ();
+    ValueTag vType = mtr->get_vtype ();
+    hist_data->total->value[mIndex].tag = vType;
+    double prec = (double) NANOSEC;
+    switch (mtype)
+      {
+      case BaseMetric::IO_READ_BYTES:
+       hist_data->total->value[mIndex].ll = fDataTotal->getReadBytes ();
+       break;
+      case BaseMetric::IO_READ_CNT:
+       hist_data->total->value[mIndex].ll = fDataTotal->getReadCnt ();
+       break;
+      case BaseMetric::IO_READ_TIME:
+       hist_data->total->value[mIndex].d =
+               (double) fDataTotal->getReadTime () / prec;
+       break;
+      case BaseMetric::IO_WRITE_BYTES:
+       hist_data->total->value[mIndex].ll = fDataTotal->getWriteBytes ();
+       break;
+      case BaseMetric::IO_WRITE_CNT:
+       hist_data->total->value[mIndex].ll = fDataTotal->getWriteCnt ();
+       break;
+      case BaseMetric::IO_WRITE_TIME:
+       hist_data->total->value[mIndex].d =
+               (double) fDataTotal->getWriteTime () / prec;
+       break;
+      case BaseMetric::IO_OTHER_CNT:
+       hist_data->total->value[mIndex].ll = fDataTotal->getOtherCnt ();
+       break;
+      case BaseMetric::IO_OTHER_TIME:
+       hist_data->total->value[mIndex].d =
+               (double) fDataTotal->getOtherTime () / prec;
+       break;
+      case BaseMetric::IO_ERROR_CNT:
+       hist_data->total->value[mIndex].ll = fDataTotal->getErrorCnt ();
+       break;
+      case BaseMetric::IO_ERROR_TIME:
+       hist_data->total->value[mIndex].d =
+               (double) fDataTotal->getErrorTime () / prec;
+       break;
+      default:
+       break;
+      }
+  }
+}
+
+void
+IOActivity::computeHistData (Hist_data *hist_data, MetricList *mlist,
+                            Hist_data::Mode mode, Histable *selObj)
+{
+
+  Hist_data::HistItem *hi = NULL;
+  int numObjs = fDataObjs->size ();
+  int numMetrics = mlist->get_items ()->size ();
+
+  for (int i = 0; i < numObjs; i++)
+    {
+      FileData *fData = fDataObjs->fetch (i);
+      if (mode == Hist_data::ALL)
+       hi = hist_data->append_hist_item (fData);
+      else if (mode == Hist_data::SELF)
+       {
+         if (fData->id == selObj->id)
+           hi = hist_data->append_hist_item (fData);
+         else
+           continue;
+       }
+
+      for (int mIndex = 0; mIndex < numMetrics; mIndex++)
+       {
+         Metric *mtr = mlist->get_items ()->fetch (mIndex);
+         if (!mtr->is_visible () && !mtr->is_tvisible ()
+             && !mtr->is_pvisible ())
+           continue;
+
+         Metric::Type mtype = mtr->get_type ();
+         ValueTag vType = mtr->get_vtype ();
+         hi->value[mIndex].tag = vType;
+
+         double prec = (double) NANOSEC;
+         switch (mtype)
+           {
+           case BaseMetric::IO_READ_BYTES:
+             hi->value[mIndex].ll = fData->getReadBytes ();
+             break;
+           case BaseMetric::IO_READ_CNT:
+             hi->value[mIndex].ll = fData->getReadCnt ();
+             break;
+           case BaseMetric::IO_READ_TIME:
+             hi->value[mIndex].d = (double) fData->getReadTime () / prec;
+             break;
+           case BaseMetric::IO_WRITE_BYTES:
+             hi->value[mIndex].ll = fData->getWriteBytes ();
+             break;
+           case BaseMetric::IO_WRITE_CNT:
+             hi->value[mIndex].ll = fData->getWriteCnt ();
+             break;
+           case BaseMetric::IO_WRITE_TIME:
+             hi->value[mIndex].d = (double) fData->getWriteTime () / prec;
+             break;
+           case BaseMetric::IO_OTHER_CNT:
+             hi->value[mIndex].ll = fData->getOtherCnt ();
+             break;
+           case BaseMetric::IO_OTHER_TIME:
+             hi->value[mIndex].d = (double) fData->getOtherTime () / prec;
+             break;
+           case BaseMetric::IO_ERROR_CNT:
+             hi->value[mIndex].ll = fData->getErrorCnt ();
+             break;
+           case BaseMetric::IO_ERROR_TIME:
+             hi->value[mIndex].d = (double) fData->getErrorTime () / prec;
+             break;
+           default:
+             break;
+           }
+       }
+    }
+}
+
+Hist_data *
+IOActivity::compute_metrics (MetricList *mlist, Histable::Type type,
+                            Hist_data::Mode mode, Histable *selObj)
+{
+
+  // it's already there, just return it
+  if (mode == Hist_data::ALL)
+    {
+      if (type == Histable::IOACTFILE && hist_data_file_all)
+       return hist_data_file_all;
+      else if (type == Histable::IOACTVFD && hist_data_vfd_all)
+       return hist_data_vfd_all;
+      else if (type == Histable::IOCALLSTACK && hist_data_callstack_all)
+       return hist_data_callstack_all;
+    }
+
+  bool has_data = false;
+  Hist_data *hist_data = NULL;
+  VMode viewMode = dbev->get_view_mode ();
+
+  switch (type)
+    {
+    case Histable::IOACTVFD:
+      if (!hasVfd)
+       computeData (type);
+
+      // computeData() creates fDataObjsVfd
+      // fDataObjsVfd contains the list of vfd objects
+      if (fDataObjsVfd != NULL)
+       {
+         // fDataObjs is used in other methods
+         fDataObjs = fDataObjsVfd;
+         has_data = true;
+       }
+      else
+       has_data = false;
+
+      if (has_data && mode == Hist_data::ALL && hist_data_vfd_all == NULL)
+       {
+         hist_data_vfd_all = new Hist_data (mlist, type, mode, true);
+         hist_data = hist_data_vfd_all;
+       }
+      else if (has_data)
+       hist_data = new Hist_data (mlist, type, mode, false);
+      else
+       {
+         hist_data = new Hist_data (mlist, type, mode, false);
+         createHistItemTotals (hist_data, mlist, type, true);
+         return hist_data;
+       }
+      break;
+    case Histable::IOACTFILE:
+      if (!hasFile)
+       computeData (type);
+
+      // computeData() creates fDataObjsFile
+      // fDataObjsFile contains the list of file objects
+      if (fDataObjsFile != NULL)
+       {
+         fDataObjs = fDataObjsFile;
+         has_data = true;
+       }
+      else
+       has_data = false;
+
+      if (has_data && mode == Hist_data::ALL && hist_data_file_all == NULL)
+       {
+         hist_data_file_all = new Hist_data (mlist, type, mode, true);
+         hist_data = hist_data_file_all;
+       }
+      else if (has_data)
+       hist_data = new Hist_data (mlist, type, mode, false);
+      else
+       {
+         hist_data = new Hist_data (mlist, type, mode, false);
+         createHistItemTotals (hist_data, mlist, type, true);
+         return hist_data;
+       }
+      break;
+    case Histable::IOCALLSTACK:
+      if (!hasCallStack)
+       computeCallStack (type, viewMode);
+
+      // computeCallStack() creates fDataObjsCallStack
+      // fDataObjsCallStack contains the list of call stack objects
+      if (fDataObjsCallStack != NULL)
+       {
+         fDataObjs = fDataObjsCallStack;
+         has_data = true;
+       }
+      else
+       has_data = false;
+
+      if (has_data && (mode == Hist_data::ALL) && (hist_data_callstack_all == NULL))
+       {
+         hist_data_callstack_all = new Hist_data (mlist, type, mode, true);
+         hist_data = hist_data_callstack_all;
+       }
+      else if (has_data)
+       hist_data = new Hist_data (mlist, type, mode, false);
+      else
+       {
+         hist_data = new Hist_data (mlist, type, mode, false);
+         createHistItemTotals (hist_data, mlist, type, true);
+         return hist_data;
+       }
+      break;
+    default:
+      fprintf (stderr,
+           "IOActivity cannot process data due to wrong Histable (type=%d) \n",
+              type);
+      abort ();
+    }
+
+  if (mode == Hist_data::ALL || (mode == Hist_data::SELF && selObj->id == 0))
+    createHistItemTotals (hist_data, mlist, type, false);
+  else
+    computeHistTotals (hist_data, mlist);
+  computeHistData (hist_data, mlist, mode, selObj);
+
+  // Determine by which metric to sort if any
+  bool rev_sort = mlist->get_sort_rev ();
+  int sort_ind = -1;
+  int nmetrics = mlist->get_items ()->size ();
+  for (int mind = 0; mind < nmetrics; mind++)
+    if (mlist->get_sort_ref_index () == mind)
+      sort_ind = mind;
+
+  hist_data->sort (sort_ind, rev_sort);
+  hist_data->compute_minmax ();
+  return hist_data;
+}
+
+void
+IOActivity::computeData (Histable::Type type)
+{
+  bool has_iodata = false;
+  reset ();
+  int64_t histableId = 0; // It is used by fDataAggr only
+  // fData uses vfd for histable id
+
+  fDataHash = new HashMap<char*, FileData*>;
+  FileData *fData = NULL;
+  FileData *fDataAggr = NULL;
+
+  fDataTotal = new FileData (TOTAL_FILENAME);
+  fDataTotal->setHistType (type);
+  fDataTotal->setVirtualFd (VIRTUAL_FD_TOTAL);
+  fDataTotal->id = histableId++;
+
+  FileData *fDataStdin = new FileData (STDIN_FILENAME);
+  fDataStdin->setFileDes (STDIN_FD);
+  fDataStdin->setHistType (type);
+  fDataStdin->setFsType ("N/A");
+  fDataStdin->id = histableId++;
+
+  FileData *fDataStdout = new FileData (STDOUT_FILENAME);
+  fDataStdout->setFileDes (STDOUT_FD);
+  fDataStdout->setHistType (type);
+  fDataStdout->setFsType ("N/A");
+  fDataStdout->id = histableId++;
+
+  FileData *fDataStderr = new FileData (STDERR_FILENAME);
+  fDataStderr->setFileDes (STDERR_FD);
+  fDataStderr->setHistType (type);
+  fDataStderr->setFsType ("N/A");
+  fDataStderr->id = histableId++;
+
+  FileData *fDataOtherIO = new FileData (OTHERIO_FILENAME);
+  fDataOtherIO->setFileDes (OTHERIO_FD);
+  fDataOtherIO->setHistType (type);
+  fDataOtherIO->setFsType ("N/A");
+  fDataOtherIO->id = histableId++;
+
+  DefaultMap<int64_t, FileData*>* fDataMap;
+  fDataObjsFile = NULL;
+  fDataObjsVfd = NULL;
+
+  // get the list of io events from DbeView
+  int numExps = dbeSession->nexps ();
+
+  for (int k = 0; k < numExps; k++)
+    {
+      DataView *ioPkts = dbev->get_filtered_events (k, DATA_IOTRACE);
+      if (ioPkts == NULL || ioPkts->getSize () <= 0)
+       continue;
+      Experiment *exp = dbeSession->get_exp (k);
+      fDataMap = exp->getFDataMap ();
+      if (fDataMap == NULL)
+       continue;
+      delete fDataVfdMap;
+      fDataVfdMap = new DefaultMap<long, FileData*>;
+
+      long sz = ioPkts->getSize ();
+      for (long i = 0; i < sz; ++i)
+       {
+         hrtime_t event_duration = ioPkts->getLongValue (PROP_EVT_TIME, i);
+         int64_t nByte = ioPkts->getLongValue (PROP_IONBYTE, i);
+         IOTrace_type ioType = (IOTrace_type) ioPkts->getIntValue (PROP_IOTYPE, i);
+         int64_t vFd = ioPkts->getLongValue (PROP_IOVFD, i);
+         if (vFd >= 0)
+           {
+             fData = fDataMap->get (vFd);
+             if (fData == NULL)
+               continue;
+           }
+         else
+           continue;
+
+         if (fDataVfdMap->get (vFd) == NULL)
+           fDataVfdMap->put (vFd, fData);
+
+         switch (ioType)
+           {
+           case READ_TRACE:
+             fData->addReadEvent (event_duration, nByte);
+             // Set the Histable id for IOVFD
+             fData->id = fData->getVirtualFd ();
+             fDataTotal->addReadEvent (event_duration, nByte);
+             fDataTotal->setReadStat (event_duration, nByte);
+             break;
+           case WRITE_TRACE:
+             fData->addWriteEvent (event_duration, nByte);
+             // Set the Histable id for IOVFD
+             fData->id = fData->getVirtualFd ();
+             fDataTotal->addWriteEvent (event_duration, nByte);
+             fDataTotal->setWriteStat (event_duration, nByte);
+             break;
+           case OPEN_TRACE:
+             fData->addOtherEvent (event_duration);
+             // Set the Histable id for IOVFD
+             fData->id = fData->getVirtualFd ();
+             fDataTotal->addOtherEvent (event_duration);
+             break;
+           case CLOSE_TRACE:
+           case OTHERIO_TRACE:
+             fData->addOtherEvent (event_duration);
+             // Set the Histable id for IOVFD
+             fData->id = fData->getVirtualFd ();
+             fDataTotal->addOtherEvent (event_duration);
+             break;
+           case READ_TRACE_ERROR:
+           case WRITE_TRACE_ERROR:
+           case OPEN_TRACE_ERROR:
+           case CLOSE_TRACE_ERROR:
+           case OTHERIO_TRACE_ERROR:
+             fData->addErrorEvent (event_duration);
+             // Set the Histable id for IOVFD
+             fData->id = fData->getVirtualFd ();
+             fDataTotal->addErrorEvent (event_duration);
+             break;
+
+           case IOTRACETYPE_LAST:
+             break;
+           }
+
+         if (type == Histable::IOACTFILE)
+           {
+             fDataAggr = fDataHash->get (fData->getFileName ());
+             if (fDataAggr == NULL)
+               {
+                 bool setInfo = false;
+                 if (vFd == VIRTUAL_FD_STDIN)
+                   fDataAggr = fDataStdin;
+                 else if (vFd == VIRTUAL_FD_STDOUT)
+                   fDataAggr = fDataStdout;
+                 else if (vFd == VIRTUAL_FD_STDERR)
+                   fDataAggr = fDataStderr;
+                 else if (vFd == VIRTUAL_FD_OTHERIO)
+                   fDataAggr = fDataOtherIO;
+                 else
+                   {
+                     fDataAggr = new FileData (fData->getFileName ());
+                     setInfo = true;
+                   }
+                 fDataHash->put (fData->getFileName (), fDataAggr);
+
+                 if (setInfo)
+                   {
+                     fDataAggr->setFsType (fData->getFsType ());
+                     fDataAggr->setHistType (type);
+                     // Set the Histable id for aggregated file name
+                     fDataAggr->id = histableId;
+                     fDataAggr->setVirtualFd (histableId);
+                     histableId++;
+                   }
+               }
+
+             fDataAggr->setFileDesList (fData->getFileDes ());
+             fDataAggr->setVirtualFds (fData->getVirtualFd ());
+             switch (ioType)
+               {
+               case READ_TRACE:
+                 fDataAggr->addReadEvent (event_duration, nByte);
+                 break;
+               case WRITE_TRACE:
+                 fDataAggr->addWriteEvent (event_duration, nByte);
+                 break;
+               case OPEN_TRACE:
+                 fDataAggr->addOtherEvent (event_duration);
+                 break;
+               case CLOSE_TRACE:
+               case OTHERIO_TRACE:
+                 fDataAggr->addOtherEvent (event_duration);
+                 break;
+               case READ_TRACE_ERROR:
+               case WRITE_TRACE_ERROR:
+               case OPEN_TRACE_ERROR:
+               case CLOSE_TRACE_ERROR:
+               case OTHERIO_TRACE_ERROR:
+                 fDataAggr->addErrorEvent (event_duration);
+                 break;
+               case IOTRACETYPE_LAST:
+                 break;
+               }
+           }
+         has_iodata = true;
+       }
+      if (sz > 0)
+       {
+         if (fDataObjsVfd == NULL)
+           fDataObjsVfd = new Vector<FileData*>;
+         fDataObjsVfd->addAll (fDataVfdMap->values ());
+         hasVfd = true;
+       }
+    }
+  if (has_iodata && type == Histable::IOACTFILE)
+    {
+      fDataObjsFile = fDataHash->values ()->copy ();
+      hasFile = true;
+    }
+}
+
+void
+IOActivity::computeCallStack (Histable::Type type, VMode viewMode)
+{
+  bool has_data = false;
+  int64_t stackIndex = 0;
+  FileData *fData = NULL;
+  delete fDataCalStkMap;
+  fDataCalStkMap = new DefaultMap<void*, FileData*>;
+  delete fDataTotal;
+  fDataTotal = new FileData (TOTAL_FILENAME);
+  fDataTotal->setHistType (type);
+
+  // There is no call stack for total, use the index for id
+  fDataTotal->id = stackIndex++;
+
+  // get the list of io events from DbeView
+  int numExps = dbeSession->nexps ();
+  for (int k = 0; k < numExps; k++)
+    {
+      DataView *ioPkts = dbev->get_filtered_events (k, DATA_IOTRACE);
+      if (ioPkts == NULL || ioPkts->getSize () <= 0)
+       continue;
+      long sz = ioPkts->getSize ();
+      for (long i = 0; i < sz; ++i)
+       {
+         hrtime_t event_duration = ioPkts->getLongValue (PROP_EVT_TIME, i);
+         int64_t nByte = ioPkts->getLongValue (PROP_IONBYTE, i);
+         void *stackId = getStack (viewMode, ioPkts, i);
+         IOTrace_type ioType =
+                 (IOTrace_type) ioPkts->getIntValue (PROP_IOTYPE, i);
+         int64_t vFd = ioPkts->getLongValue (PROP_IOVFD, i);
+
+         if (stackId != NULL && vFd > 0)
+           {
+             fData = fDataCalStkMap->get (stackId);
+             if (fData == NULL)
+               {
+                 char *stkName = dbe_sprintf (GTXT ("Stack 0x%llx"),
+                                              (unsigned long long) stackId);
+                 fData = new FileData (stkName);
+                 fDataCalStkMap->put (stackId, fData);
+                 fData->id = (int64_t) stackId;
+                 fData->setVirtualFd (stackIndex);
+                 stackIndex++;
+                 fData->setHistType (type);
+               }
+           }
+         else
+           continue;
+
+         switch (ioType)
+           {
+           case READ_TRACE:
+             fData->addReadEvent (event_duration, nByte);
+             fDataTotal->addReadEvent (event_duration, nByte);
+             fDataTotal->setReadStat (event_duration, nByte);
+             break;
+           case WRITE_TRACE:
+             fData->addWriteEvent (event_duration, nByte);
+             fDataTotal->addWriteEvent (event_duration, nByte);
+             fDataTotal->setWriteStat (event_duration, nByte);
+             break;
+           case OPEN_TRACE:
+             fData->addOtherEvent (event_duration);
+             fDataTotal->addOtherEvent (event_duration);
+             break;
+           case CLOSE_TRACE:
+           case OTHERIO_TRACE:
+             fData->addOtherEvent (event_duration);
+             fDataTotal->addOtherEvent (event_duration);
+             break;
+           case READ_TRACE_ERROR:
+           case WRITE_TRACE_ERROR:
+           case OPEN_TRACE_ERROR:
+             fData->addErrorEvent (event_duration);
+             fDataTotal->addErrorEvent (event_duration);
+             break;
+           case CLOSE_TRACE_ERROR:
+           case OTHERIO_TRACE_ERROR:
+             fData->addErrorEvent (event_duration);
+             fDataTotal->addErrorEvent (event_duration);
+             break;
+           case IOTRACETYPE_LAST:
+             break;
+           }
+         has_data = true;
+       }
+    }
+  if (has_data)
+    {
+      fDataObjsCallStack = fDataCalStkMap->values ()->copy ();
+      hasCallStack = true;
+    }
+}
diff --git a/gprofng/src/IOActivity.h b/gprofng/src/IOActivity.h
new file mode 100644 (file)
index 0000000..35c4517
--- /dev/null
@@ -0,0 +1,86 @@
+/* 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 _IOACTIVITY_H
+#define _IOACTIVITY_H
+
+
+#include <stdio.h>
+
+#include "vec.h"
+#include "Histable.h"
+#include "Hist_data.h"
+#include "Metric.h"
+#include "FileData.h"
+#include "DefaultMap.h"
+#include "dbe_types.h"
+
+class Experiment;
+class Expression;
+class DataView;
+class DbeView;
+
+class IOActivity
+{
+public:
+
+  IOActivity (DbeView *_dbev);
+  void reset (void);
+  Hist_data *compute_metrics (MetricList *, Histable::Type, Hist_data::Mode,
+                             Histable*);
+
+  ~IOActivity ()
+  {
+    this->reset ();
+  }
+
+private:
+  void computeData (Histable::Type);
+  void computeCallStack (Histable::Type, VMode viewMode);
+  void createHistItemTotals (Hist_data *, MetricList *, Histable::Type, bool);
+  void computeHistTotals (Hist_data *, MetricList *);
+  void computeHistData (Hist_data *, MetricList *, Hist_data::Mode, Histable *);
+
+  Vector<FileData*> *fDataObjs;
+  Vector<FileData*> *fDataObjsFile;
+  Vector<FileData*> *fDataObjsVfd;
+  Vector<FileData*> *fDataObjsCallStack;
+  bool hasFile;
+  bool hasVfd;
+  bool hasCallStack;
+  HashMap<char*, FileData*> *fDataHash;
+  FileData *fDataTotal;
+
+  // list of FileData objects using the stack id as the key
+  DefaultMap<void*, FileData*> *fDataCalStkMap;
+
+  // list of FileData objects using the VFD as the key
+  DefaultMap<long, FileData*> *fDataVfdMap;
+
+  // the cached data for mode=Hist_Data::ALL
+  Hist_data *hist_data_file_all;
+  Hist_data *hist_data_vfd_all;
+  Hist_data *hist_data_callstack_all;
+  Hist_data *hist_data_callstack;
+
+  DbeView *dbev;
+};
+
+#endif /* _IOACTIVITY_H */
diff --git a/gprofng/src/IndexMap2D.h b/gprofng/src/IndexMap2D.h
new file mode 100644 (file)
index 0000000..0f68a3a
--- /dev/null
@@ -0,0 +1,119 @@
+/* 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.  */
+
+/*
+ *     Index Map2D implementation.
+ *
+ *    Index Map2D is dynamic two dimensional array
+ */
+
+#ifndef _DBE_INDEXMAP2D_H
+#define _DBE_INDEXMAP2D_H
+
+#include <assert.h>
+#include <vec.h>
+#include <Map2D.h>
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+class IndexMap2D : public Map2D<Key1_t, Key2_t, Value_t>
+{
+public:
+
+  IndexMap2D ();
+  ~IndexMap2D ();
+
+  void put (Key1_t key1, Key2_t key2, Value_t val);
+  Value_t get (Key1_t key1, Key2_t key2);
+  Value_t get (Key1_t key1, Key2_t key2,
+              typename Map2D<Key1_t, Key2_t, Value_t>::Relation rel);
+  Value_t remove (Key1_t key1, Key2_t key2);
+
+private:
+
+  Vector<Vector<Value_t>*> *map1;
+};
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+IndexMap2D<Key1_t, Key2_t, Value_t>::IndexMap2D ()
+{
+  map1 = new Vector<Vector<Value_t>*>;
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+IndexMap2D<Key1_t, Key2_t, Value_t>::~IndexMap2D ()
+{
+  map1->destroy ();
+  delete map1;
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+void
+IndexMap2D<Key1_t, Key2_t, Value_t>::put (Key1_t key1, Key2_t key2, Value_t val)
+{
+  if (key1 < 0 || key2 < 0)
+    return;
+  Vector<Value_t> *map2 = NULL;
+  if (key1 < map1->size ())
+    map2 = map1->fetch ((int) key1);
+  if (map2 == NULL)
+    {
+      map2 = new Vector<Value_t>;
+      map1->store ((int) key1, map2);
+    }
+  map2->store ((int) key2, val);
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+Value_t
+IndexMap2D<Key1_t, Key2_t, Value_t>::get (Key1_t key1, Key2_t key2)
+{
+  if (key1 < 0 || key1 >= map1->size () || key2 < 0)
+    return (Value_t) 0;
+  Vector<Value_t> *map2 = map1->fetch ((int) key1);
+  if (map2 == NULL || key2 >= map2->size ())
+    return (Value_t) 0;
+  return map2->fetch ((int) key2);
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+Value_t
+IndexMap2D<Key1_t, Key2_t, Value_t>::get (Key1_t key1, Key2_t key2,
+                         typename Map2D<Key1_t, Key2_t, Value_t>::Relation rel)
+{
+  if (rel != Map2D<Key1_t, Key2_t, Value_t>::REL_EQEQ)
+    return (Value_t) 0;
+  return get (key1, key2);
+}
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+Value_t
+IndexMap2D<Key1_t, Key2_t, Value_t>::remove (Key1_t key1, Key2_t key2)
+{
+  if (key1 < 0 || key1 >= map1->size () || key2 < 0)
+    return (Value_t) 0;
+  Vector<Value_t> *map2 = map1->fetch ((int) key1);
+  if (map2 == NULL || key2 >= map2->size ())
+    return (Value_t) 0;
+  Value_t res = map2->fetch ((int) key2);
+  map2->store ((int) key2, (Value_t) 0);
+  return res;
+}
+
+#endif
diff --git a/gprofng/src/IndexObject.cc b/gprofng/src/IndexObject.cc
new file mode 100644 (file)
index 0000000..a7c8a37
--- /dev/null
@@ -0,0 +1,554 @@
+/* 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 "util.h"
+#include "DbeSession.h"
+#include "DbeView.h"
+#include "IndexObject.h"
+#include "StringBuilder.h"
+
+IndexObject::IndexObject (int _indextype, uint64_t _index)
+{
+  indextype = _indextype;
+  obj = NULL;
+  id = _index;
+  name = NULL;
+  nameIsFinal = false;
+}
+
+IndexObject::IndexObject (int _indextype, Histable *_obj)
+{
+  indextype = _indextype;
+  obj = _obj;
+  id = obj ? obj->id : (uint64_t) - 1;
+  name = NULL;
+  nameIsFinal = false;
+}
+
+void
+IndexObject::set_name (char * other_name)
+{
+  if (name == NULL)
+    {
+      name = other_name;
+      nameIsFinal = true;
+    }
+}
+
+static uint64_t
+extractExpgrid (uint64_t id)
+{
+  return (id >> IndexObject::INDXOBJ_EXPGRID_SHIFT)
+         & IndexObject::INDXOBJ_EXPGRID_MASK;
+}
+
+static uint64_t
+extractExpid (uint64_t id)
+{
+  return (id >> IndexObject::INDXOBJ_EXPID_SHIFT)
+         & IndexObject::INDXOBJ_EXPID_MASK;
+}
+
+static uint64_t
+extractPayload (uint64_t id)
+{
+  return (id >> IndexObject::INDXOBJ_PAYLOAD_SHIFT)
+         & IndexObject::INDXOBJ_PAYLOAD_MASK;
+}
+
+static void
+printCompareLabel (StringBuilder *sb, uint64_t grpId);
+
+static bool
+printThread (StringBuilder *sbIn, Expression::Context * ctx, uint64_t id)
+{
+  uint64_t proc = extractExpid (id);
+  uint64_t thrid = extractPayload (id);
+  bool isFinal = true;
+  bool hasJava = false;
+  bool javaThread = false;
+  if (ctx)
+    {
+      if (ctx->dview && ctx->dview->getProp (PROP_JTHREAD))
+       {
+         hasJava = true;
+         uint64_t tstamp = ctx->dview->getLongValue (PROP_TSTAMP, ctx->eventId);
+         JThread *jthread = ctx->exp->map_pckt_to_Jthread (thrid, tstamp);
+         if (jthread != JTHREAD_NONE && jthread != JTHREAD_DEFAULT)
+           {
+             sbIn->appendf (GTXT ("Process %llu, Thread %llu, JThread %llu \'%s\', Group \'%s\', Parent \'%s\'"),
+                            (unsigned long long) proc,
+                            (unsigned long long) thrid,
+                            (unsigned long long) jthread->jthr_id,
+                            get_str(jthread->name, ""),
+                            get_str(jthread->group_name, ""),
+                            get_str(jthread->parent_name, ""));
+             javaThread = true;
+           }
+       }
+    }
+  if (!javaThread)
+    {
+      sbIn->appendf (GTXT ("Process %llu, Thread %llu"),
+                    (unsigned long long) proc, (unsigned long long) thrid);
+      if (hasJava)
+       // sometimes threads start as native and later become Java; keep checking
+       isFinal = false;
+    }
+  if (ctx && ctx->dbev && ctx->dbev->comparingExperiments ())
+    {
+      Vector <Histable *> *v = ctx->exp->get_comparable_objs ();
+      int st = 0;
+      for (long i = 0, sz = VecSize (v); i < sz; i++)
+       {
+         Experiment *exp = (Experiment *) v->get (i);
+         if (exp)
+           {
+             if (st == 0)
+               {
+                 st = 1;
+                 continue;
+               }
+             sbIn->appendf (GTXT (" [ Group %llu  Process %llu ]"),
+                            (unsigned long long) exp->groupId - 1,
+                            (unsigned long long) exp->getUserExpId ());
+           }
+       }
+    }
+  return isFinal;
+}
+
+static bool
+printProcess (StringBuilder *sbIn, Expression::Context * ctx, uint64_t id)
+{
+  uint64_t proc = id;
+  if (ctx && ctx->exp)
+    {
+      int st = 0;
+      if (ctx->dbev && ctx->dbev->comparingExperiments ())
+       {
+         Vector <Histable *> *v = ctx->exp->get_comparable_objs ();
+         for (long i = 0, sz = VecSize (v); i < sz; i++)
+           {
+             Experiment *exp = (Experiment *) v->get (i);
+             if (exp)
+               {
+                 if (st == 0)
+                   {
+                     st = 1;
+                     sbIn->appendf (GTXT ("%s, Process %3llu, PID %llu"),
+                                get_str (exp->utargname, GTXT ("(unknown)")),
+                                    (unsigned long long) proc,
+                                    (unsigned long long) exp->getPID ());
+                     continue;
+                   }
+                 sbIn->appendf (GTXT (" [ Group %llu,  Process %llu, PID %llu ]"),
+                                (unsigned long long) exp->groupId - 1,
+                                (unsigned long long) exp->getUserExpId (),
+                                (unsigned long long) exp->getPID ());
+               }
+           }
+       }
+      if (st == 0)
+       sbIn->appendf (GTXT ("%s, Process %3llu, PID %llu"),
+                      get_str (ctx->exp->utargname, GTXT ("(unknown)")),
+                      (unsigned long long) proc,
+                      (unsigned long long) ctx->exp->getPID ());
+    }
+  else
+    sbIn->appendf (GTXT ("Process %3llu"), (unsigned long long) proc);
+  return true; //name is final
+}
+
+static bool
+printExperiment (StringBuilder *sbIn, Expression::Context * ctx, uint64_t id)
+{
+  uint64_t grpId = extractExpgrid (id);
+  uint64_t expid = extractExpid (id);
+  if (ctx && ctx->dbev->comparingExperiments ())
+    printCompareLabel (sbIn, grpId);
+  if (ctx)
+    {
+      Experiment *hasFounder = ctx->exp->founder_exp;
+      int pid = ctx->exp->getPID ();
+      uint64_t founderExpid;
+      if (hasFounder)
+       founderExpid = hasFounder->getUserExpId ();
+      else
+       founderExpid = expid;
+      sbIn->appendf (GTXT ("Base Experiment %llu, Process %llu, PID %llu, %s"),
+                    (unsigned long long) founderExpid,
+                    (unsigned long long) expid,
+                    (unsigned long long) pid,
+                    get_str (ctx->exp->utargname, GTXT ("(unknown)")));
+    }
+  else
+    sbIn->appendf (GTXT ("Process %llu"), (unsigned long long) expid);
+  return true; // name is final
+}
+
+void
+IndexObject::set_name_from_context (Expression::Context * ctx)
+{
+  if (name != NULL)
+    if (nameIsFinal && strstr (name, GTXT ("(unknown)")) == NULL)
+      return;
+  if (ctx == NULL || ctx->dview == NULL || ctx->dbev == NULL)
+    return;
+  StringBuilder sb;
+  switch (indextype)
+    {
+    case INDEX_THREADS:
+      nameIsFinal = printThread (&sb, ctx, id);
+      break;
+    case INDEX_PROCESSES:
+      nameIsFinal = printProcess (&sb, ctx, id);
+      break;
+    case INDEX_EXPERIMENTS:
+      nameIsFinal = printExperiment (&sb, ctx, id);
+      break;
+    default:
+      name = NULL;
+      return;
+    }
+  if (sb.length ())
+    name = sb.toString ();
+}
+
+static void
+printCompareLabel (StringBuilder *sbIn, uint64_t grpId)
+{
+  static const char *labels[] = {"", GTXT ("Baseline"), GTXT ("Comparison")};
+  static int length;
+  if (!length)
+    {
+      length = strlen (labels[1]);
+      int length2 = strlen (labels[2]);
+      if (length < length2)
+       length = length2;
+      length += 5; // for open/close brace and grpId number and spaces
+    }
+  char *s = NULL;
+  if (grpId != 0)
+    {
+      if (grpId <= 2)
+       s = dbe_sprintf ("[%s]", labels[grpId]);
+      else
+       s = dbe_sprintf ("[%s-%llu]", labels[2],
+                        (unsigned long long) (grpId - 1));
+    }
+  sbIn->appendf ("%-*s", length, get_str (s, ""));
+  free (s);
+}
+
+char *
+IndexObject::get_name (NameFormat fmt)
+{
+  if (name == NULL)
+    {
+      StringBuilder sb;
+      int64_t upper;
+      int64_t num1;
+      int64_t num2;
+      switch (indextype)
+       {
+       case INDEX_THREADS:
+         printThread (&sb, NULL, id);
+         break;
+
+       case INDEX_CPUS:
+         sb.sprintf (GTXT ("CPU %llu"), (unsigned long long) id);
+         break;
+
+       case INDEX_SAMPLES:
+         sb.sprintf (GTXT ("Sample %llu"), (unsigned long long) id);
+         break;
+
+       case INDEX_GCEVENTS:
+         if (id == 0)
+           {
+             sb.sprintf (GTXT ("Not in any GCEvent"));
+           }
+         else
+           {
+             sb.sprintf (GTXT ("GCEvent %llu"), (unsigned long long) id);
+           }
+         break;
+
+       case INDEX_SECONDS:
+         sb.sprintf (GTXT ("Second of execution %llu"), (unsigned long long) id);
+         break;
+
+       case INDEX_PROCESSES:
+         printProcess (&sb, NULL, id);
+         break;
+
+       case INDEX_EXPERIMENTS:
+         printExperiment (&sb, NULL, id);
+         break;
+       case INDEX_BYTES:
+         upper = id;
+         if (id == -1)
+           {
+             break;
+           }
+         if (id % 2 == 1 && id > 1)
+           {
+             upper = id - 1;
+             if (upper >= 1099511627776)
+               {
+                 num1 = upper / 1099511627776;
+                 sb.sprintf (GTXT (">= %3llu TB"), (unsigned long long) num1);
+               }
+             else
+               {
+                 // XXXX do nothing, this should not happen
+               }
+           }
+         else
+           {
+             if (upper >= 1099511627776)
+               {
+                 num1 = upper / 1099511627776;
+                 num2 = num1 / 4;
+                 if (num2)
+                   {
+                     sb.sprintf (GTXT ("%3lluTB < n <= %3lluTB"), (unsigned long long) num2, (unsigned long long) num1);
+                   }
+                 else
+                   {
+                     sb.sprintf (GTXT ("256GB < n <= %3lluTB"), (unsigned long long) num1);
+                   }
+               }
+             else if (upper >= 1073741824)
+               {
+                 num1 = upper / 1073741824;
+                 num2 = num1 / 4;
+                 if (num2)
+                   {
+                     sb.sprintf (GTXT ("%3lluGB < n <= %3lluGB"), (unsigned long long) num2, (unsigned long long) num1);
+                   }
+                 else
+                   {
+                     sb.sprintf (GTXT ("256MB < n <= %3lluGB"), (unsigned long long) num1);
+                   }
+               }
+             else if (upper >= 1048576)
+               {
+                 num1 = upper / 1048576;
+                 num2 = num1 / 4;
+                 if (num2)
+                   {
+                     sb.sprintf (GTXT ("%3lluMB < n <= %3lluMB"), (unsigned long long) num2, (unsigned long long) num1);
+                   }
+                 else
+                   {
+                     sb.sprintf (GTXT ("256KB < n <= %3lluMB"), (unsigned long long) num1);
+                   }
+               }
+             else if (upper >= 1024)
+               {
+                 num1 = upper / 1024;
+                 num2 = num1 / 4;
+                 if (num2)
+                   {
+                     sb.sprintf (GTXT ("%3lluKB < n <= %3lluKB"), (unsigned long long) num2, (unsigned long long) num1);
+                   }
+                 else
+                   {
+                     sb.sprintf (GTXT ("  256 < n <= %3lluKB"), (unsigned long long) num1);
+                   }
+               }
+             else if (upper > 0)
+               {
+                 num1 = upper;
+                 num2 = num1 / 4;
+                 if (num1 == 1)
+                   {
+                     sb.sprintf (GTXT ("    1 Byte"));
+                   }
+                 else
+                   {
+                     sb.sprintf (GTXT ("%5llu < n <= %5llu Bytes"), (unsigned long long) num2, (unsigned long long) num1);
+                   }
+               }
+             else if (upper == 0)
+               {
+                 sb.sprintf (GTXT ("    0 Bytes"));
+               }
+             else
+               {
+                 sb.sprintf (GTXT ("<No Data>"));
+               }
+           }
+         break;
+       case INDEX_DURATION:
+         if (id == -1)
+           {
+             break;
+           }
+
+         if (id > 10000000000000)
+           {
+             sb.sprintf (GTXT ("n > 10000s"));
+           }
+         else if (id > 1000000000000)
+           {
+             sb.sprintf (GTXT ("1000s < n <= 10000s"));
+           }
+         else if (id > 100000000000)
+           {
+             sb.sprintf (GTXT (" 100s < n <= 1000s"));
+           }
+         else if (id > 10000000000)
+           {
+             sb.sprintf (GTXT ("  10s < n <=  100s"));
+           }
+         else if (id > 1000000000)
+           {
+             sb.sprintf (GTXT ("   1s < n <=   10s"));
+           }
+         else if (id > 100000000)
+           {
+             sb.sprintf (GTXT ("100ms < n <=    1s"));
+           }
+         else if (id > 10000000)
+           {
+             sb.sprintf (GTXT (" 10ms < n <= 100ms"));
+           }
+         else if (id > 1000000)
+           {
+             sb.sprintf (GTXT ("  1ms < n <=  10ms"));
+           }
+         else if (id > 100000)
+           {
+             sb.sprintf (GTXT ("100us < n <=   1ms"));
+           }
+         else if (id > 10000)
+           {
+             sb.sprintf (GTXT (" 10us < n <= 100us"));
+           }
+         else if (id > 1000)
+           {
+             sb.sprintf (GTXT ("  1us < n <=  10us"));
+           }
+         else if (id > 0)
+           {
+             sb.sprintf (GTXT ("   0s < n <=   1us"));
+           }
+         else if (id == 0)
+           {
+             sb.sprintf (GTXT ("   0s"));
+           }
+         else
+           {
+             sb.sprintf (GTXT ("<No Data>"));
+           }
+         break;
+
+         // Custom index objects
+       default:
+         if (obj)
+             sb.sprintf (GTXT ("%s from %s"),
+                         dbeSession->getIndexSpaceDescr (indextype), obj->get_name (fmt));
+         else
+           {
+             IndexObjType_t *indexObj = dbeSession->getIndexSpace (indextype);
+             if (indexObj->memObj)
+               {
+                 if (strcasecmp (indexObj->name, NTXT ("Memory_page_size")) == 0)
+                   {
+                     if (id == 0)
+                         sb.append (GTXT ("<Unknown>"));
+                     else
+                         sb.sprintf (NTXT ("%s 0x%16.16llx (%llu)"), indexObj->name,
+                                     (unsigned long long) id, (unsigned long long) id);
+                   }
+                 else if (strcasecmp (indexObj->name, NTXT ("Memory_in_home_lgrp")) == 0)
+                   {
+                     if (id == 0 || id == 1)
+                         sb.sprintf (NTXT ("%s: %s"), indexObj->name,
+                                     id == 1 ? GTXT ("True") : GTXT ("False"));
+                     else
+                         sb.sprintf (NTXT ("%s %s (0x%llx"), indexObj->name,
+                                     GTXT ("<Unknown>"), (unsigned long long) id);
+                   }
+                 else if (strcasecmp (indexObj->name, NTXT ("Memory_lgrp")) == 0)
+                   {
+                     if (id == 0)
+                         sb.append (GTXT ("<Unknown>"));
+                     else
+                         sb.sprintf (NTXT ("%s %llu"), indexObj->name, (unsigned long long) id);
+                   }
+                 else
+                     sb.sprintf (NTXT ("%s 0x%16.16llx"), indexObj->name, (unsigned long long) id);
+               }
+             else
+                 sb.sprintf ("%s 0x%16.16llx (%llu)", indexObj->name,
+                             (unsigned long long) id, (unsigned long long) id);
+           }
+       }
+      name = sb.toString ();
+      nameIsFinal = true;
+    }
+  return name;
+}
+
+bool
+IndexObject::requires_string_sort ()
+{
+  if (indextype == INDEX_PROCESSES || indextype >= INDEX_LAST)
+    return true;
+  return false;
+}
+
+Histable *
+IndexObject::convertto (Histable_type type, Histable *ext)
+{
+  if (type == INDEXOBJ)
+    return this;
+  if (obj)
+    return obj->convertto (type, ext);
+  return NULL;
+}
+
+IndexObjType_t::IndexObjType_t ()
+{
+  type = 0;
+  name = NULL;
+  i18n_name = NULL;
+  index_expr_str = NULL;
+  index_expr = NULL;
+  mnemonic = 0;
+  short_description = NULL;
+  long_description = NULL;
+  memObj = NULL;
+}
+
+IndexObjType_t::~IndexObjType_t ()
+{
+  free (name);
+  free (i18n_name);
+  free (index_expr_str);
+  delete index_expr;
+  free (short_description);
+  free (long_description);
+}
diff --git a/gprofng/src/IndexObject.h b/gprofng/src/IndexObject.h
new file mode 100644 (file)
index 0000000..23f21d3
--- /dev/null
@@ -0,0 +1,111 @@
+/* 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 _INDEXOBJECT_H
+#define _INDEXOBJECT_H
+
+#include "Histable.h"
+#include "Expression.h"
+
+class IndexObject : public Histable
+{
+public:
+  IndexObject (int _indextype, uint64_t _index);
+  IndexObject (int _indextype, Histable *_obj);
+  bool requires_string_sort (); // name column should be sorted using name text
+
+  virtual Histable_type
+  get_type ()
+  {
+    return INDEXOBJ;
+  }
+
+  virtual char *get_name (NameFormat = NA);
+  virtual void set_name (char*);
+  virtual void set_name_from_context (Expression::Context *);
+  virtual Histable *convertto (Histable_type, Histable* = NULL);
+
+  virtual uint64_t
+  get_addr ()
+  {
+    return id;
+  }
+
+  uint64_t
+  get_index ()
+  {
+    return id;
+  }
+
+  Histable *
+  get_obj ()
+  {
+    return obj;
+  }
+
+  // for use in index object definitions
+  static const uint64_t INDXOBJ_EXPGRID_SHIFT   = 60;
+  static const uint64_t INDXOBJ_EXPID_SHIFT     = 32;
+  static const uint64_t INDXOBJ_PAYLOAD_SHIFT   = 0;
+  static const uint64_t INDXOBJ_EXPGRID_MASK    =
+       ((1LLU << (64 - INDXOBJ_EXPGRID_SHIFT)) - 1);
+  static const uint64_t INDXOBJ_EXPID_MASK      =
+       ((1LLU << (INDXOBJ_EXPGRID_SHIFT - INDXOBJ_EXPID_SHIFT)) - 1);
+  static const uint64_t INDXOBJ_PAYLOAD_MASK    =
+       ((1LLU << (INDXOBJ_EXPID_SHIFT - INDXOBJ_PAYLOAD_SHIFT)) - 1);
+
+private:
+
+  int indextype;
+  Histable *obj;
+  bool nameIsFinal;
+};
+
+typedef enum IndexObjTypes
+{
+  INDEX_THREADS = 0,
+  INDEX_CPUS,
+  INDEX_SAMPLES,
+  INDEX_GCEVENTS,
+  INDEX_SECONDS,
+  INDEX_PROCESSES,
+  INDEX_EXPERIMENTS,
+  INDEX_BYTES,
+  INDEX_DURATION,
+  INDEX_LAST    // never used; marks the count of precompiled items
+} IndexObjTypes_t;
+
+class IndexObjType_t
+{
+public:
+  IndexObjType_t ();
+  ~IndexObjType_t ();
+  int type;
+  char *name;           // used as input
+  char *i18n_name;      // used for output
+  char *index_expr_str;
+  Expression *index_expr;
+  char mnemonic;
+  char *short_description;
+  char *long_description;
+  MemObjType_t *memObj;
+};
+
+#endif  /* _INDEXOBJECT_H */
diff --git a/gprofng/src/IntervalMap.h b/gprofng/src/IntervalMap.h
new file mode 100644 (file)
index 0000000..8c20474
--- /dev/null
@@ -0,0 +1,194 @@
+/* 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.  */
+
+/*
+ *  Interval Map implementation.
+ *
+ *    Interval Map makes the following assumptions:
+ *    - if duplicate keys, the last one will be stored
+ *    - <TBC>
+ */
+#ifndef _DBE_INTERVALMAP_H
+#define _DBE_INTERVALMAP_H
+
+#include <assert.h>
+#include <vec.h>
+#include <Map.h>
+
+template <typename Key_t, typename Value_t>
+class IntervalMap : public Map<Key_t, Value_t>
+{
+public:
+
+  IntervalMap ();
+  ~IntervalMap ();
+  void put (Key_t key, Value_t val);
+  Value_t get (Key_t key);
+  Value_t get (Key_t key, typename Map<Key_t, Value_t>::Relation rel);
+  Value_t remove (Key_t key);
+
+private:
+
+  struct Entry
+  {
+    Key_t key;
+    Value_t val;
+  };
+
+  static const int CHUNK_SIZE;
+
+  int entries;
+  int nchunks;
+  Entry **chunks;
+  Vector<Entry*> *index;
+};
+
+template <typename Key_t, typename Value_t>
+const int IntervalMap<Key_t, Value_t>::CHUNK_SIZE = 16384;
+
+template <typename Key_t, typename Value_t>
+IntervalMap<Key_t, Value_t>::IntervalMap ()
+{
+  entries = 0;
+  nchunks = 0;
+  chunks = NULL;
+  index = new Vector<Entry*>;
+}
+
+template <typename Key_t, typename Value_t>
+IntervalMap<Key_t, Value_t>::~IntervalMap ()
+{
+  for (int i = 0; i < nchunks; i++)
+    delete[] chunks[i];
+  delete[] chunks;
+  delete index;
+}
+
+template <typename Key_t, typename Value_t>
+void
+IntervalMap<Key_t, Value_t>::put (Key_t key, Value_t val)
+{
+  int lo = 0;
+  int hi = entries - 1;
+  while (lo <= hi)
+    {
+      int md = (lo + hi) / 2;
+      Entry *entry = index->fetch (md);
+      int cmp = entry->key < key ? -1 : entry->key > key ? 1 : 0;
+      if (cmp < 0)
+       lo = md + 1;
+      else if (cmp > 0)
+       hi = md - 1;
+      else
+       {
+         entry->val = val;
+         return;
+       }
+    }
+
+  if (entries >= nchunks * CHUNK_SIZE)
+    {
+      nchunks++;
+      // Reallocate Entry chunk array
+      Entry **new_chunks = new Entry*[nchunks];
+      for (int i = 0; i < nchunks - 1; i++)
+       new_chunks[i] = chunks[i];
+      delete chunks;
+      chunks = new_chunks;
+
+      // Allocate new chunk for entries.
+      chunks[nchunks - 1] = new Entry[CHUNK_SIZE];
+    }
+  Entry *entry = &chunks[entries / CHUNK_SIZE][entries % CHUNK_SIZE];
+  entry->key = key;
+  entry->val = val;
+  index->insert (lo, entry);
+  entries++;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+IntervalMap<Key_t, Value_t>::get (Key_t key)
+{
+  return get (key, Map<Key_t, Value_t>::REL_EQ);
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+IntervalMap<Key_t, Value_t>::get (Key_t key, typename Map<Key_t, Value_t>::Relation rel)
+{
+  int lo = 0;
+  int hi = entries - 1;
+  while (lo <= hi)
+    {
+      int md = (lo + hi) / 2;
+      Entry *entry = index->fetch (md);
+      int cmp = entry->key < key ? -1 : entry->key > key ? 1 : 0;
+      switch (rel)
+       {
+       case Map<Key_t, Value_t>::REL_LT:
+         if (cmp < 0)
+           lo = md + 1;
+         else
+           hi = md - 1;
+         break;
+       case Map<Key_t, Value_t>::REL_GT:
+         if (cmp <= 0)
+           lo = md + 1;
+         else
+           hi = md - 1;
+         break;
+       case Map<Key_t, Value_t>::REL_LE:
+       case Map<Key_t, Value_t>::REL_GE:
+       case Map<Key_t, Value_t>::REL_EQ:
+         if (cmp < 0)
+           lo = md + 1;
+         else if (cmp > 0)
+           hi = md - 1;
+         else
+           return entry->val;
+         break;
+       }
+    }
+  switch (rel)
+    {
+    case Map<Key_t, Value_t>::REL_LT:
+    case Map<Key_t, Value_t>::REL_LE:
+      return hi >= 0 ? index->fetch (hi)->val : (Value_t) 0;
+    case Map<Key_t, Value_t>::REL_GT:
+    case Map<Key_t, Value_t>::REL_GE:
+      return lo < entries ? index->fetch (lo)->val : (Value_t) 0;
+    case Map<Key_t, Value_t>::REL_EQ:
+      break;
+    }
+  return (Value_t) 0;
+}
+
+template <typename Key_t, typename Value_t>
+Value_t
+IntervalMap<Key_t, Value_t>::remove (Key_t)
+{
+  // Not implemented
+  if (1)
+    assert (0);
+  return (Value_t) 0;
+}
+
+#endif
diff --git a/gprofng/src/LoadObject.cc b/gprofng/src/LoadObject.cc
new file mode 100644 (file)
index 0000000..d9ce3e8
--- /dev/null
@@ -0,0 +1,1242 @@
+/* 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 <errno.h>
+
+#include "util.h"
+#include "StringBuilder.h"
+#include "Application.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "Exp_Layout.h"
+#include "DataObject.h"
+#include "Elf.h"
+#include "Function.h"
+#include "Module.h"
+#include "ClassFile.h"
+#include "Stabs.h"
+#include "LoadObject.h"
+#include "dbe_types.h"
+#include "DbeFile.h"
+#include "ExpGroup.h"
+
+enum
+{
+  LO_InstHTableSize     = 4096,
+  HTableSize            = 1024
+};
+
+LoadObject *
+LoadObject::create_item (const char *nm, int64_t chksum)
+{
+  LoadObject *lo = new LoadObject (nm);
+  lo->checksum = chksum;
+  dbeSession->append (lo);
+  return lo;
+}
+
+LoadObject *
+LoadObject::create_item (const char *nm, const char *_runTimePath, DbeFile *df)
+{
+  LoadObject *lo = new LoadObject (nm);
+  lo->runTimePath = dbe_strdup (_runTimePath);
+  lo->dbeFile->orig_location = dbe_strdup (_runTimePath);
+  if (df)
+    {
+      if ((df->filetype & DbeFile::F_JAR_FILE) != 0)
+       {
+         if (lo->dbeFile->find_in_jar_file (nm, df->get_jar_file ()))
+           {
+             lo->dbeFile->inArchive = df->inArchive;
+             lo->dbeFile->container = df;
+           }
+       }
+      else
+       {
+         lo->dbeFile->set_location (df->get_location ());
+         lo->dbeFile->sbuf = df->sbuf;
+         lo->dbeFile->inArchive = df->inArchive;
+       }
+    }
+  dbeSession->append (lo);
+  return lo;
+}
+
+LoadObject::LoadObject (const char *loname)
+{
+  flags = 0;
+  size = 0;
+  type = SEG_UNKNOWN;
+  isReadStabs = false;
+  need_swap_endian = false;
+  instHTable = new DbeInstr*[LO_InstHTableSize];
+  for (int i = 0; i < LO_InstHTableSize; i++)
+    instHTable[i] = NULL;
+
+  functions = new Vector<Function*>;
+  funcHTable = new Function*[HTableSize];
+  for (int i = 0; i < HTableSize; i++)
+    funcHTable[i] = NULL;
+
+  seg_modules = new Vector<Module*>;
+  modules = new HashMap<char*, Module*>;
+  platform = Unknown;
+  noname = dbeSession->createUnknownModule (this);
+  modules->put (noname->get_name (), noname);
+  pathname = NULL;
+  arch_name = NULL;
+  runTimePath = NULL;
+  objStabs = NULL;
+  firstExp = NULL;
+  seg_modules_map = NULL;
+  comp_funcs = NULL;
+  warnq = new Emsgqueue (NTXT ("lo_warnq"));
+  commentq = new Emsgqueue (NTXT ("lo_commentq"));
+  elf_lo = NULL;
+  elf_inited = false;
+  checksum = 0;
+  isUsed = false;
+  h_function = NULL;
+  h_instr = NULL;
+
+  char *nm = (char *) loname;
+  if (strncmp (nm, NTXT ("./"), 2) == 0)
+    nm += 2;
+  set_name (nm);
+  dbeFile = new DbeFile (nm);
+  dbeFile->filetype |= DbeFile::F_LOADOBJ | DbeFile::F_FILE;
+}
+
+LoadObject::~LoadObject ()
+{
+  delete seg_modules_map;
+  delete functions;
+  delete[] instHTable;
+  delete[] funcHTable;
+  delete seg_modules;
+  delete modules;
+  delete elf_lo;
+  free (pathname);
+  free (arch_name);
+  free (runTimePath);
+  delete objStabs;
+  delete warnq;
+  delete commentq;
+  delete h_instr;
+}
+
+Elf *
+LoadObject::get_elf ()
+{
+  if (elf_lo == NULL)
+    {
+      if (dbeFile->get_need_refind ())
+       elf_inited = false;
+      if (elf_inited)
+       return NULL;
+      elf_inited = true;
+      char *fnm = dbeFile->get_location ();
+      if (fnm == NULL)
+       {
+         append_msg (CMSG_ERROR, GTXT ("Cannot find file: `%s'"),
+                     dbeFile->get_name ());
+         return NULL;
+       }
+      Elf::Elf_status st = Elf::ELF_ERR_CANT_OPEN_FILE;
+      elf_lo = Elf::elf_begin (fnm, &st);
+      if (elf_lo == NULL)
+       switch (st)
+         {
+         case Elf::ELF_ERR_CANT_OPEN_FILE:
+           append_msg (CMSG_ERROR, GTXT ("Cannot open ELF file `%s'"), fnm);
+           break;
+         case Elf::ELF_ERR_BAD_ELF_FORMAT:
+         default:
+           append_msg (CMSG_ERROR, GTXT ("Cannot read ELF header of `%s'"),
+                       fnm);
+           break;
+         }
+    }
+  return elf_lo;
+}
+
+Stabs *
+LoadObject::openDebugInfo (char *fname, Stabs::Stab_status *stp)
+{
+  if (objStabs == NULL)
+    {
+      if (fname == NULL)
+       return NULL;
+      objStabs = new Stabs (fname, get_pathname ());
+      Stabs::Stab_status st = objStabs->get_status ();
+      if ((st == Stabs::DBGD_ERR_NONE) && (checksum != 0))
+       {
+         Elf *elf = get_elf ();
+         if (elf && (checksum != elf->elf_checksum ()))
+           {
+             char *buf = dbe_sprintf (GTXT ("*** Note: '%s' has an unexpected checksum value; perhaps it was rebuilt. File ignored"),
+                                      fname);
+             commentq->append (new Emsg (CMSG_ERROR, buf));
+             delete buf;
+             st = Stabs::DBGD_ERR_CHK_SUM;
+           }
+       }
+      if (stp)
+       *stp = st;
+      if (st != Stabs::DBGD_ERR_NONE)
+       {
+         delete objStabs;
+         objStabs = NULL;
+       }
+    }
+  return objStabs;
+}
+
+uint64_t
+LoadObject::get_addr ()
+{
+  return MAKE_ADDRESS (seg_idx, 0);
+}
+
+bool
+LoadObject::compare (const char *_path, int64_t _checksum)
+{
+  return _checksum == checksum && dbe_strcmp (_path, get_pathname ()) == 0;
+}
+
+int
+LoadObject::compare (const char *_path, const char *_runTimePath, DbeFile *df)
+{
+  int ret = 0;
+  if (dbe_strcmp (_path, get_pathname ()) != 0)
+    return ret;
+  ret |= CMP_PATH;
+  if (_runTimePath)
+    {
+      if (dbe_strcmp (_runTimePath, runTimePath) != 0)
+       return ret;
+      ret |= CMP_RUNTIMEPATH;
+    }
+  if (df && dbeFile->compare (df))
+    ret |= CMP_CHKSUM;
+  return ret;
+}
+
+void
+LoadObject::set_platform (Platform_t pltf, int wsz)
+{
+  switch (pltf)
+    {
+    case Sparc:
+    case Sparcv9:
+    case Sparcv8plus:
+      platform = (wsz == W64) ? Sparcv9 : Sparc;
+      break;
+    case Intel:
+    case Amd64:
+      platform = (wsz == W64) ? Amd64 : Intel;
+      break;
+    default:
+      platform = pltf;
+      break;
+    }
+};
+
+void
+LoadObject::set_name (char *string)
+{
+  char *p;
+  pathname = dbe_strdup (string);
+
+  p = get_basename (pathname);
+  if (p[0] == '<')
+    name = dbe_strdup (p);
+  else    // set a short name  to "<basename>"
+    name = dbe_sprintf (NTXT ("<%s>"), p);
+}
+
+void
+LoadObject::dump_functions (FILE *out)
+{
+  int index;
+  Function *fitem;
+  char *sname, *mname;
+  if (platform == Java)
+    {
+      JMethod *jmthd;
+      Vector<JMethod*> *jmethods = (Vector<JMethod*>*)functions;
+      Vec_loop (JMethod*, jmethods, index, jmthd)
+      {
+       fprintf (out, "id %6llu, @0x%llx sz-%lld %s (module = %s)\n",
+                (unsigned long long) jmthd->id, (long long) jmthd->get_mid (),
+                (long long) jmthd->size, jmthd->get_name (),
+                jmthd->module ? jmthd->module->file_name : noname->file_name);
+      }
+    }
+  else
+    {
+      Vec_loop (Function*, functions, index, fitem)
+      {
+       if (fitem->alias && fitem->alias != fitem)
+         fprintf (out, "id %6llu, @0x%llx -        %s == alias of '%s'\n",
+                  (ull_t) fitem->id, (ull_t) fitem->img_offset,
+                  fitem->get_name (), fitem->alias->get_name ());
+       else
+         {
+           mname = fitem->module ? fitem->module->file_name : noname->file_name;
+           sname = fitem->getDefSrcName ();
+           fprintf (out,
+                    "id %6llu, @0x%llx - 0x%llx [save 0x%llx] o-%lld sz-%lld %s (module = %s)",
+                    (ull_t) fitem->id, (ull_t) fitem->img_offset,
+                    (ull_t) (fitem->img_offset + fitem->size),
+                    (ull_t) fitem->save_addr, (ull_t) fitem->img_offset,
+                    (ll_t) fitem->size, fitem->get_name (), mname);
+           if (sname && !streq (sname, mname))
+             fprintf (out, " (Source = %s)", sname);
+           fprintf (out, "\n");
+         }
+      }
+    }
+}
+
+int
+LoadObject::get_index (Function *func)
+{
+  Function *fp;
+  uint64_t offset;
+  int x;
+  int left = 0;
+  int right = functions->size () - 1;
+  offset = func->img_offset;
+  while (left <= right)
+    {
+      x = (left + right) / 2;
+      fp = functions->fetch (x);
+
+      if (left == right)
+       {
+         if (offset >= fp->img_offset + fp->size)
+           return -1;
+         if (offset >= fp->img_offset)
+           return x;
+         return -1;
+       }
+      if (offset < fp->img_offset)
+       right = x - 1;
+      else if (offset >= fp->img_offset + fp->size)
+       left = x + 1;
+      else
+       return x;
+    }
+  return -1;
+}
+
+char *
+LoadObject::get_alias (Function *func)
+{
+  Function *fp, *alias;
+  int index, nsize;
+  static char buf[1024];
+  if (func->img_offset == 0 || func->alias == NULL)
+    return NULL;
+  int fid = get_index (func);
+  if (fid == -1)
+    return NULL;
+
+  nsize = functions->size ();
+  alias = func->alias;
+  for (index = fid; index < nsize; index++)
+    {
+      fp = functions->fetch (index);
+      if (fp->alias != alias)
+       {
+         fid = index;
+         break;
+       }
+    }
+
+  *buf = '\0';
+  for (index--; index >= 0; index--)
+    {
+      fp = functions->fetch (index);
+      if (fp->alias != alias)
+       break;
+      if (fp != alias)
+       {
+         size_t len = strlen (buf);
+         if (*buf != '\0')
+           {
+             snprintf (buf + len, sizeof (buf) - len, NTXT (", "));
+             len = strlen (buf);
+           }
+         snprintf (buf + len, sizeof (buf) - len, "%s", fp->get_name ());
+       }
+    }
+  return buf;
+}
+
+DbeInstr*
+LoadObject::find_dbeinstr (uint64_t file_off)
+{
+  int hash = (((int) file_off) >> 2) & (LO_InstHTableSize - 1);
+  DbeInstr *instr = instHTable[hash];
+  if (instr && instr->img_offset == file_off)
+    return instr;
+  Function *fp = find_function (file_off);
+  if (fp == NULL)
+    fp = dbeSession->get_Unknown_Function ();
+  uint64_t func_off = file_off - fp->img_offset;
+  instr = fp->find_dbeinstr (0, func_off);
+  instHTable[hash] = instr;
+  return instr;
+}
+
+Function *
+LoadObject::find_function (uint64_t foff)
+{
+  // Look up in the hash table
+  int hash = (((int) foff) >> 6) & (HTableSize - 1);
+  Function *func = funcHTable[hash];
+  if (func && foff >= func->img_offset && foff < func->img_offset + func->size)
+    return func->alias ? func->alias : func;
+
+  // Use binary search
+  func = NULL;
+  int left = 0;
+  int right = functions->size () - 1;
+  while (left <= right)
+    {
+      int x = (left + right) / 2;
+      Function *fp = functions->fetch (x);
+      assert (fp != NULL);
+
+      if (foff < fp->img_offset)
+       right = x - 1;
+      else if (foff >= fp->img_offset + fp->size)
+       left = x + 1;
+      else
+       {
+         func = fp;
+         break;
+       }
+    }
+
+  // Plug the hole with a static function
+  char *func_name = NULL;
+  Size low_bound = 0, high_bound = 0;
+  if (func == NULL)
+    {
+      int last = functions->size () - 1;
+      uint64_t usize = (uint64_t) size;
+      if (foff >= usize)
+       {
+         // Cannot map to this LoadObject. Probably LoadObject was changed.
+         if (last >= 0 && functions->fetch (last)->img_offset == usize)
+           {
+             // Function is already created
+             func = functions->fetch (last);
+             if (func->size < 0 || (uint64_t) func->size < foff - usize)
+               func->size = foff - usize;
+           }
+         else
+           {
+             low_bound = size;
+             high_bound = foff;
+             func_name = dbe_sprintf (GTXT ("<static>@0x%llx (%s) --  no functions found"),
+                                      low_bound, name);
+           }
+       }
+      else if (last < 0)
+       {
+         low_bound = 0;
+         high_bound = size;
+         func_name = dbe_sprintf (GTXT ("<static>@0x%llx (%s) --  no functions found"),
+                                  low_bound, name);
+       }
+      else if (foff < functions->fetch (0)->img_offset)
+       {
+         low_bound = 0;
+         high_bound = functions->fetch (0)->img_offset;
+       }
+      else
+       {
+         Function *fp = functions->fetch (last);
+         if (foff >= fp->img_offset + fp->size)
+           {
+             low_bound = fp->img_offset + fp->size;
+             high_bound = size;
+           }
+         else
+           {
+             fp = functions->fetch (left);
+             if (foff >= fp->img_offset + fp->size)
+               {
+                 low_bound = fp->img_offset + fp->size;
+                 high_bound = functions->fetch (left + 1)->img_offset;
+               }
+             else
+               {
+                 Function *fp1 = functions->fetch (left - 1);
+                 low_bound = fp1->img_offset + fp1->size;
+                 high_bound = fp->img_offset;
+               }
+           }
+       }
+    }
+
+  if (func == NULL)
+    {
+      func = dbeSession->createFunction ();
+      func->size = (unsigned) (high_bound - low_bound);
+      func->module = noname;
+      func->img_fname = get_pathname ();
+      func->img_offset = (off_t) low_bound;
+      noname->functions->append (func); // unordered
+      if (func_name == NULL)
+       func_name = dbe_sprintf (GTXT ("<static>@0x%llx (%s)"), low_bound,
+                                name);
+      func->set_name (func_name);
+      free (func_name);
+
+      // now insert the function
+      functions->insert (left, func);
+    }
+
+  // Update the hash table
+  funcHTable[hash] = func;
+  return func->alias ? func->alias : func;
+}
+
+static void
+fixFuncAlias (Vector<Function*> *SymLst)
+{
+  int ind, i, k;
+  int64_t len, bestLen, maxSize;
+  Function *sym, *bestAlias;
+
+  // XXXX it is a clone of Stabs::fixSymtabAlias()
+  ind = SymLst->size () - 1;
+  for (i = 0; i < ind; i++)
+    {
+      bestAlias = SymLst->fetch (i);
+      if (bestAlias->img_offset == 0) // Ignore this bad symbol
+       continue;
+      sym = SymLst->fetch (i + 1);
+      if (bestAlias->img_offset != sym->img_offset)
+       {
+         if (bestAlias->size == 0
+             || sym->img_offset < bestAlias->img_offset + bestAlias->size)
+           bestAlias->size = (int) (sym->img_offset - bestAlias->img_offset);
+         continue;
+       }
+
+      // Find a "best" alias
+      bestLen = strlen (bestAlias->get_name ());
+      maxSize = bestAlias->size;
+      for (k = i + 1; k <= ind; k++)
+       {
+         sym = SymLst->fetch (k);
+         if (bestAlias->img_offset != sym->img_offset)
+           { // no more aliases
+             if ((maxSize == 0) ||
+                 (sym->img_offset < bestAlias->img_offset + maxSize))
+               maxSize = sym->img_offset - bestAlias->img_offset;
+             break;
+           }
+         if (maxSize < sym->size)
+           maxSize = sym->size;
+         len = strlen (sym->get_name ());
+         if (len < bestLen)
+           {
+             bestAlias = sym;
+             bestLen = len;
+           }
+       }
+      for (; i < k; i++)
+       {
+         sym = SymLst->fetch (i);
+         sym->alias = bestAlias;
+         sym->size = maxSize;
+       }
+      i--;
+    }
+}
+
+void
+LoadObject::post_process_functions ()
+{
+  if (flags & SEG_FLAG_DYNAMIC || platform == Java)
+    return;
+
+  char *msg = GTXT ("Processing Load Object Data");
+  if (dbeSession->is_interactive ())
+    theApplication->set_progress (1, msg);
+
+  // First sort the functions
+  functions->sort (func_compare);
+  fixFuncAlias (functions);
+
+  Module *mitem;
+  int index;
+  Vec_loop (Module*, seg_modules, index, mitem)
+  {
+    mitem->functions->sort (func_compare);
+  }
+
+  // Find any derived functions, and set their derivedNode
+  Function *fitem;
+  Vec_loop (Function*, functions, index, fitem)
+  {
+    if (dbeSession->is_interactive () && index % 5000 == 0)
+      {
+       int percent = (int) (100.0 * index / functions->size ());
+       theApplication->set_progress (percent, (percent != 0) ? NULL : msg);
+      }
+    fitem->findDerivedFunctions ();
+  }
+
+  // 4987698: get the alias name for MAIN_
+  fitem = find_function (NTXT ("MAIN_"));
+  if (fitem)
+    fitem->module->read_stabs ();
+  fitem = find_function (NTXT ("@plt"));
+  if (fitem)
+    fitem->flags |= FUNC_FLAG_PLT;
+  if (dbeSession->is_interactive ())
+    theApplication->set_progress (0, NTXT (""));
+}
+
+int
+LoadObject::func_compare (const void *p1, const void *p2)
+{
+  Function *f1 = *(Function **) p1;
+  Function *f2 = *(Function **) p2;
+  if (f1->img_offset != f2->img_offset)
+    return f1->img_offset > f2->img_offset ? 1 : -1;
+
+  // annotated source not available for weak symbols.
+  if ((f1->module->flags & MOD_FLAG_UNKNOWN) != 0)
+    {
+      if ((f2->module->flags & MOD_FLAG_UNKNOWN) == 0)
+       return -1;
+    }
+  else if ((f2->module->flags & MOD_FLAG_UNKNOWN) != 0)
+    return 1;
+  return strcoll (f1->get_name (), f2->get_name ());
+}
+
+Function *
+LoadObject::find_function (char *fname)
+{
+  Function *fitem;
+  int index;
+  Vec_loop (Function*, functions, index, fitem)
+  {
+    if (strcmp (fitem->get_name (), fname) == 0)
+      return fitem;
+  }
+  return (Function *) NULL;
+}
+
+Function *
+LoadObject::find_function (char *fname, unsigned int chksum)
+{
+  Function *fitem;
+  int index;
+  Vec_loop (Function*, functions, index, fitem)
+  {
+    if (fitem->chksum == chksum && strcmp (fitem->get_name (), fname) == 0)
+      return fitem;
+  }
+  return (Function *) NULL;
+}
+
+Module *
+LoadObject::find_module (char *mname)
+{
+  for (int i = 0, sz = seg_modules ? seg_modules->size () : 0; i < sz; i++)
+    {
+      Module *module = seg_modules->fetch (i);
+      if (strcmp (module->get_name (), mname) == 0)
+       return module;
+    }
+  return (Module *) NULL;
+}
+
+LoadObject::Arch_status
+LoadObject::sync_read_stabs ()
+{
+  Arch_status st = ARCHIVE_SUCCESS;
+  if (!isReadStabs)
+    {
+      aquireLock ();
+      if (!isReadStabs)
+       {
+         st = read_stabs ();
+         post_process_functions ();
+         isReadStabs = true;
+       }
+      releaseLock ();
+    }
+  return st;
+}
+
+LoadObject::Arch_status
+LoadObject::read_stabs ()
+{
+  if ((dbeFile->filetype & DbeFile::F_FICTION) != 0)
+    return ARCHIVE_SUCCESS;
+  Arch_status stabs_status = ARCHIVE_ERR_OPEN;
+  if (platform == Java)
+    {
+      Module *cf = NULL;
+      for (int i = 0, sz = seg_modules ? seg_modules->size () : 0; i < sz; i++)
+       {
+         Module *mod = seg_modules->fetch (i);
+         if (mod->dbeFile
+             && (mod->dbeFile->filetype & DbeFile::F_JAVACLASS) != 0)
+           {
+             cf = mod;
+             break;
+           }
+       }
+      if (cf)
+       {
+         int status = cf->readFile ();
+         switch (status)
+           {
+           case Module::AE_OK:
+             stabs_status = ARCHIVE_SUCCESS;
+             break;
+           case Module::AE_NOSTABS:
+             stabs_status = ARCHIVE_NO_STABS;
+             break;
+           case Module::AE_NOTREAD:
+           default:
+             stabs_status = ARCHIVE_ERR_OPEN;
+             break;
+           }
+       }
+    }
+  else if (strchr (pathname, '`'))
+    return ARCHIVE_SUCCESS;
+  else
+    {
+      Arch_status st = ARCHIVE_WRONG_ARCH;
+      Elf *elf = get_elf ();
+      if (elf == NULL)
+       {
+         if (read_archive () == 0)
+           st = ARCHIVE_SUCCESS;
+         else
+           {
+             char *msg = dbe_sprintf (GTXT ("*** Warning: Can't open file: %s"),
+                                      dbeFile->get_name ());
+             warnq->append (new Emsg (CMSG_ERROR, msg));
+             delete msg;
+           }
+       }
+      else if (checksum != 0 && checksum != elf->elf_checksum ())
+       {
+         if (read_archive () == 0)
+           st = ARCHIVE_SUCCESS;
+         else
+           {
+             char *msg = dbe_sprintf (
+                                      GTXT ("*** Note: '%s' has an unexpected checksum value; perhaps it was rebuilt. File ignored"),
+                                      dbeFile->get_location ());
+             commentq->append (new Emsg (CMSG_ERROR, msg));
+             delete msg;
+           }
+       }
+      if (st == ARCHIVE_SUCCESS)    // An old archive is used
+       return st;
+
+      Stabs::Stab_status status = Stabs::DBGD_ERR_CANT_OPEN_FILE;
+      char *location = dbeFile->get_location (true);
+      if (location == NULL)
+       return ARCHIVE_ERR_OPEN;
+
+      if (openDebugInfo (location, &status))
+       {
+         status = objStabs->read_archive (this);
+         isRelocatable = objStabs->is_relocatable ();
+         size = objStabs->get_textsz ();
+         platform = objStabs->get_platform ();
+         wsize = objStabs->get_class ();
+       }
+
+      switch (status)
+       {
+       case Stabs::DBGD_ERR_NONE:
+         stabs_status = ARCHIVE_SUCCESS;
+         break;
+       case Stabs::DBGD_ERR_CANT_OPEN_FILE:
+         stabs_status = ARCHIVE_ERR_OPEN;
+         break;
+       case Stabs::DBGD_ERR_BAD_ELF_LIB:
+       case Stabs::DBGD_ERR_BAD_ELF_FORMAT:
+         stabs_status = ARCHIVE_BAD_STABS;
+         break;
+       case Stabs::DBGD_ERR_NO_STABS:
+         stabs_status = ARCHIVE_NO_STABS;
+         break;
+       case Stabs::DBGD_ERR_NO_DWARF:
+         stabs_status = ARCHIVE_NO_DWARF;
+         break;
+       default:
+         stabs_status = ARCHIVE_BAD_STABS;
+         break;
+       }
+    }
+  return stabs_status;
+}
+
+#define ARCH_STRLEN(s)      ((strlen(s) + 4) & ~0x3 )
+
+static int
+offsetCmp (const void *a, const void *b)
+{
+  uint32_t o1 = ((inst_info_t *) a)->offset;
+  uint32_t o2 = ((inst_info_t *) b)->offset;
+  return o1 == o2 ? 0 : (o1 < o2 ? -1 : 1);
+}
+
+int
+LoadObject::read_archive ()
+{
+  if (arch_name == NULL)
+    return 1;
+  Module *mod = NULL;
+  Function *func = NULL;
+  char *buf;
+  Data_window *dwin = new Data_window (arch_name);
+  if (dwin->not_opened ())
+    {
+      delete dwin;
+      buf = dbe_sprintf (GTXT ("*** Warning: Error opening file for reading: %s: %s"),
+                        arch_name, strerror (errno));
+      warnq->append (new Emsg (CMSG_ERROR, buf));
+      delete buf;
+      return 1;
+    }
+  dwin->need_swap_endian = need_swap_endian;
+
+  // Prevent reading earlier archive files, which didn't support versioning.
+  int64_t offset = 0;
+  ARCH_common *cpkt = (ARCH_common*) dwin->bind (offset, sizeof (ARCH_common));
+  uint16_t v16;
+  if (cpkt)
+    {
+      v16 = (uint16_t) cpkt->type;
+      if (dwin->decode (v16) != ARCH_SEGMENT)
+       cpkt = NULL;
+    }
+  if (cpkt == NULL)
+    {
+      buf = dbe_sprintf (GTXT ("archive file malformed %s"), arch_name);
+      warnq->append (new Emsg (CMSG_WARN, buf));
+      delete buf;
+      return 1;
+    }
+
+  char *msg = NULL;
+  unsigned long long pointer_invalid = 0;
+  for (int64_t last_offset = -5000;;)
+    {
+      cpkt = (ARCH_common*) dwin->bind (offset, sizeof (ARCH_common));
+      if (cpkt == NULL)
+       break;
+      v16 = (uint16_t) cpkt->size;
+      uint32_t cpktsize = dwin->decode (v16);
+      cpkt = (ARCH_common*) dwin->bind (offset, cpktsize);
+      if ((cpkt == NULL) || (cpktsize == 0))
+       {
+         buf = dbe_sprintf (GTXT ("archive file malformed %s"), arch_name);
+         warnq->append (new Emsg (CMSG_WARN, buf));
+         delete buf;
+         break;
+       }
+
+      // Update the progress bar
+      if (dbeSession->is_interactive () && ((offset - last_offset) >= 5000))
+       {
+         last_offset = offset;
+         int percent = (int) (100.0 * offset / dwin->get_fsize ());
+         if (msg == NULL)
+           msg = dbe_sprintf (GTXT ("Reading Load Object Data: %s"), name);
+         theApplication->set_progress (percent, (percent != 0) ? NULL : msg);
+       }
+      char *ptr = (char *) cpkt;
+      v16 = (uint16_t) cpkt->type;
+      switch (dwin->decode (v16))
+       {
+       case ARCH_SEGMENT:
+         {
+           ARCH_segment *aseg = (ARCH_segment*) cpkt;
+           if (dwin->decode (aseg->version) != ARCH_VERSION)
+             {
+               buf = dbe_sprintf (GTXT ("Archive file version mismatch for %s"), arch_name);
+               warnq->append (new Emsg (CMSG_ERROR, buf));
+               delete buf;
+               if (dbeSession->is_interactive ())
+                 theApplication->set_progress (0, "");
+               return 1;
+             }
+           if (size == 0)
+             size = dwin->decode (aseg->textsz);
+           Platform_t pltf = (Platform_t) dwin->decode (aseg->platform);
+           if (pltf != Unknown)
+             {
+               platform = pltf; // override if known
+               wsize = (platform == Sparcv9 || platform == Amd64) ? W64 : W32;
+             }
+           break;
+         }
+       case ARCH_MSG:
+         {
+           ARCH_message *amsg = (ARCH_message*) cpkt;
+           buf = status_str ((Arch_status) dwin->decode (amsg->errcode));
+           commentq->append (new Emsg (CMSG_ARCHIVE, buf));
+           free (buf);
+           break;
+         }
+       case ARCH_INF:
+         {
+           ARCH_info *ainf = (ARCH_info*) cpkt;
+           Emsg *m = new Emsg (CMSG_ARCHIVE, (char*) (ainf + 1));
+           commentq->append (m);
+           break;
+         }
+       case ARCH_MODULE:
+         {
+           ARCH_module *amod = (ARCH_module*) cpkt;
+           char *str = ((char*) amod) + sizeof (ARCH_module);
+           if (streq (str, SP_UNKNOWN_NAME) &&
+               streq (str + ARCH_STRLEN (str), SP_UNKNOWN_NAME))
+             {
+               mod = noname;
+               break;
+             }
+           mod = dbeSession->createModule (this, str);
+           mod->lang_code = (Sp_lang_code) dwin->decode (amod->lang_code);
+           mod->fragmented = dwin->decode (amod->fragmented);
+           str += ARCH_STRLEN (str);
+           mod->set_file_name (dbe_strdup (str));
+           modules->put (get_basename (str), mod);
+           break;
+         }
+       case ARCH_FUNCTION:
+         {
+           if (mod == NULL)
+             break;
+           ARCH_function *afnc = (ARCH_function*) cpkt;
+           func = dbeSession->createFunction ();
+           func->img_offset = dwin->decode (afnc->offset);
+           func->size = dwin->decode (afnc->size);
+           func->save_addr = dwin->decode (afnc->save_addr)
+                   - dwin->decode (afnc->offset);
+           func->module = mod;
+           func->set_name (((char*) afnc) + sizeof (ARCH_function));
+           mod->functions->append (func);
+           functions->append (func);
+           break;
+         }
+       case ARCH_LDINSTR:
+         if (mod == NULL)
+           break;
+         Dprintf (DEBUG_LOADOBJ, "LDINSTR list for %s\n", mod->get_name ());
+         if (mod->infoList == NULL)
+           mod->infoList = new Vector<inst_info_t*>;
+         for (memop_info_t *mp = (memop_info_t*) (ptr + sizeof (ARCH_aninfo));
+                 (char*) mp < ptr + cpktsize; mp++)
+           {
+             memop_info_t *memop = new memop_info_t;
+             memop->offset = dwin->decode (mp->offset);
+             memop->id = dwin->decode (mp->id);
+             memop->signature = dwin->decode (mp->signature);
+             memop->datatype_id = dwin->decode (mp->datatype_id);
+             mod->ldMemops.append (memop);
+
+             inst_info_t *instop = new inst_info_t;
+             instop->type = CPF_INSTR_TYPE_LD;
+             instop->offset = memop->offset;
+             instop->memop = memop;
+             mod->infoList->incorporate (instop, offsetCmp);
+             Dprintf (DEBUG_LOADOBJ,
+                      "ld: offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n",
+                      memop->offset, memop->id, memop->signature,
+                      memop->datatype_id);
+           }
+         Dprintf (DEBUG_LOADOBJ, "LDINSTR list of %lld for %s\n",
+                  (long long) mod->ldMemops.size (), mod->get_name ());
+         break;
+       case ARCH_STINSTR:
+         if (mod == NULL)
+           break;
+         Dprintf (DEBUG_LOADOBJ, NTXT ("STINSTR list for %s\n"), mod->get_name ());
+         if (mod->infoList == NULL)
+           mod->infoList = new Vector<inst_info_t*>;
+         for (memop_info_t *mp = (memop_info_t*) (ptr + sizeof (ARCH_aninfo));
+                 ((char *) mp) < ptr + cpktsize; mp++)
+           {
+             memop_info_t *memop = new memop_info_t;
+             memop->offset = dwin->decode (mp->offset);
+             memop->id = dwin->decode (mp->id);
+             memop->signature = dwin->decode (mp->signature);
+             memop->datatype_id = dwin->decode (mp->datatype_id);
+             mod->stMemops.append (memop);
+
+             inst_info_t *instop = new inst_info_t;
+             instop->type = CPF_INSTR_TYPE_ST;
+             instop->offset = memop->offset;
+             instop->memop = memop;
+             mod->infoList->incorporate (instop, offsetCmp);
+             Dprintf (DEBUG_LOADOBJ,
+                      "st: offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n",
+                      memop->offset, memop->id, memop->signature,
+                      memop->datatype_id);
+           }
+         Dprintf (DEBUG_LOADOBJ, "STINSTR list of %lld for %s\n",
+                  (long long) mod->stMemops.size (), mod->get_name ());
+         break;
+       case ARCH_PREFETCH:
+         if (mod == NULL)
+           break;
+         Dprintf (DEBUG_LOADOBJ, "PFINSTR list for %s\n", mod->get_name ());
+         if (mod->infoList == NULL)
+           mod->infoList = new Vector<inst_info_t*>;
+         for (memop_info_t *mp = (memop_info_t*) (ptr + sizeof (ARCH_aninfo));
+                 ((char*) mp) < ptr + cpkt->size; mp++)
+           {
+             memop_info_t *memop = new memop_info_t;
+             memop->offset = dwin->decode (mp->offset);
+             memop->id = dwin->decode (mp->id);
+             memop->signature = dwin->decode (mp->signature);
+             memop->datatype_id = dwin->decode (mp->datatype_id);
+             mod->pfMemops.append (memop);
+
+             inst_info_t *instop = new inst_info_t;
+             instop->type = CPF_INSTR_TYPE_PREFETCH;
+             instop->offset = memop->offset;
+             instop->memop = memop;
+             mod->infoList->incorporate (instop, offsetCmp);
+             Dprintf (DEBUG_LOADOBJ,
+                      "pf: offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n",
+                      memop->offset, memop->id, memop->signature,
+                      memop->datatype_id);
+           }
+         Dprintf (DEBUG_LOADOBJ, "PFINSTR list of %lld for %s\n",
+                  (long long) mod->pfMemops.size (), mod->get_name ());
+         break;
+       case ARCH_BRTARGET:
+         if (mod == NULL)
+           break;
+         for (target_info_t *tp = (target_info_t*) (ptr + sizeof (ARCH_aninfo));
+                 ((char*) tp) < ptr + cpkt->size; tp++)
+           {
+             target_info_t *bTarget = new target_info_t;
+             bTarget->offset = dwin->decode (tp->offset);
+             mod->bTargets.append (bTarget);
+           }
+         Dprintf (DEBUG_LOADOBJ, "BRTARGET list of %lld for %s\n",
+                  (long long) mod->infoList->size (), mod->get_name ());
+         break;
+       default:
+         /* Check if the prointer is valid - should be even. */
+         pointer_invalid = (unsigned long long) (offset + cpktsize) & 1;
+         break; // ignore unknown packets
+       }
+      if (pointer_invalid)
+       break;
+      offset += cpktsize;
+    }
+  delete msg;
+  delete dwin;
+
+  if (dbeSession->is_interactive ())
+    theApplication->set_progress (0, NTXT (""));
+  return 0;
+}
+
+char *
+LoadObject::status_str (Arch_status rv, char */*arg*/)
+{
+  switch (rv)
+    {
+    case ARCHIVE_SUCCESS:
+    case ARCHIVE_EXIST:
+      return NULL;
+    case ARCHIVE_BAD_STABS:
+      return dbe_sprintf (GTXT ("Error: unable to read symbol table of %s"),
+                         name);
+    case ARCHIVE_ERR_SEG:
+      return dbe_sprintf (GTXT ("Error: unable to read load object file %s"),
+                         pathname);
+    case ARCHIVE_ERR_OPEN:
+      return dbe_sprintf (GTXT ("Error: unable to open file %s"),
+                         pathname);
+    case ARCHIVE_ERR_MAP:
+      return dbe_sprintf (GTXT ("Error: unable to map file %s"),
+                         pathname);
+    case ARCHIVE_WARN_CHECKSUM:
+      return dbe_sprintf (GTXT ("Note: checksum differs from that recorded in experiment for %s"),
+                         name);
+    case ARCHIVE_WARN_MTIME:
+      return dbe_sprintf (GTXT ("Warning: last-modified time differs from that recorded in experiment for %s"),
+                         name);
+    case ARCHIVE_WARN_HOST:
+      return dbe_sprintf (GTXT ("Try running er_archive -F on the experiment, on the host where it was recorded"));
+    case ARCHIVE_ERR_VERSION:
+      return dbe_sprintf (GTXT ("Error: Wrong version of archive for %s"),
+                         pathname);
+    case ARCHIVE_NO_STABS:
+      return dbe_sprintf (GTXT ("Note: no stabs or dwarf information in %s"),
+                         name);
+    case ARCHIVE_WRONG_ARCH:
+#if ARCH(SPARC)
+      return dbe_sprintf (GTXT ("Error: file %s is built for Intel, and can't be read on SPARC"),
+                         name);
+#else
+      return dbe_sprintf (GTXT ("Error: file %s is built for SPARC, and can't be read on Intel"),
+                         name);
+#endif
+    case ARCHIVE_NO_LIBDWARF:
+      return dbe_strdup (GTXT ("Warning: no libdwarf found to read DWARF symbol tables"));
+    case ARCHIVE_NO_DWARF:
+      return dbe_sprintf (GTXT ("Note: no DWARF symbol table in %s"), name);
+    default:
+      return dbe_sprintf (GTXT ("Warning: unexpected archive error %d"),
+                         (int) rv);
+    }
+}
+
+uint32_t
+LoadObject::get_checksum ()
+{
+  char *errmsg = NULL;
+  uint32_t crcval = get_cksum (pathname, &errmsg);
+  if (0 == crcval && errmsg)
+    {
+      warnq->append (new Emsg (CMSG_ERROR, errmsg));
+      free (errmsg);
+    }
+  return crcval;
+}
+
+static char*
+get_module_map_key (Module *mod)
+{
+  return mod->lang_code == Sp_lang_java ? mod->get_name () : mod->file_name;
+}
+
+Module *
+LoadObject::get_comparable_Module (Module *mod)
+{
+  if (mod->loadobject == this)
+    return mod;
+  if (get_module_map_key (mod) == NULL)
+    return NULL;
+  if (seg_modules_map == NULL)
+    {
+      seg_modules_map = new HashMap<char*, Module*>;
+      for (int i = 0; i < seg_modules->size (); i++)
+       {
+         Module *m = seg_modules->fetch (i);
+         char *key = get_module_map_key (m);
+         if (key)
+           {
+             seg_modules_map->put (m->file_name, m);
+             char *bname = get_basename (key);
+             if (bname != key)
+               seg_modules_map->put (bname, m);
+           }
+       }
+    }
+
+  char *key = get_module_map_key (mod);
+  Module *cmpMod = seg_modules_map->get (key);
+  if (cmpMod && cmpMod->comparable_objs == NULL)
+    return cmpMod;
+  char *bname = get_basename (key);
+  if (bname != key)
+    {
+      cmpMod = seg_modules_map->get (bname);
+      if (cmpMod && cmpMod->comparable_objs == NULL)
+       return cmpMod;
+    }
+  return NULL;
+}
+
+Vector<Histable*> *
+LoadObject::get_comparable_objs ()
+{
+  update_comparable_objs ();
+  if (comparable_objs || dbeSession->expGroups->size () <= 1)
+    return comparable_objs;
+  comparable_objs = new Vector<Histable*>(dbeSession->expGroups->size ());
+  for (int i = 0, sz = dbeSession->expGroups->size (); i < sz; i++)
+    {
+      ExpGroup *gr = dbeSession->expGroups->fetch (i);
+      Histable *h = gr->get_comparable_loadObject (this);
+      comparable_objs->append (h);
+      if (h)
+       h->comparable_objs = comparable_objs;
+    }
+  dump_comparable_objs ();
+  return comparable_objs;
+}
+
+void
+LoadObject::append_module (Module *mod)
+{
+  seg_modules->append (mod);
+  if (seg_modules_map == NULL)
+    seg_modules_map = new HashMap<char*, Module*>;
+  char *key = get_module_map_key (mod);
+  if (key)
+    {
+      seg_modules_map->put (key, mod);
+      char *bname = get_basename (key);
+      if (bname != key)
+       seg_modules_map->put (bname, mod);
+    }
+}
+
+// LIBRARY_VISIBILITY
+Function *
+LoadObject::get_hide_function ()
+{
+  if (h_function == NULL)
+    h_function = dbeSession->create_hide_function (this);
+  return h_function;
+}
+
+DbeInstr *
+LoadObject::get_hide_instr (DbeInstr *instr)
+{
+  if (h_instr == NULL)
+    {
+      Function *hf = get_hide_function ();
+      h_instr = hf->create_hide_instr (instr);
+    }
+  return h_instr;
+}
diff --git a/gprofng/src/LoadObject.h b/gprofng/src/LoadObject.h
new file mode 100644 (file)
index 0000000..0c997e3
--- /dev/null
@@ -0,0 +1,210 @@
+/* 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 _LOADOBJECT_H
+#define _LOADOBJECT_H
+
+// A Segment object represents a segment of the program text.
+
+#include "Histable.h"
+#include "Stabs.h"
+#include "DbeLock.h"
+
+#define JAVA_COMPILED_METHODS   "JAVA_COMPILED_METHODS"
+#define DYNFUNC_SEGMENT         "DYNAMIC_FUNCTIONS"
+#define SEG_FLAG_DYNAMIC    0x01
+#define SEG_FLAG_JVM        0x02
+#define SEG_FLAG_OMP        0x04
+#define SEG_FLAG_EXE        0x08
+#define SEG_FLAG_REORDER    0x10
+
+/* Hash name for all comparable executions */
+#define COMP_EXE_NAME       "<COMP_EXE_NAME>"
+
+class Emsg;
+class Elf;
+class Experiment;
+class Function;
+class Module;
+template <typename Key_t, typename Value_t> class HashMap;
+template <typename Key_t, typename Value_t> class Map;
+template <class ITEM> class Vector;
+
+enum
+{
+  CMP_PATH          = 1,
+  CMP_RUNTIMEPATH   = 2,
+  CMP_CHKSUM        = 4
+};
+
+class LoadObject : public HistableFile, public DbeLock
+{
+public:
+
+  // The various segments types.
+  enum seg_type
+  {
+    SEG_TEXT,
+    SEG_DATA,
+    SEG_BSS,
+    SEG_HEAP,
+    SEG_STACK,
+    SEG_DEVICE,
+    SEG_UNKNOWN
+  };
+
+  // These codes are stored in *.archive files
+  enum Arch_status
+  {
+    ARCHIVE_SUCCESS,
+    ARCHIVE_EXIST,
+    ARCHIVE_BAD_STABS,
+    ARCHIVE_ERR_SEG,
+    ARCHIVE_ERR_OPEN,
+    ARCHIVE_ERR_MAP,
+    ARCHIVE_WARN_MTIME,
+    ARCHIVE_WARN_HOST,
+    ARCHIVE_ERR_VERSION,
+    ARCHIVE_NO_STABS,
+    ARCHIVE_WRONG_ARCH,
+    ARCHIVE_NO_LIBDWARF,
+    ARCHIVE_NO_DWARF,
+    ARCHIVE_WARN_CHECKSUM
+  };
+
+  LoadObject (const char *loname);
+
+  static LoadObject *create_item (const char *nm, int64_t chksum);
+  static LoadObject *create_item (const char *nm, const char *_runTimePath, DbeFile *df);
+
+  virtual ~LoadObject ();
+  virtual void set_name (char *string);
+  virtual uint64_t get_addr ();
+  virtual Vector<Histable*> *get_comparable_objs ();
+
+  virtual Histable_type
+  get_type ()
+  {
+    return LOADOBJECT;
+  };
+
+  virtual int64_t
+  get_size ()
+  {
+    return size;
+  }
+
+  char *
+  get_pathname ()
+  {
+    return pathname;
+  }
+
+  void
+  set_archname (char *aname)
+  {
+    free (arch_name);
+    arch_name = aname;
+  }
+
+  bool
+  is_relocatable ()
+  {
+    return isRelocatable;
+  }
+
+  bool compare (const char *nm, int64_t _checksum);
+  int compare (const char *_path, const char *_runTimePath, DbeFile *df);
+  void set_platform (Platform_t pltf, int wsz);
+  void dump_functions (FILE *);
+  int get_index (Function *func);
+  char *get_alias (Function *func);
+  DbeInstr *find_dbeinstr (uint64_t file_off);
+  Function *find_function (uint64_t offset);
+  Function *find_function (char *fname);
+  Function *find_function (char *fname, unsigned int chksum);
+  Module *find_module (char *mname);
+  Module *get_comparable_Module (Module *mod);
+  void append_module (Module *mod);
+  Elf *get_elf ();
+  Stabs *openDebugInfo (char *fname, Stabs::Stab_status *stp = NULL);
+  Arch_status read_stabs ();
+  Arch_status sync_read_stabs ();
+  void post_process_functions ();
+  char *status_str (Arch_status rv, char *arg = NULL);
+  Function *get_hide_function ();
+  DbeInstr *get_hide_instr (DbeInstr *instr);
+  uint32_t get_checksum ();
+
+  Emsg *
+  fetch_warnings (void) // fetch the queue of warning messages
+  {
+    return warnq->fetch ();
+  }
+
+  Emsg *
+  fetch_comments (void) // fetch the queue of comment messages
+  {
+    return commentq->fetch ();
+  }
+
+  unsigned int flags;           // SEG_FLAG_*
+  bool isReadStabs;
+  bool need_swap_endian;
+  int seg_idx;                  // for compatibility (ADDRESS)
+  seg_type type;
+  int64_t size;                 // size of loadobject in bytes
+  int64_t max_size;             // Maximum size of loadobject in bytes
+  int64_t min_size;             // Min size of loadobject in bytes.
+  Vector<Function*> *functions; // Ordered list of functions
+  Vector<Module*> *seg_modules; // list of modules
+  HashMap<char*, Module*> *modules;
+  Module *noname;               // Module pointer to unknown name
+  Platform_t platform;          // Sparc, Sparcv9, Intel
+  WSize_t wsize;                // word size: 32,64
+  Stabs *objStabs;
+  HashMap<char*, Function*> *comp_funcs;    // list of comparable functions
+  Experiment *firstExp;
+  char *runTimePath;
+  time_t mtime;                 // file timestamp (in seconds)
+  int64_t checksum;             // file checksum
+
+private:
+  Elf *elf_lo;
+  bool elf_inited;
+  DbeInstr **instHTable;        // hash table for DbeInstr
+  char *pathname;               // User name of object file
+  ino64_t inode;                // inode number of segment file
+  bool isRelocatable;           // is relocatable .o
+  char *arch_name;              // .archive name
+  Emsgqueue *warnq;
+  Emsgqueue *commentq;
+  Function **funcHTable;        // hash table for functions
+  Function *h_function;         // hide pseudo function
+  DbeInstr *h_instr;            // hide pseudo instr
+  HashMap<char*, Module*> *seg_modules_map; // to find a comparable module
+
+  static int func_compare (const void *p1, const void *p2);
+  int read_archive ();
+  void init_datatypes ();
+  void update_datatypes (Module*, Vaddr, uint32_t datatype_id);
+};
+
+#endif /* _LOADOBJECT_H */
diff --git a/gprofng/src/MachineModel.cc b/gprofng/src/MachineModel.cc
new file mode 100644 (file)
index 0000000..15f493a
--- /dev/null
@@ -0,0 +1,317 @@
+/* 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 <string.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "DbeSession.h"
+#include "Command.h"
+#include "Application.h"
+#include "MemorySpace.h"
+#include "i18n.h"
+
+#define MAXARGS     20
+
+static const char *LIBNAME = "../lib/analyzer/lib/machinemodels";
+
+char *
+DbeSession::find_mach_model (char *name)
+{
+  // Read current working directory to see if it's there
+  if (name[0] == '/')
+    {
+      // Absolute path given
+      char *path = dbe_sprintf (NTXT ("%s.ermm"), name);
+      if (access (path, R_OK | F_OK) == 0)
+       return path;
+      free (path);
+      // Don't try anywhere else
+      return NULL;
+    }
+
+  char *path = dbe_sprintf (NTXT ("./%s.ermm"), name);
+  if (access (path, R_OK | F_OK) == 0)
+    return path;
+  free (path);
+
+
+  // Read the user's home directory to see if it's there
+  char *home = getenv (NTXT ("HOME"));
+  if (home != NULL)
+    {
+      path = dbe_sprintf (NTXT ("%s/%s.ermm"), home, name);
+      if (access (path, R_OK | F_OK) == 0)
+       return path;
+      free (path);
+    }
+  if (strchr (name, (int) '/') != NULL)
+    // name has a slash; don't look in system installation directory
+    return NULL;
+
+  // Read system installation directory to see if it's there
+  path = dbe_sprintf ("%s/%s/%s.ermm", theApplication->get_run_dir (),
+                     LIBNAME, name);
+  if (access (path, R_OK | F_OK) == 0)
+    return path;
+  free (path);
+  return NULL;
+}
+
+//  Handle the definitions from a machinemodel file
+//  Return value is NULL if it was OK, or an error message if not
+char *
+DbeSession::load_mach_model (char *_name)
+{
+  CmdType cmd_type;
+  int arg_count, cparam;
+  char *cmd, *end_cmd;
+  char *arglist[MAXARGS];
+  char *ret = NULL;
+  char *path = NULL;
+  FILE *fptr = NULL;
+
+  // Does name have .ermm suffix?  If so, strip it away
+  char *name = dbe_strdup (_name);
+  size_t len = strlen (name);
+  if (len > 5 && strcmp (name + len - 5, ".ermm") == 0)
+    name[len - 5] = 0;
+
+  if ((mach_model_loaded != NULL) && (strcmp (name, mach_model_loaded) == 0))
+    {
+      ret = dbe_sprintf (GTXT ("Machine model %s is already loaded\n"), name);
+      free (name);
+      return ret;
+    }
+  else if (mach_model_loaded == NULL && len == 0)
+    {
+      ret = dbe_sprintf (GTXT ("No Machine model is loaded\n"));
+      free (name);
+      return ret;
+    }
+
+  if (len != 0)
+    {
+      // zero-length just means unload any previously loaded model; only look if non-zero
+      path = find_mach_model (name);
+      if (path == NULL)
+       {
+         ret = dbe_sprintf (GTXT ("Machine model %s not found\n"), name);
+         free (name);
+         return ret;
+       }
+      fptr = fopen (path, NTXT ("r"));
+      if (fptr == NULL)
+       {
+         ret = dbe_sprintf (GTXT ("Open of Machine model %s, file %s failed\n"), name, path);
+         free (path);
+         free (name);
+         return ret;
+       }
+    }
+
+  // We are now committed to make the new machine model the loaded one;
+  //   Delete any MemoryObjects from any previously loaded machinemodel
+  if (dbeSession->mach_model_loaded != NULL)
+    {
+      Vector <char *> *oldobjs = MemorySpace::getMachineModelMemObjs
+             (dbeSession->mach_model_loaded);
+      for (int i = 0; i < oldobjs->size (); i++)
+       MemorySpace::mobj_delete (oldobjs->fetch (i));
+      delete oldobjs;
+      free (mach_model_loaded);
+    }
+  if (len == 0)
+    {
+      mach_model_loaded = NULL;
+      free (name);
+      // and there's no "loading" to do; just return
+      return NULL;
+    }
+  else
+    mach_model_loaded = name;
+
+  int line_no = 0;
+  end_cmd = NULL;
+
+  while (!feof (fptr))
+    {
+      char *script = read_line (fptr);
+      if (script == NULL)
+       continue;
+
+      line_no++;
+      strtok (script, NTXT ("\n"));
+
+      // extract the command
+      cmd = strtok (script, NTXT (" \t"));
+      if (cmd == NULL || *cmd == '#' || *cmd == '\n')
+       {
+         free (script);
+         continue;
+       }
+
+      char *remainder = strtok (NULL, NTXT ("\n"));
+      // now extract the arguments
+      int nargs = 0;
+      for (;;)
+       {
+         if (nargs >= MAXARGS)
+           {
+             ret = dbe_sprintf (GTXT ("Warning: more than %d arguments to %s command, line %d\n"),
+                                MAXARGS, cmd, line_no);
+             continue;
+           }
+
+         char *nextarg = strtok (remainder, NTXT ("\n"));
+
+         if (nextarg == NULL || *nextarg == '#')
+             // either the end of the line, or a comment indicator
+             break;
+         arglist[nargs++] = parse_qstring (nextarg, &end_cmd);
+         remainder = end_cmd;
+         if (remainder == NULL)
+           break;
+
+         // skip any blanks or tabs to get to next argument
+         while ((*remainder == ' ') || (*remainder == '\t'))
+           remainder++;
+       }
+
+      cmd_type = Command::get_command (cmd, arg_count, cparam);
+      // check for extra arguments
+      if (cmd_type != UNKNOWN_CMD && cmd_type != INDXOBJDEF && nargs > arg_count)
+       ret = dbe_sprintf (GTXT ("Warning: extra arguments to %s command, line %d\n"),
+                          cmd, line_no);
+      if (nargs < arg_count)
+       {
+         ret = dbe_sprintf (GTXT ("Error: missing arguments to %s command, line %d\n"),
+                            cmd, line_no);
+
+         // ignore this command
+         free (script);
+         continue;
+       }
+
+      switch (cmd_type)
+       {
+       case INDXOBJDEF:
+         {
+           char *err = dbeSession->indxobj_define (arglist[0], NULL,
+                           arglist[1], (nargs >= 3) ? PTXT (arglist[2]) : NULL,
+                           (nargs >= 4) ? PTXT (arglist[3]) : NULL);
+           if (err != NULL)
+             ret = dbe_sprintf (GTXT ("   %s: line %d `%s %s %s'\n"),
+                                err, line_no, cmd, arglist[0], arglist[1]);
+           break;
+         }
+       case COMMENT:
+         // ignore the line
+         break;
+       default:
+         {
+           // unexpected command in a machinemodel file
+           ret = dbe_sprintf (GTXT ("Unexpected command in machinemodel file %s on line %d: `%.64s'\n"),
+                              path, line_no, cmd);
+           break;
+         }
+       }
+      free (script);
+    }
+  fclose (fptr);
+  return ret;
+}
+
+Vector<char*> *
+DbeSession::list_mach_models ()
+{
+  Vector<char*> *model_names = new Vector<char*>();
+
+  // Open the current directory to read the entries there
+  DIR *dir = opendir (NTXT ("."));
+  if (dir != NULL)
+    {
+      struct dirent *entry = NULL;
+      while ((entry = readdir (dir)) != NULL)
+       {
+         size_t len = strlen (entry->d_name);
+         if (len < 5 || strcmp (entry->d_name + len - 5, ".ermm") != 0)
+           continue;
+         char *model = dbe_strdup (entry->d_name);
+
+         // remove the .ermm suffix
+         model[len - 5] = 0;
+
+         // add to vector
+         model_names->append (dbe_strdup (model));
+       }
+      closedir (dir);
+    }
+
+  // Read the user's home directory to list the models there
+  char *home = getenv ("HOME");
+  if (home != NULL)
+    {
+      dir = opendir (home);
+      if (dir != NULL)
+       {
+         struct dirent *entry = NULL;
+         while ((entry = readdir (dir)) != NULL)
+           {
+             size_t len = strlen (entry->d_name);
+             if (len < 5 || strcmp (entry->d_name + len - 5, ".ermm") != 0)
+               continue;
+             char *model = dbe_strdup (entry->d_name);
+
+             // remove the .ermm suffix
+             model[len - 5] = 0;
+
+             // add to vector
+             model_names->append (dbe_strdup (model));
+           }
+         closedir (dir);
+       }
+    }
+
+  // Read system installation directory to list the models there
+  char *sysdir = dbe_sprintf ("%s/%s", theApplication->get_run_dir (), LIBNAME);
+
+  dir = opendir (sysdir);
+  if (dir != NULL)
+    {
+      struct dirent *entry = NULL;
+      while ((entry = readdir (dir)) != NULL)
+       {
+         size_t len = strlen (entry->d_name);
+         if (len < 5 || strcmp (entry->d_name + len - 5, ".ermm") != 0)
+           continue;
+         char *model = dbe_strdup (entry->d_name);
+
+         // remove the .ermm suffix
+         model[len - 5] = 0;
+
+         // add to vector
+         model_names->append (dbe_strdup (model));
+       }
+      closedir (dir);
+    }
+  return model_names;
+}
diff --git a/gprofng/src/Makefile.am b/gprofng/src/Makefile.am
new file mode 100644 (file)
index 0000000..b874b5b
--- /dev/null
@@ -0,0 +1,202 @@
+## 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 .. -I ../.. 
+
+CCSOURCES = \
+       Application.cc \
+       BaseMetric.cc \
+       BaseMetricTreeNode.cc \
+       CallStack.cc \
+       CatchOutOfMemory.cc \
+       ClassFile.cc \
+       Command.cc \
+       CompCom.cc \
+       DataObject.cc \
+       DataSpace.cc \
+       Data_window.cc \
+       DataStream.cc \
+       DbeApplication.cc \
+       DbeFile.cc \
+       DbeJarFile.cc \
+       DbeLock.cc \
+       DbeSession.cc \
+       DbeThread.cc \
+       DbeView.cc \
+       DerivedMetrics.cc \
+       Disasm.cc \
+       Dwarf.cc \
+       DwarfLib.cc \
+       Elf.cc \
+       Emsg.cc \
+       Experiment.cc \
+       Exp_Layout.cc \
+       ExpGroup.cc \
+       Expression.cc \
+       FileData.cc \
+       Filter.cc \
+       FilterSet.cc \
+       Function.cc \
+       HeapMap.cc \
+       HeapData.cc \
+       HeapActivity.cc \
+       Hist_data.cc \
+       IndexObject.cc \
+       IOActivity.cc \
+       LoadObject.cc \
+       MachineModel.cc \
+       MemObject.cc \
+       MemorySpace.cc \
+       Metric.cc \
+       MetricList.cc \
+       Module.cc \
+       Ovw_data.cc \
+       PRBTree.cc \
+       PathTree.cc \
+       PreviewExp.cc \
+       Print.cc \
+       SAXParserFactory.cc \
+       Sample.cc \
+       Settings.cc \
+       SourceFile.cc \
+       Stabs.cc \
+       Stats_data.cc \
+       StringBuilder.cc \
+       Table.cc \
+       QLParser.tab.cc \
+       dbe_collctrl.cc \
+       i18n.cc \
+       parse.cc \
+       UserLabel.cc \
+       util.cc \
+       Dbe.cc \
+       $(NULL)
+
+CSOURCES = \
+       dbe_hwcdrv.c \
+       dbe_hwcfuncs.c \
+       dbe_hwctable.c \
+       dbe_memmgr.c \
+       gethrtime.c \
+       $(NULL)
+
+LIBGPROFNG = libgprofng.la
+
+AM_CPPFLAGS = $(GPROFNG_CPPFLAGS) -DLOCALEDIR=\"@localedir@\" -I.. -I$(srcdir) \
+       -I$(srcdir)/../common \
+       -I$(srcdir)/../../include -I$(srcdir)/../../opcodes \
+       -I../../bfd -I$(srcdir)/../../bfd
+AM_CFLAGS = $(GPROFNG_CFLAGS) $(PTHREAD_CFLAGS) -Wno-switch \
+       -Wno-format-truncation
+AM_CXXFLAGS = $(AM_CFLAGS)
+
+man_MANS = gprofng.1 \
+       gp-archive.1 \
+       gp-collect-app.1 \
+       gp-display-src.1 \
+       gp-display-text.1
+
+MAINTAINERCLEANFILES = $(man_MANS)
+
+EXTRA_DIST = $(man_MANS)
+
+
+lib_LTLIBRARIES = $(LIBGPROFNG)
+libgprofng_la_SOURCES = $(CCSOURCES) $(CSOURCES)
+libgprofng_la_LDFLAGS = -version-info 0:0:0
+libgprofng_la_LIBADD = $(top_builddir)/../opcodes/libopcodes.la \
+       $(top_builddir)/../bfd/libbfd.la \
+       $(GPROFNG_LIBADD) \
+       $(PTHREAD_LIBS) -ldl
+
+dbedir = $(prefix)/etc
+dbe_DATA = $(srcdir)/gprofng.rc
+
+
+bin_PROGRAMS = gp-archive gp-collect-app gprofng gp-display-text gp-display-src
+
+gp_archive_SOURCES = gp-archive.cc ArchiveExp.cc
+gp_archive_LDADD = $(LIBGPROFNG)
+
+gp_collect_app_SOURCES = gp-collect-app.cc checks.cc envsets.cc count.cc
+gp_collect_app_LDADD = $(LIBGPROFNG)
+
+gprofng_SOURCES = gprofng.cc
+gprofng_LDADD = $(LIBGPROFNG)
+
+gp_display_src_SOURCES = gp-display-src.cc
+gp_display_src_LDADD = $(LIBGPROFNG)
+
+gp_display_text_SOURCES = gp-display-text.cc ipc.cc ipcio.cc
+gp_display_text_LDADD = $(LIBGPROFNG)
+
+
+if BUILD_MAN
+
+# The man pages depend on the version number and on a help2man include file.
+common_mandeps = $(top_srcdir)/../bfd/version.m4
+
+# Use -o so that the `missing' program can infer the output file.
+# Embolden subcommand names in the output, and include a SEE ALSO.
+# Arrange to regenerate the output if we have help2man, but leave the
+# disted output there otherwise.
+# Some extra annoying complexity is in place so that people without
+# help2man dno't accidentally overwrite the manpage.
+
+INFO_PAGE            = "gprofng"
+MANUAL               = "User Commands"
+TEXT_GPROFNG         = "the driver for the gprofng tool suite"
+TEXT_GP_ARCHIVE      = "archive gprofng experiment data"
+TEXT_GP_COLLECT_APP  = "collect performance data for the target application"
+TEXT_GP_DISPLAY_SRC  = "display the source code, optionally interleaved with the disassembly of the target object"
+TEXT_GP_DISPLAY_TEXT = "display the performance data in plain text format"
+
+HELP2MAN_OPT = --libtool --no-info --info-page=$(INFO_PAGE) --manual=$(MANUAL)
+H2M_FILTER = | sed 's/\.TP/\.TP\n.B/' | sed 's/Commands:/\.SH COMMANDS/' \
+  | sed 's/See also:/\.SH SEE ALSO/' | sed 's/Documentation:/.SH DOCUMENTATION/' \
+  | sed 's/Limitations:/.SH LIMITATIONS/'
+
+gprofng.1: $(srcdir)/gprofng.cc $(common_mandeps) | ./gprofng$(EXEEXT)
+       $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+         --name=$(TEXT_GPROFNG) ./gprofng$(EXEEXT) $(H2M_FILTER) > $@
+
+gp-archive.1: $(srcdir)/gp-archive.cc $(common_mandeps) | ./gp-archive$(EXEEXT)
+       $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+         --name=$(TEXT_GP_ARCHIVE) ./gp-archive$(EXEEXT) $(H2M_FILTER) > $@
+
+gp-collect-app.1: $(srcdir)/gp-collect-app.cc $(common_mandeps) | ./gp-collect-app$(EXEEXT)
+       $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+         --name=$(TEXT_GP_COLLECT_APP) ./gp-collect-app$(EXEEXT) $(H2M_FILTER) > $@
+
+gp-display-src.1: $(srcdir)/gp-display-src.cc $(srcdir)/Command.cc \
+               $(common_mandeps) | ./gp-display-src$(EXEEXT)
+       $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+         --name=$(TEXT_GP_DISPLAY_SRC) ./gp-display-src$(EXEEXT) $(H2M_FILTER) > $@
+
+gp-display-text.1: $(srcdir)/gp-display-text.cc $(srcdir)/Command.cc \
+               $(common_mandeps) | ./gp-display-text$(EXEEXT)
+       $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+         --name=$(TEXT_GP_DISPLAY_TEXT) ./gp-display-text$(EXEEXT) $(H2M_FILTER) > $@
+
+endif
+
+# Distribution involves building the binaries to generate the manpage,
+# so ensure that the necessary libraries are built at dist time.
+dist-hook: $(LIBGPROFNG)
+
diff --git a/gprofng/src/Makefile.in b/gprofng/src/Makefile.in
new file mode 100644 (file)
index 0000000..f21671d
--- /dev/null
@@ -0,0 +1,1171 @@
+# 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@
+bin_PROGRAMS = gp-archive$(EXEEXT) gp-collect-app$(EXEEXT) \
+       gprofng$(EXEEXT) gp-display-text$(EXEEXT) \
+       gp-display-src$(EXEEXT)
+subdir = src
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../libtool.m4 \
+       $(top_srcdir)/../ltoptions.m4 $(top_srcdir)/../ltsugar.m4 \
+       $(top_srcdir)/../ltversion.m4 $(top_srcdir)/../lt~obsolete.m4 \
+       $(top_srcdir)/acinclude.m4 $(top_srcdir)/../config/warnings.m4 \
+       $(top_srcdir)/../config/enable.m4 \
+       $(top_srcdir)/../config/ax_pthread.m4 \
+       $(top_srcdir)/config/bison.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 $(am__DIST_COMMON)
+mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/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)$(bindir)" \
+       "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(dbedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgprofng_la_DEPENDENCIES = $(top_builddir)/../opcodes/libopcodes.la \
+       $(top_builddir)/../bfd/libbfd.la $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1)
+am__objects_1 = Application.lo BaseMetric.lo BaseMetricTreeNode.lo \
+       CallStack.lo CatchOutOfMemory.lo ClassFile.lo Command.lo \
+       CompCom.lo DataObject.lo DataSpace.lo Data_window.lo \
+       DataStream.lo DbeApplication.lo DbeFile.lo DbeJarFile.lo \
+       DbeLock.lo DbeSession.lo DbeThread.lo DbeView.lo \
+       DerivedMetrics.lo Disasm.lo Dwarf.lo DwarfLib.lo Elf.lo \
+       Emsg.lo Experiment.lo Exp_Layout.lo ExpGroup.lo Expression.lo \
+       FileData.lo Filter.lo FilterSet.lo Function.lo HeapMap.lo \
+       HeapData.lo HeapActivity.lo Hist_data.lo IndexObject.lo \
+       IOActivity.lo LoadObject.lo MachineModel.lo MemObject.lo \
+       MemorySpace.lo Metric.lo MetricList.lo Module.lo Ovw_data.lo \
+       PRBTree.lo PathTree.lo PreviewExp.lo Print.lo \
+       SAXParserFactory.lo Sample.lo Settings.lo SourceFile.lo \
+       Stabs.lo Stats_data.lo StringBuilder.lo Table.lo \
+       QLParser.tab.lo dbe_collctrl.lo i18n.lo parse.lo UserLabel.lo \
+       util.lo Dbe.lo
+am__objects_2 = dbe_hwcdrv.lo dbe_hwcfuncs.lo dbe_hwctable.lo \
+       dbe_memmgr.lo gethrtime.lo
+am_libgprofng_la_OBJECTS = $(am__objects_1) $(am__objects_2)
+libgprofng_la_OBJECTS = $(am_libgprofng_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 = 
+libgprofng_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+       $(AM_CXXFLAGS) $(CXXFLAGS) $(libgprofng_la_LDFLAGS) $(LDFLAGS) \
+       -o $@
+PROGRAMS = $(bin_PROGRAMS)
+am_gp_archive_OBJECTS = gp-archive.$(OBJEXT) ArchiveExp.$(OBJEXT)
+gp_archive_OBJECTS = $(am_gp_archive_OBJECTS)
+gp_archive_DEPENDENCIES = $(LIBGPROFNG)
+am_gp_collect_app_OBJECTS = gp-collect-app.$(OBJEXT) checks.$(OBJEXT) \
+       envsets.$(OBJEXT) count.$(OBJEXT)
+gp_collect_app_OBJECTS = $(am_gp_collect_app_OBJECTS)
+gp_collect_app_DEPENDENCIES = $(LIBGPROFNG)
+am_gp_display_src_OBJECTS = gp-display-src.$(OBJEXT)
+gp_display_src_OBJECTS = $(am_gp_display_src_OBJECTS)
+gp_display_src_DEPENDENCIES = $(LIBGPROFNG)
+am_gp_display_text_OBJECTS = gp-display-text.$(OBJEXT) ipc.$(OBJEXT) \
+       ipcio.$(OBJEXT)
+gp_display_text_OBJECTS = $(am_gp_display_text_OBJECTS)
+gp_display_text_DEPENDENCIES = $(LIBGPROFNG)
+am_gprofng_OBJECTS = gprofng.$(OBJEXT)
+gprofng_OBJECTS = $(am_gprofng_OBJECTS)
+gprofng_DEPENDENCIES = $(LIBGPROFNG)
+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@ -I$(top_builddir)
+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 = 
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+       $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+       $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+       $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo "  CXX     " $@;
+am__v_CXX_1 = 
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+       $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo "  CXXLD   " $@;
+am__v_CXXLD_1 = 
+SOURCES = $(libgprofng_la_SOURCES) $(gp_archive_SOURCES) \
+       $(gp_collect_app_SOURCES) $(gp_display_src_SOURCES) \
+       $(gp_display_text_SOURCES) $(gprofng_SOURCES)
+DIST_SOURCES = $(libgprofng_la_SOURCES) $(gp_archive_SOURCES) \
+       $(gp_collect_app_SOURCES) $(gp_display_src_SOURCES) \
+       $(gp_display_text_SOURCES) $(gprofng_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+man1dir = $(mandir)/man1
+NROFF = nroff
+MANS = $(man_MANS)
+DATA = $(dbe_DATA)
+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
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../depcomp \
+       $(top_srcdir)/../mkinstalldirs
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BUILD_SUBDIRS = @BUILD_SUBDIRS@
+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@
+EXPECT = @EXPECT@
+FGREP = @FGREP@
+GPROFNG_CFLAGS = @GPROFNG_CFLAGS@
+GPROFNG_CPPFLAGS = @GPROFNG_CPPFLAGS@
+GPROFNG_LIBADD = @GPROFNG_LIBADD@
+GPROFNG_LIBDIR = @GPROFNG_LIBDIR@
+GREP = @GREP@
+HELP2MAN = @HELP2MAN@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+JAVA = @JAVA@
+JAVAC = @JAVAC@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LD_NO_AS_NEEDED = @LD_NO_AS_NEEDED@
+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@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_LIBS = @PTHREAD_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+WERROR = @WERROR@
+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@
+ax_pthread_config = @ax_pthread_config@
+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@
+gprofng_cflags = @gprofng_cflags@
+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@
+jdk_inc = @jdk_inc@
+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@
+subdirs = @subdirs@
+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 .. -I ../.. 
+CCSOURCES = \
+       Application.cc \
+       BaseMetric.cc \
+       BaseMetricTreeNode.cc \
+       CallStack.cc \
+       CatchOutOfMemory.cc \
+       ClassFile.cc \
+       Command.cc \
+       CompCom.cc \
+       DataObject.cc \
+       DataSpace.cc \
+       Data_window.cc \
+       DataStream.cc \
+       DbeApplication.cc \
+       DbeFile.cc \
+       DbeJarFile.cc \
+       DbeLock.cc \
+       DbeSession.cc \
+       DbeThread.cc \
+       DbeView.cc \
+       DerivedMetrics.cc \
+       Disasm.cc \
+       Dwarf.cc \
+       DwarfLib.cc \
+       Elf.cc \
+       Emsg.cc \
+       Experiment.cc \
+       Exp_Layout.cc \
+       ExpGroup.cc \
+       Expression.cc \
+       FileData.cc \
+       Filter.cc \
+       FilterSet.cc \
+       Function.cc \
+       HeapMap.cc \
+       HeapData.cc \
+       HeapActivity.cc \
+       Hist_data.cc \
+       IndexObject.cc \
+       IOActivity.cc \
+       LoadObject.cc \
+       MachineModel.cc \
+       MemObject.cc \
+       MemorySpace.cc \
+       Metric.cc \
+       MetricList.cc \
+       Module.cc \
+       Ovw_data.cc \
+       PRBTree.cc \
+       PathTree.cc \
+       PreviewExp.cc \
+       Print.cc \
+       SAXParserFactory.cc \
+       Sample.cc \
+       Settings.cc \
+       SourceFile.cc \
+       Stabs.cc \
+       Stats_data.cc \
+       StringBuilder.cc \
+       Table.cc \
+       QLParser.tab.cc \
+       dbe_collctrl.cc \
+       i18n.cc \
+       parse.cc \
+       UserLabel.cc \
+       util.cc \
+       Dbe.cc \
+       $(NULL)
+
+CSOURCES = \
+       dbe_hwcdrv.c \
+       dbe_hwcfuncs.c \
+       dbe_hwctable.c \
+       dbe_memmgr.c \
+       gethrtime.c \
+       $(NULL)
+
+LIBGPROFNG = libgprofng.la
+AM_CPPFLAGS = $(GPROFNG_CPPFLAGS) -DLOCALEDIR=\"@localedir@\" -I.. -I$(srcdir) \
+       -I$(srcdir)/../common \
+       -I$(srcdir)/../../include -I$(srcdir)/../../opcodes \
+       -I../../bfd -I$(srcdir)/../../bfd
+
+AM_CFLAGS = $(GPROFNG_CFLAGS) $(PTHREAD_CFLAGS) -Wno-switch \
+       -Wno-format-truncation
+
+AM_CXXFLAGS = $(AM_CFLAGS)
+man_MANS = gprofng.1 \
+       gp-archive.1 \
+       gp-collect-app.1 \
+       gp-display-src.1 \
+       gp-display-text.1
+
+MAINTAINERCLEANFILES = $(man_MANS)
+EXTRA_DIST = $(man_MANS)
+lib_LTLIBRARIES = $(LIBGPROFNG)
+libgprofng_la_SOURCES = $(CCSOURCES) $(CSOURCES)
+libgprofng_la_LDFLAGS = -version-info 0:0:0
+libgprofng_la_LIBADD = $(top_builddir)/../opcodes/libopcodes.la \
+       $(top_builddir)/../bfd/libbfd.la \
+       $(GPROFNG_LIBADD) \
+       $(PTHREAD_LIBS) -ldl
+
+dbedir = $(prefix)/etc
+dbe_DATA = $(srcdir)/gprofng.rc
+gp_archive_SOURCES = gp-archive.cc ArchiveExp.cc
+gp_archive_LDADD = $(LIBGPROFNG)
+gp_collect_app_SOURCES = gp-collect-app.cc checks.cc envsets.cc count.cc
+gp_collect_app_LDADD = $(LIBGPROFNG)
+gprofng_SOURCES = gprofng.cc
+gprofng_LDADD = $(LIBGPROFNG)
+gp_display_src_SOURCES = gp-display-src.cc
+gp_display_src_LDADD = $(LIBGPROFNG)
+gp_display_text_SOURCES = gp-display-text.cc ipc.cc ipcio.cc
+gp_display_text_LDADD = $(LIBGPROFNG)
+
+# The man pages depend on the version number and on a help2man include file.
+@BUILD_MAN_TRUE@common_mandeps = $(top_srcdir)/../bfd/version.m4
+
+# Use -o so that the `missing' program can infer the output file.
+# Embolden subcommand names in the output, and include a SEE ALSO.
+# Arrange to regenerate the output if we have help2man, but leave the
+# disted output there otherwise.
+# Some extra annoying complexity is in place so that people without
+# help2man dno't accidentally overwrite the manpage.
+@BUILD_MAN_TRUE@INFO_PAGE = "gprofng"
+@BUILD_MAN_TRUE@MANUAL = "User Commands"
+@BUILD_MAN_TRUE@TEXT_GPROFNG = "the driver for the gprofng tool suite"
+@BUILD_MAN_TRUE@TEXT_GP_ARCHIVE = "archive gprofng experiment data"
+@BUILD_MAN_TRUE@TEXT_GP_COLLECT_APP = "collect performance data for the target application"
+@BUILD_MAN_TRUE@TEXT_GP_DISPLAY_SRC = "display the source code, optionally interleaved with the disassembly of the target object"
+@BUILD_MAN_TRUE@TEXT_GP_DISPLAY_TEXT = "display the performance data in plain text format"
+@BUILD_MAN_TRUE@HELP2MAN_OPT = --libtool --no-info --info-page=$(INFO_PAGE) --manual=$(MANUAL)
+@BUILD_MAN_TRUE@H2M_FILTER = | sed 's/\.TP/\.TP\n.B/' | sed 's/Commands:/\.SH COMMANDS/' \
+@BUILD_MAN_TRUE@  | sed 's/See also:/\.SH SEE ALSO/' | sed 's/Documentation:/.SH DOCUMENTATION/' \
+@BUILD_MAN_TRUE@  | sed 's/Limitations:/.SH LIMITATIONS/'
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cc .lo .o .obj
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am  $(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --foreign src/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+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}; \
+       }
+
+libgprofng.la: $(libgprofng_la_OBJECTS) $(libgprofng_la_DEPENDENCIES) $(EXTRA_libgprofng_la_DEPENDENCIES) 
+       $(AM_V_CXXLD)$(libgprofng_la_LINK) -rpath $(libdir) $(libgprofng_la_OBJECTS) $(libgprofng_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+       fi; \
+       for p in $$list; do echo "$$p $$p"; done | \
+       sed 's/$(EXEEXT)$$//' | \
+       while read p p1; do if test -f $$p \
+        || test -f $$p1 \
+         ; then echo "$$p"; echo "$$p"; else :; fi; \
+       done | \
+       sed -e 'p;s,.*/,,;n;h' \
+           -e 's|.*|.|' \
+           -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+       sed 'N;N;N;s,\n, ,g' | \
+       $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+         { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+           if ($$2 == $$4) files[d] = files[d] " " $$1; \
+           else { print "f", $$3 "/" $$4, $$1; } } \
+         END { for (d in files) print "f", d, files[d] }' | \
+       while read type dir files; do \
+           if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+           test -z "$$files" || { \
+           echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+           $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+           } \
+       ; done
+
+uninstall-binPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+       files=`for p in $$list; do echo "$$p"; done | \
+         sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+             -e 's/$$/$(EXEEXT)/' \
+       `; \
+       test -n "$$list" || exit 0; \
+       echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+       @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+       echo " rm -f" $$list; \
+       rm -f $$list || exit $$?; \
+       test -n "$(EXEEXT)" || exit 0; \
+       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+       echo " rm -f" $$list; \
+       rm -f $$list
+
+gp-archive$(EXEEXT): $(gp_archive_OBJECTS) $(gp_archive_DEPENDENCIES) $(EXTRA_gp_archive_DEPENDENCIES) 
+       @rm -f gp-archive$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(gp_archive_OBJECTS) $(gp_archive_LDADD) $(LIBS)
+
+gp-collect-app$(EXEEXT): $(gp_collect_app_OBJECTS) $(gp_collect_app_DEPENDENCIES) $(EXTRA_gp_collect_app_DEPENDENCIES) 
+       @rm -f gp-collect-app$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(gp_collect_app_OBJECTS) $(gp_collect_app_LDADD) $(LIBS)
+
+gp-display-src$(EXEEXT): $(gp_display_src_OBJECTS) $(gp_display_src_DEPENDENCIES) $(EXTRA_gp_display_src_DEPENDENCIES) 
+       @rm -f gp-display-src$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(gp_display_src_OBJECTS) $(gp_display_src_LDADD) $(LIBS)
+
+gp-display-text$(EXEEXT): $(gp_display_text_OBJECTS) $(gp_display_text_DEPENDENCIES) $(EXTRA_gp_display_text_DEPENDENCIES) 
+       @rm -f gp-display-text$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(gp_display_text_OBJECTS) $(gp_display_text_LDADD) $(LIBS)
+
+gprofng$(EXEEXT): $(gprofng_OBJECTS) $(gprofng_DEPENDENCIES) $(EXTRA_gprofng_DEPENDENCIES) 
+       @rm -f gprofng$(EXEEXT)
+       $(AM_V_CXXLD)$(CXXLINK) $(gprofng_OBJECTS) $(gprofng_LDADD) $(LIBS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT)
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Application.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ArchiveExp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BaseMetric.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BaseMetricTreeNode.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CallStack.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CatchOutOfMemory.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClassFile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Command.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CompCom.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DataObject.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DataSpace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DataStream.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Data_window.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Dbe.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeApplication.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeFile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeJarFile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeLock.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeSession.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeThread.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbeView.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DerivedMetrics.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Disasm.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Dwarf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DwarfLib.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Elf.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Emsg.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ExpGroup.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Exp_Layout.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Experiment.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Expression.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileData.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Filter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FilterSet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Function.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HeapActivity.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HeapData.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HeapMap.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Hist_data.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IOActivity.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IndexObject.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LoadObject.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MachineModel.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MemObject.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MemorySpace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Metric.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetricList.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Module.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Ovw_data.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PRBTree.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PathTree.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PreviewExp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Print.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/QLParser.tab.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SAXParserFactory.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Sample.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Settings.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SourceFile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Stabs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Stats_data.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StringBuilder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Table.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UserLabel.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/checks.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/count.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbe_collctrl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbe_hwcdrv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbe_hwcfuncs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbe_hwctable.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbe_memmgr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/envsets.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gethrtime.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gp-archive.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gp-collect-app.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gp-display-src.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gp-display-text.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gprofng.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i18n.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ipcio.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.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)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@   $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.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)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@   $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@   $(am__mv) $$depbase.Tpo $$depbase.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 $@ $<
+
+.cc.o:
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@  $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@  $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@  $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@  $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@  $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@  $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@  $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@     DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+install-man1: $(man_MANS)
+       @$(NORMAL_INSTALL)
+       @list1=''; \
+       list2='$(man_MANS)'; \
+       test -n "$(man1dir)" \
+         && test -n "`echo $$list1$$list2`" \
+         || exit 0; \
+       echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
+       $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
+       { for i in $$list1; do echo "$$i"; done;  \
+       if test -n "$$list2"; then \
+         for i in $$list2; do echo "$$i"; done \
+           | sed -n '/\.1[a-z]*$$/p'; \
+       fi; \
+       } | while read p; do \
+         if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; echo "$$p"; \
+       done | \
+       sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+       sed 'N;N;s,\n, ,g' | { \
+       list=; while read file base inst; do \
+         if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+           echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+           $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+         fi; \
+       done; \
+       for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+       while read files; do \
+         test -z "$$files" || { \
+           echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+           $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+       done; }
+
+uninstall-man1:
+       @$(NORMAL_UNINSTALL)
+       @list=''; test -n "$(man1dir)" || exit 0; \
+       files=`{ for i in $$list; do echo "$$i"; done; \
+       l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+         sed -n '/\.1[a-z]*$$/p'; \
+       } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+             -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+       dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
+install-dbeDATA: $(dbe_DATA)
+       @$(NORMAL_INSTALL)
+       @list='$(dbe_DATA)'; test -n "$(dbedir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(dbedir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(dbedir)" || 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_DATA) $$files '$(DESTDIR)$(dbedir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(dbedir)" || exit $$?; \
+       done
+
+uninstall-dbeDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(dbe_DATA)'; test -n "$(dbedir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       dir='$(DESTDIR)$(dbedir)'; $(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"
+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
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+       $(MAKE) $(AM_MAKEFLAGS) \
+         top_distdir="$(top_distdir)" distdir="$(distdir)" \
+         dist-hook
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(MANS) $(DATA)
+install-binPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+       for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(dbedir)"; 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."
+       -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+       clean-libtool mostlyclean-am
+
+distclean: distclean-am
+       -rm -rf ./$(DEPDIR)
+       -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+       distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dbeDATA install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man1
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -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-binPROGRAMS uninstall-dbeDATA \
+       uninstall-libLTLIBRARIES uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \
+       clean-binPROGRAMS clean-generic clean-libLTLIBRARIES \
+       clean-libtool cscopelist-am ctags ctags-am dist-hook distclean \
+       distclean-compile distclean-generic distclean-libtool \
+       distclean-tags distdir dvi dvi-am html html-am info info-am \
+       install install-am install-binPROGRAMS install-data \
+       install-data-am install-dbeDATA 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-man1 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-binPROGRAMS uninstall-dbeDATA \
+       uninstall-libLTLIBRARIES uninstall-man uninstall-man1
+
+.PRECIOUS: Makefile
+
+
+@BUILD_MAN_TRUE@gprofng.1: $(srcdir)/gprofng.cc $(common_mandeps) | ./gprofng$(EXEEXT)
+@BUILD_MAN_TRUE@       $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+@BUILD_MAN_TRUE@         --name=$(TEXT_GPROFNG) ./gprofng$(EXEEXT) $(H2M_FILTER) > $@
+
+@BUILD_MAN_TRUE@gp-archive.1: $(srcdir)/gp-archive.cc $(common_mandeps) | ./gp-archive$(EXEEXT)
+@BUILD_MAN_TRUE@       $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+@BUILD_MAN_TRUE@         --name=$(TEXT_GP_ARCHIVE) ./gp-archive$(EXEEXT) $(H2M_FILTER) > $@
+
+@BUILD_MAN_TRUE@gp-collect-app.1: $(srcdir)/gp-collect-app.cc $(common_mandeps) | ./gp-collect-app$(EXEEXT)
+@BUILD_MAN_TRUE@       $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+@BUILD_MAN_TRUE@         --name=$(TEXT_GP_COLLECT_APP) ./gp-collect-app$(EXEEXT) $(H2M_FILTER) > $@
+
+@BUILD_MAN_TRUE@gp-display-src.1: $(srcdir)/gp-display-src.cc $(srcdir)/Command.cc \
+@BUILD_MAN_TRUE@               $(common_mandeps) | ./gp-display-src$(EXEEXT)
+@BUILD_MAN_TRUE@       $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+@BUILD_MAN_TRUE@         --name=$(TEXT_GP_DISPLAY_SRC) ./gp-display-src$(EXEEXT) $(H2M_FILTER) > $@
+
+@BUILD_MAN_TRUE@gp-display-text.1: $(srcdir)/gp-display-text.cc $(srcdir)/Command.cc \
+@BUILD_MAN_TRUE@               $(common_mandeps) | ./gp-display-text$(EXEEXT)
+@BUILD_MAN_TRUE@       $(AM_V_GEN)_BUILDING_MANPAGE=1 $(HELP2MAN) $(HELP2MAN_OPT) \
+@BUILD_MAN_TRUE@         --name=$(TEXT_GP_DISPLAY_TEXT) ./gp-display-text$(EXEEXT) $(H2M_FILTER) > $@
+
+# Distribution involves building the binaries to generate the manpage,
+# so ensure that the necessary libraries are built at dist time.
+dist-hook: $(LIBGPROFNG)
+
+# 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/src/Map.h b/gprofng/src/Map.h
new file mode 100644 (file)
index 0000000..530dcfc
--- /dev/null
@@ -0,0 +1,61 @@
+/* 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 _DBE_MAP_H
+#define _DBE_MAP_H
+
+#include "vec.h"
+
+template <typename Key_t, typename Value_t>
+class Map
+{
+public:
+
+  enum Relation
+  {
+    REL_LT,
+    REL_LE,
+    REL_EQ,
+    REL_GE,
+    REL_GT
+  };
+
+  virtual ~Map () { };
+  virtual void put (Key_t key, Value_t val) = 0;
+  virtual Value_t get (Key_t key) = 0;
+  virtual Value_t get (Key_t key, Relation rel) = 0;
+  virtual Value_t remove (Key_t key) = 0;
+
+  virtual Vector<Key_t> *
+  keySet ()
+  {
+    return NULL;
+  }
+
+  virtual Vector<Value_t> *
+  values ()
+  {
+    return NULL;
+  }
+};
+
+#define destroy_map(t, p) if (p) { Vector<t> *v = p->values (); Destroy (v); delete p; }
+
+#endif
diff --git a/gprofng/src/Map2D.h b/gprofng/src/Map2D.h
new file mode 100644 (file)
index 0000000..41b2be2
--- /dev/null
@@ -0,0 +1,53 @@
+/* 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 _DBE_MAP2D_H
+#define _DBE_MAP2D_H
+
+template <typename Key1_t, typename Key2_t, typename Value_t>
+class Map2D
+{
+public:
+
+  enum MapType
+  {
+    Default,
+    Interval
+  };
+
+  // Relation for the first key is always EQUAL
+  enum Relation
+  {
+    REL_EQLT,
+    REL_EQLE,
+    REL_EQEQ,
+    REL_EQGE,
+    REL_EQGT
+  };
+
+  virtual ~Map2D () { };
+  virtual void put (Key1_t key1, Key2_t key2, Value_t val) = 0;
+  virtual Value_t get (Key1_t key1, Key2_t key2) = 0;
+  virtual Value_t get (Key1_t key1, Key2_t key2, Relation rel) = 0;
+  virtual Value_t remove (Key1_t key1, Key2_t key2) = 0;
+
+};
+
+#endif
diff --git a/gprofng/src/MemObject.cc b/gprofng/src/MemObject.cc
new file mode 100644 (file)
index 0000000..d207a99
--- /dev/null
@@ -0,0 +1,44 @@
+/* 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 "Exp_Layout.h"
+#include "MemObject.h"
+#include "DataSpace.h"
+#include "ABS.h"
+#include "Dbe.h"
+#include "i18n.h"
+
+MemObj::MemObj (uint64_t _index, char *_name)
+{
+  id = _index;
+  name = _name;
+}
+
+MemObj::~MemObj ()
+{
+  free (name);
+}
+
+Histable *
+MemObj::convertto (Histable_type type, Histable*)
+{
+  return type == MEMOBJ ? this : NULL;
+}
diff --git a/gprofng/src/MemObject.h b/gprofng/src/MemObject.h
new file mode 100644 (file)
index 0000000..6bc459f
--- /dev/null
@@ -0,0 +1,62 @@
+/* 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 _MEMOBJECT_H
+#define _MEMOBJECT_H
+
+#include "Histable.h"
+#include "util.h"
+
+class MemObj : public Histable
+{
+public:
+  friend class MemorySpace;
+
+  MemObj (uint64_t _index, char *_name);
+  ~MemObj ();
+
+  virtual Histable *convertto (Histable_type, Histable* = NULL);
+
+  virtual Histable_type
+  get_type ()
+  {
+    return MEMOBJ;
+  }
+
+  virtual char *
+  get_name (NameFormat = NA)
+  {
+    return dbe_strdup (name);
+  }
+
+  virtual uint64_t
+  get_addr ()
+  {
+    return id;
+  }
+
+  uint64_t
+  get_index ()
+  {
+    return id;
+  }
+};
+
+#endif  /* _MEMOBJECT_H */
diff --git a/gprofng/src/MemorySpace.cc b/gprofng/src/MemorySpace.cc
new file mode 100644 (file)
index 0000000..3f7c78d
--- /dev/null
@@ -0,0 +1,452 @@
+/* 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 <ctype.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "Application.h"
+#include "Experiment.h"
+#include "Exp_Layout.h"
+#include "MetricList.h"
+#include "MemObject.h"
+#include "PathTree.h"
+#include "DbeView.h"
+#include "Metric.h"
+#include "MemorySpace.h"
+#include "Table.h"
+#include "IndexObject.h"
+
+MemObjType_t::MemObjType_t ()
+{
+  type = -1;
+  name = NULL;
+  index_expr = NULL;
+  machmodel = NULL;
+  mnemonic = 0;
+  short_description = NULL;
+  long_description = NULL;
+}
+
+MemObjType_t::~MemObjType_t ()
+{
+  free (name);
+  free (index_expr);
+  free (machmodel);
+  free (short_description);
+  free (long_description);
+}
+
+MemorySpace::MemorySpace (DbeView *_dbev, int _mstype)
+{
+  char *mname;
+  dbev = _dbev;
+  phaseIdx = -1;
+
+  // set up the MemoryObject information
+  objs = new HashMap<uint64_t, MemObj*>;
+  mstype = _mstype;
+  msindex_exp = NULL;
+  msname = NULL;
+  msindex_exp_str = NULL;
+
+  // find the memory space in the table
+  MemObjType_t *mot = findMemSpaceByIndex (mstype);
+  if (mot)
+    {
+      msname = dbe_strdup (mot->name);
+      if (mot->index_expr != NULL)
+       {
+         msindex_exp_str = dbe_strdup (mot->index_expr);
+         msindex_exp = dbeSession->ql_parse (msindex_exp_str);
+         if (msindex_exp == NULL)
+           // this was checked when the definition was created
+           abort ();
+       }
+    }
+
+  // create the Total and Unknown objects
+  mname = dbe_strdup (NTXT ("<Total>"));
+  total_memobj = createMemObject ((uint64_t) - 2, mname);
+  mname = dbe_strdup (GTXT ("<Unknown>"));
+  unk_memobj = createMemObject ((uint64_t) - 1, mname);
+  hist_data_all = NULL;
+  selected_mo_index = (uint64_t) - 3;
+  sel_ind = -1;
+}
+
+MemorySpace::~MemorySpace ()
+{
+  reset ();
+  delete objs;
+  free (msname);
+  free (msindex_exp);
+  free (msindex_exp_str);
+}
+
+void
+MemorySpace::reset ()
+{
+  if (hist_data_all != NULL)
+    {
+      delete hist_data_all;
+      hist_data_all = NULL;
+    }
+  // do not clear the selected object's index
+  // selected_mo_index = (uint64_t)-3;
+
+  // destroy any existing objects, but keep the vector
+  // Now that we have a hashmap, which has its own vector,
+  //     safe to delete and reallocate
+  delete objs;
+  objs = new HashMap<uint64_t, MemObj*>;
+}
+
+// find a memory object by its memory-object index
+int
+MemorySpace::findMemObject (uint64_t indx)
+{
+  int index;
+  Hist_data::HistItem *hi;
+  if (indx == (uint64_t) - 3)
+    return -1;
+
+  Vec_loop (Hist_data::HistItem *, hist_data_all->hist_items, index, hi)
+  {
+    if (((uint64_t) ((MemObj *) hi->obj)->id) == indx)
+      return index;
+  }
+  // object does not exist; filter change eliminated it, for example
+  return -1;
+}
+
+// find the object referenced in the packet
+MemObj *
+MemorySpace::lookupMemObject (Experiment *exp, DataView *packets, long i)
+{
+  uint64_t idx;
+  uint64_t va = (uint64_t) packets->getLongValue (PROP_VADDR, i);
+  if (va == ABS_UNSUPPORTED)
+    // return NULL, to ignore the record
+    return NULL;
+  if (va < ABS_CODE_RANGE)
+    // The va is not valid, rather, it's an error code
+    // return the <Unknown> object
+    return unk_memobj;
+
+  Expression::Context ctx (dbev, exp, packets, i);
+  idx = msindex_exp->eval (&ctx);
+  if (idx == (uint64_t) - 1)
+    return unk_memobj;
+
+  // do a binary search for the memory object
+  MemObj *res = objs->get (idx);
+  if (res == NULL)
+    {
+      res = createMemObject (idx, NULL);
+      objs->put (idx, res);
+    }
+  else
+    return res;
+
+  // recompute range
+  if (idx < idx_min)
+    idx_min = idx;
+  if (idx > idx_max)
+    idx_max = idx;
+  return res;
+}
+
+MemObj *
+MemorySpace::createMemObject (uint64_t index, char *moname)
+{
+  MemObj *res;
+  char *name;
+  if (moname != NULL)
+    {
+      res = new MemObj (index, moname);
+      return res;
+    }
+
+  // Custom memory objects
+  // The memory_page_size is defined in the machine model file such
+  // as ./machinemodels/t4.ermm.
+  // Most users prefer to look at the hexadecimal version of virtual
+  // addresses. Display only the hexadecimal version of virtual addresses
+  // for all machine model views with an exception of virtual page size.
+  if (dbe_strcmp (msname, NTXT ("Memory_page_size")) == 0)
+    name = dbe_sprintf (NTXT ("%s 0x%16.16llx (%llu)"), msname,
+                       (long long) index, (unsigned long long) index);
+  else if (dbe_strcmp (msname, NTXT ("Memory_in_home_lgrp")) == 0)
+    name = dbe_sprintf (NTXT ("%s: %s"), msname,
+                       index == 1 ? GTXT ("True") : index == 0 ? GTXT ("False")
+                       : GTXT ("<Unknown>"));
+  else if (dbe_strcmp (msname, NTXT ("Memory_lgrp")) == 0)
+    name = dbe_sprintf (NTXT ("%s %llu"), msname, (unsigned long long) index);
+  else
+    name = dbe_sprintf (NTXT ("%s 0x%16.16llx"), msname, (long long) index);
+
+  res = new MemObj (index, name);
+  return res;
+}
+
+
+static Vector<MemObjType_t*> dyn_memobj_vec;
+static Vector<MemObjType_t*> *dyn_memobj = &dyn_memobj_vec;
+static Vector<int> *ordlist;
+
+// Static function to get a vector of custom memory object definitions
+
+Vector<void*> *
+MemorySpace::getMemObjects ()
+{
+  MemObjType_t *mot;
+  int ii;
+  int size = dyn_memobj->size ();
+  Vector<int> *indx = new Vector<int>(size);
+  Vector<char*> *name = new Vector<char*>(size);
+  Vector<char> *mnemonic = new Vector<char>(size);
+  Vector<char*> *formula = new Vector<char*>(size);
+  Vector<char*> *machmodel = new Vector<char*>(size);
+  Vector<int> *order = new Vector<int>(size);
+  Vector<char*> *sdesc = new Vector<char*>(size);
+  Vector<char*> *ldesc = new Vector<char*>(size);
+
+  if (size > 0)
+    {
+      Vec_loop (MemObjType_t *, dyn_memobj, ii, mot)
+      {
+       indx->store (ii, mot->type);
+       order->store (ii, ii);
+       name->store (ii, dbe_strdup (mot->name));
+       formula->store (ii, dbe_strdup (mot->index_expr));
+       mnemonic->store (ii, mot->mnemonic);
+       sdesc->store (ii, mot->short_description == NULL ? NULL
+                     : dbe_strdup (mot->short_description));
+       ldesc->store (ii, mot->long_description == NULL ? NULL
+                     : dbe_strdup (mot->long_description));
+       if (mot->machmodel == NULL)
+         machmodel->store (ii, NULL);
+       else
+         machmodel->store (ii, dbe_strdup (mot->machmodel));
+      }
+    }
+  Vector<void*> *res = new Vector<void*>(8);
+  res->store (0, indx);
+  res->store (1, name);
+  res->store (2, mnemonic);
+  res->store (3, formula);
+  res->store (4, machmodel);
+  res->store (5, order);
+  res->store (6, sdesc);
+  res->store (7, ldesc);
+  return (res);
+}
+
+// Static function to set order of memory object tabs
+void
+MemorySpace::set_MemTabOrder (Vector<int> *orders)
+{
+  int size = orders->size ();
+  ordlist = new Vector<int>(size);
+  for (int i = 0; i < size; i++)
+    ordlist->store (i, orders->fetch (i));
+}
+
+// Static function to define a new memory object type
+char *
+MemorySpace::mobj_define (char *mname, char *mindex_exp, char *_machmodel,
+                         char *short_description, char *long_description)
+{
+  MemObjType_t *mot;
+
+  if (mname == NULL)
+    return dbe_strdup (GTXT ("No memory object name has been specified."));
+  if (isalpha ((int) (mname[0])) == 0)
+    return dbe_sprintf (GTXT ("Memory Object type name %s does not begin with an alphabetic character"),
+                       mname);
+  char *p = mname;
+  while (*p != 0)
+    {
+      if (isalnum ((int) (*p)) == 0 && *p != '_')
+       return dbe_sprintf (GTXT ("Memory Object type name %s contains a non-alphanumeric character"),
+                           mname);
+      p++;
+    }
+
+  mot = findMemSpaceByName (mname);
+  if (mot != NULL)
+    {
+      if (strcmp (mot->index_expr, mindex_exp) == 0)
+       // It's a redefinition, but the new definition is the same
+       return NULL;
+      return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
+                         mname);
+    }
+
+  // make sure the name is not in use
+  if (dbeSession->findIndexSpaceByName (mname) >= 0)
+    return dbe_sprintf (GTXT ("Memory/Index Object type name %s is already defined"),
+                       mname);
+
+  if (mindex_exp == NULL || *mindex_exp == 0)
+    return dbe_strdup (GTXT ("No index-expr has been specified."));
+
+  // verify that the index expression parses correctly
+  Expression *e = dbeSession->ql_parse (mindex_exp);
+  if (e == NULL)
+    return dbe_sprintf (GTXT ("Memory Object index expression is invalid: %s"),
+                       mindex_exp);
+  delete e;
+
+  // It's OK, create the new table entry
+  char *s = dbeSession->indxobj_define (mname, NULL, mindex_exp,
+                                       short_description, long_description);
+  if (s)
+    return s;
+  IndexObjType_t *indObj = dbeSession->findIndexSpace (mname);
+
+  mot = new MemObjType_t;
+  mot->type = indObj->type;
+  indObj->memObj = mot;
+  mot->name = dbe_strdup (mname);
+  mot->index_expr = dbe_strdup (mindex_exp);
+  mot->mnemonic = MemorySpace::pickMnemonic (mname);
+  mot->machmodel = dbe_strdup (_machmodel);
+  mot->short_description = dbe_strdup (short_description);
+  mot->long_description = dbe_strdup (long_description);
+
+  // add it to the list
+  dyn_memobj->append (mot);
+
+  // tell the session
+  if (dbeSession != NULL)
+    dbeSession->mobj_define (mot);
+  return NULL;
+}
+
+// Static function to delete a new memory object type
+
+char *
+MemorySpace::mobj_delete (char *mname)
+{
+  if (mname == NULL)
+    return dbe_strdup (GTXT ("No memory object name has been specified.\n"));
+
+  // search the dynamic types
+  for (long idx = 0, sz = VecSize (dyn_memobj); idx < sz; idx++)
+    {
+      MemObjType_t *mt = dyn_memobj->get (idx);
+      if (strcasecmp (mt->name, mname) == 0)
+       {
+         // delete it from the vector
+         mt = dyn_memobj->remove (idx);
+         delete mt;
+         dbeSession->removeIndexSpaceByName (mname);
+         return NULL;
+       }
+    }
+  return dbe_sprintf (GTXT ("Memory object `%s' is not defined.\n"), mname);
+}
+
+// Static function to get a list of memory object names from a machine model
+
+Vector <char*> *
+MemorySpace::getMachineModelMemObjs (char *mname)
+{
+  Vector <char *> *ret = new Vector <char *> ();
+  if (mname == NULL)
+    return ret;
+
+  // search the memory objects
+  int idx;
+  MemObjType_t *mt;
+  Vec_loop (MemObjType_t*, dyn_memobj, idx, mt)
+  {
+    if (mt->machmodel != NULL && strcmp (mt->machmodel, mname) == 0)
+      {
+       char *n = dbe_strdup (mt->name);
+       ret->append (n);
+      }
+  }
+  return ret;
+}
+
+char
+MemorySpace::pickMnemonic (char *name)
+{
+  return name[0];
+}
+
+void
+MemorySpace::get_filter_keywords (Vector <void*> *res)
+{
+  Vector <char*> *kwCategory = (Vector<char*>*) res->fetch (0);
+  Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1);
+  Vector <char*> *kwDataType = (Vector<char*>*) res->fetch (2);
+  Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3);
+  Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4);
+  Vector <char*> *kwDescription = (Vector<char*>*) res->fetch (5);
+  Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6);
+
+  char *vtypeNames[] = VTYPE_TYPE_NAMES;
+  for (int i = 0, sz = dyn_memobj ? dyn_memobj->size () : 0; i < sz; i++)
+    {
+      MemObjType_t *obj = dyn_memobj->fetch (i);
+      kwCategory->append (dbe_strdup (NTXT ("FK_MEMOBJ")));
+      kwCategoryI18N->append (dbe_strdup (GTXT ("Memory Object Definitions")));
+      kwDataType->append (dbe_strdup (vtypeNames[TYPE_INT64]));
+      kwKeyword->append (dbe_strdup (obj->name));
+      kwFormula->append (dbe_strdup (obj->index_expr));
+      kwDescription->append (NULL);
+      kwEnumDescs->append (NULL);
+    }
+}
+
+MemObjType_t *
+MemorySpace::findMemSpaceByName (const char *mname)
+{
+  int idx;
+  MemObjType_t *mt;
+
+  // search the dynamic types
+  Vec_loop (MemObjType_t*, dyn_memobj, idx, mt)
+  {
+    if (strcasecmp (mt->name, mname) == 0)
+      return mt;
+  }
+  return NULL;
+}
+
+MemObjType_t *
+MemorySpace::findMemSpaceByIndex (int index)
+{
+  int idx;
+  MemObjType_t *mt;
+
+  // search the dynamic types
+  Vec_loop (MemObjType_t*, dyn_memobj, idx, mt)
+  {
+    if (mt->type == index)
+      return mt;
+  }
+  return NULL;
+}
diff --git a/gprofng/src/MemorySpace.h b/gprofng/src/MemorySpace.h
new file mode 100644 (file)
index 0000000..7d02e5e
--- /dev/null
@@ -0,0 +1,113 @@
+/* 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 _MEMORYSPACE_H
+#define        _MEMORYSPACE_H
+
+#include <stdio.h>
+
+#include "dbe_structs.h"
+#include "vec.h"
+#include "Exp_Layout.h"
+#include "Histable.h"
+#include "Hist_data.h"
+#include "Metric.h"
+#include "HashMap.h"
+
+class Experiment;
+class Expression;
+class DataView;
+class DbeView;
+class MemObj;
+
+class MemObjType_t
+{
+public:
+  MemObjType_t ();
+  ~MemObjType_t ();
+  int type;
+  char *name;
+  char *index_expr;
+  char *machmodel;
+  char mnemonic;
+  char *short_description;
+  char *long_description;
+};
+
+class MemorySpace
+{
+public:
+
+  MemorySpace (DbeView *_dbev, int subtype);
+  ~MemorySpace ();
+
+  void reset (void);
+
+  int
+  getMemObjType (void)
+  {
+    return mstype;
+  }
+
+  char *
+  getMemObjTypeName (void)
+  {
+    return msname;
+  }
+
+  Expression *
+  getMemObjDef (void)
+  {
+    return msindex_exp;
+  }
+
+  // static members, used to define or fetch the various MemorySpaces
+  static void get_filter_keywords (Vector <void*> *res);
+  static Vector<void*> *getMemObjects (void);
+  static void set_MemTabOrder (Vector<int> *);
+  static char *mobj_define (char *, char *, char *, char *, char *);
+  static char *mobj_delete (char *);
+  static MemObjType_t *findMemSpaceByName (const char *mname);
+  static MemObjType_t *findMemSpaceByIndex (int index);
+  static char pickMnemonic (char *name);
+  static Vector<char *> *getMachineModelMemObjs (char *);
+
+private:
+  HashMap<uint64_t, MemObj*> *objs;
+  int findMemObject (uint64_t indx);
+  MemObj *lookupMemObject (Experiment *exp, DataView*, long);
+  MemObj *createMemObject (uint64_t, char *moname);
+
+  int mstype;               // type of this memory space
+  char *msname;             // name of this memory space
+  Expression *msindex_exp;  // index-expression for this memory space
+  char *msindex_exp_str;    // string for index-expression
+  Hist_data *hist_data_all; // the cached data for mode=Hist_Data::ALL
+  uint64_t selected_mo_index; // which page, cacheline, etc.
+  int sel_ind;              // index of selected object in list
+  DbeView *dbev;
+  int phaseIdx;
+  uint64_t idx_min;
+  uint64_t idx_max;
+  MemObj *unk_memobj;
+  MemObj *total_memobj;
+};
+
+#endif /* _MEMORYSPACE_H */
diff --git a/gprofng/src/Metric.cc b/gprofng/src/Metric.cc
new file mode 100644 (file)
index 0000000..3b026ff
--- /dev/null
@@ -0,0 +1,1660 @@
+/* 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 <stdio.h>
+#include <strings.h>
+#include <limits.h>
+#include <sys/param.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "Expression.h"
+#include "Metric.h"
+
+Metric::Metric (BaseMetric *item, SubType st) : BaseMetric (*item)
+{
+  name = NULL;
+  abbr = NULL;
+  abbr_unit = NULL;
+  baseMetric = item;
+  set_subtype (st);
+  visbits = VAL_NA;
+  if (item->get_type () == DERIVED)
+    visbits = VAL_VALUE;
+}
+
+Metric::Metric (const Metric& item) : BaseMetric (item)
+{
+  baseMetric = item.baseMetric;
+  subtype = item.subtype;
+  name = dbe_strdup (item.name);
+  abbr = dbe_strdup (item.abbr);
+  abbr_unit = dbe_strdup (item.abbr_unit);
+  visbits = item.visbits;
+}
+
+Metric::~Metric ()
+{
+  free (name);
+  free (abbr);
+  free (abbr_unit);
+}
+
+// Note that BaseMetric::get_vtype() has the base value type.
+// Here, we get the value type for the displayed metric,
+// which may be different if comparison is used.
+
+ValueTag
+Metric::get_vtype2 ()
+{
+  ValueTag vtype = get_vtype ();
+  if (visbits & VAL_DELTA)
+    {
+      switch (vtype)
+       {
+       case VT_ULLONG: return VT_LLONG;
+       default: return vtype;
+       }
+    }
+  if (visbits & VAL_RATIO)
+    {
+      switch (vtype)
+       {
+       case VT_INT:
+       case VT_LLONG:
+       case VT_ULLONG:
+       case VT_FLOAT:
+       case VT_DOUBLE: return VT_DOUBLE;
+       default: return vtype;
+       }
+    }
+  return vtype;
+}
+
+void
+Metric::set_subtype (SubType st)
+{
+  subtype = st;
+  free (name);
+  free (abbr);
+  free (abbr_unit);
+  name = NULL;
+  abbr = NULL;
+  abbr_unit = NULL;
+
+  switch (get_type ())
+    {
+    case CP_LMS_USER:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive User CPU Time"));
+         abbr = dbe_strdup (GTXT ("Excl. User CPU"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive User CPU Time"));
+         abbr = dbe_strdup (GTXT ("Incl. User CPU"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed User CPU Time"));
+         abbr = dbe_strdup (GTXT ("Attr. User CPU"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected CP_LMS_USER metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+         abort ();
+       }
+      break;
+
+    case CP_LMS_WAIT_CPU:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Wait CPU Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Wait CPU"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Wait CPU Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Wait CPU"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Wait CPU Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Wait CPU"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected CP_LMS_WAIT_CPU metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case CP_LMS_USER_LOCK:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive User Lock Time"));
+         abbr = dbe_strdup (GTXT ("Excl. User Lock"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive User Lock Time"));
+         abbr = dbe_strdup (GTXT ("Incl. User Lock"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed User Lock Time"));
+         abbr = dbe_strdup (GTXT ("Attr. User Lock"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected CP_LMS_USER_LOCK metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case CP_LMS_SYSTEM:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive System CPU Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Sys. CPU"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive System CPU Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Sys. CPU"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed System CPU Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Sys. CPU"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected CP_LMS_SYSTEM metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case SYNC_WAIT_TIME:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Sync Wait Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Sync Wait"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Sync Wait Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Sync Wait"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Sync Wait Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Sync Wait"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected LWT metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case CP_LMS_TFAULT:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Text Page Fault Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Text Fault"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Text Page Fault Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Text Fault"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Text Page Fault Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Text Fault"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected CP_LMS_TFAULT metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case CP_LMS_DFAULT:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Data Page Fault Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Data Fault"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Data Page Fault Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Data Fault"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Data Page Fault Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Data Fault"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected CP_LMS_DFAULT metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case CP_KERNEL_CPU:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Kernel CPU Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Kernel CPU"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Kernel CPU Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Kernel CPU"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Kernel CPU Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Kernel CPU"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected CP_KERNEL_CPU metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case HWCNTR:
+      {
+       char *sstr, *estr1, *estr2;
+       if (get_hw_ctr () == NULL)
+         abort ();
+       sstr = get_username ();
+       if (st == EXCLUSIVE)
+         {
+           estr1 = GTXT ("Exclusive ");
+           estr2 = GTXT ("Excl. ");
+         }
+       else if (st == INCLUSIVE)
+         {
+           estr1 = GTXT ("Inclusive ");
+           estr2 = GTXT ("Incl. ");
+         }
+       else if (st == ATTRIBUTED)
+         {
+           estr1 = GTXT ("Attributed ");
+           estr2 = GTXT ("Attr. ");
+         }
+       else if (st == DATASPACE)
+         {
+           estr1 = GTXT ("Data-derived ");
+           estr2 = GTXT ("Data. ");
+         }
+       else
+         {
+           estr1 = dbe_sprintf (GTXT ("Unexpected hwc %s metric subtype %d"),
+                                get_aux (), st);
+           estr2 = dbe_strdup (NTXT ("??"));
+         }
+       name = dbe_sprintf (NTXT ("%s%s"), estr1, sstr);
+       abbr = dbe_sprintf (NTXT ("%s%s"), estr2, sstr);
+       break;
+      }
+
+    case DERIVED:
+      {
+       switch (st)
+         {
+         case EXCLUSIVE:
+           name = dbe_sprintf (GTXT ("Exclusive %s"), get_username ());
+           abbr = dbe_sprintf (GTXT ("Excl. %s"), get_cmd ());
+           break;
+         case INCLUSIVE:
+           name = dbe_sprintf (GTXT ("Inclusive %s"), get_username ());
+           abbr = dbe_sprintf (GTXT ("Incl. %s"), get_cmd ());
+           break;
+         case ATTRIBUTED:
+           name = dbe_sprintf (GTXT ("Attributed %s"), get_username ());
+           abbr = dbe_sprintf (GTXT ("Attr. %s"), get_cmd ());
+           break;
+         default:
+           name = dbe_sprintf (GTXT ("Unexpected derived %s metric subtype %d"),
+                               get_username (), st);
+           abbr = dbe_strdup (NTXT ("??"));
+           break;
+         }
+       break;
+      }
+
+    case OMP_MASTER_THREAD:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Master Thread Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Master Thread"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Master Thread Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Master Thread"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Master Thread Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Master Thread"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected Master Thread metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case CP_TOTAL:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Total Thread Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Total Thread"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Total Thread Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Total Thread"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Total Thread Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Total Thread"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected TOTAL metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case SYNC_WAIT_COUNT:
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Sync Wait Count"));
+         abbr = dbe_strdup (GTXT ("Excl. Sync Wait Count"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Sync Wait Count"));
+         abbr = dbe_strdup (GTXT ("Incl. Sync Wait Count"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Sync Wait Count"));
+         abbr = dbe_strdup (GTXT ("Attr. Sync Wait Count"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected LWCNT metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case CP_TOTAL_CPU:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Total CPU Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Total CPU"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Total CPU Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Total CPU"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Total CPU Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Total CPU"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected TOTAL_CPU metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case CP_LMS_TRAP:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Trap CPU Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Trap CPU"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Trap CPU Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Trap CPU"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Trap CPU Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Trap CPU"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected CP_LMS_TRAP metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case CP_LMS_KFAULT:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Kernel Page Fault Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Kernel Page Fault"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Kernel Page Fault Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Kernel Page Fault"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Kernel Page Fault Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Kernel Page Fault"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected CP_LMS_KFAULT metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case CP_LMS_SLEEP:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Sleep Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Sleep"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Sleep Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Sleep"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Sleep Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Sleep"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected CP_LMS_SLEEP metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case CP_LMS_STOPPED:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Stopped Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Stopped"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Stopped Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Stopped"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Stopped Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Stopped"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected CP_LMS_STOPPED metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case HEAP_ALLOC_BYTES:
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Bytes Allocated"));
+         abbr = dbe_strdup (GTXT ("Excl. Bytes Allocated"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Bytes Allocated"));
+         abbr = dbe_strdup (GTXT ("Incl. Bytes Allocated"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Bytes Allocated"));
+         abbr = dbe_strdup (GTXT ("Attr. Bytes Allocated"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected BYTES_MALLOCD metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case HEAP_ALLOC_CNT:
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Allocations"));
+         abbr = dbe_strdup (GTXT ("Excl. Allocations"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Allocations"));
+         abbr = dbe_strdup (GTXT ("Incl. Allocations"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Allocations"));
+         abbr = dbe_strdup (GTXT ("Attr. Allocations"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected MALLOCS metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case HEAP_LEAK_BYTES:
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Bytes Leaked"));
+         abbr = dbe_strdup (GTXT ("Excl. Bytes Leaked"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Bytes Leaked"));
+         abbr = dbe_strdup (GTXT ("Incl. Bytes Leaked"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Bytes Leaked"));
+         abbr = dbe_strdup (GTXT ("Attr. Bytes Leaked"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected BYTES_LEAKED metric subtype %d"),
+                             st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case HEAP_LEAK_CNT:
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Leaks"));
+         abbr = dbe_strdup (GTXT ("Excl. Leaks"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Leaks"));
+         abbr = dbe_strdup (GTXT ("Incl. Leaks"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Leaks"));
+         abbr = dbe_strdup (GTXT ("Attr. Leaks"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected LEAKS metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case IO_READ_BYTES:
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Read Bytes"));
+         abbr = dbe_strdup (GTXT ("Excl. Read Bytes"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Read Bytes"));
+         abbr = dbe_strdup (GTXT ("Incl. Read Bytes"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Read Bytes"));
+         abbr = dbe_strdup (GTXT ("Attr. Read Bytes"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected READ_BYTES metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case IO_WRITE_BYTES:
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Write Bytes"));
+         abbr = dbe_strdup (GTXT ("Excl. Write Bytes"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Write Bytes"));
+         abbr = dbe_strdup (GTXT ("Incl. Write Bytes"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Write Bytes"));
+         abbr = dbe_strdup (GTXT ("Attr. Write Bytes"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected WRITE_BYTES metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case IO_READ_CNT:
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Read Count"));
+         abbr = dbe_strdup (GTXT ("Excl. Read Count"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Read Count"));
+         abbr = dbe_strdup (GTXT ("Incl. Read Count"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Read Count"));
+         abbr = dbe_strdup (GTXT ("Attr. Read Count"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected READCNT metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case IO_WRITE_CNT:
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Write Count"));
+         abbr = dbe_strdup (GTXT ("Excl. Write Count"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Write Count"));
+         abbr = dbe_strdup (GTXT ("Incl. Write Count"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Write Count"));
+         abbr = dbe_strdup (GTXT ("Attr. Write Count"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected WRITECNT metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case IO_OTHER_CNT:
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Other I/O Count"));
+         abbr = dbe_strdup (GTXT ("Excl. Other I/O Count"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Other I/O Count"));
+         abbr = dbe_strdup (GTXT ("Incl. Other I/O Count"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Other I/O Count"));
+         abbr = dbe_strdup (GTXT ("Attr. Other I/O Count"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OTHERIOCNT metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case IO_ERROR_CNT:
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive I/O Error Count"));
+         abbr = dbe_strdup (GTXT ("Excl. I/O Error Count"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive I/O Error Count"));
+         abbr = dbe_strdup (GTXT ("Incl. I/O Error Count"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed I/O Error Count"));
+         abbr = dbe_strdup (GTXT ("Attr. I/O Error Count"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected IOERRORCNT metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case IO_READ_TIME:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Read Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Read Time"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Read Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Read Time"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Read Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Read Time"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected READ_TIME metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case IO_WRITE_TIME:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Write Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Write Time"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Write Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Write Time"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Write Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Write Time"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected WRITE_TIME metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case IO_OTHER_TIME:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Other I/O Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Other I/O Time"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Other I/O Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Other I/O Time"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Other I/O Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Other I/O Time"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OTHERIO_TIME metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case IO_ERROR_TIME:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive I/O Error Time"));
+         abbr = dbe_strdup (GTXT ("Excl. I/O Error Time"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive I/O Error Time"));
+         abbr = dbe_strdup (GTXT ("Incl. I/O Error Time"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed I/O Error Time"));
+         abbr = dbe_strdup (GTXT ("Attr. I/O Error Time"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected IOERROR_TIME metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+
+    case SIZES:
+      name = dbe_strdup (GTXT ("Size"));
+      abbr = dbe_strdup (GTXT ("Size"));
+      abbr_unit = dbe_strdup (GTXT ("bytes"));
+      break;
+
+    case ADDRESS:
+      name = dbe_strdup (GTXT ("PC Address"));
+      abbr = dbe_strdup (GTXT ("PC Addr."));
+      break;
+
+    case ONAME:
+      name = dbe_strdup (GTXT ("Name"));
+      abbr = dbe_strdup (GTXT ("Name"));
+      break;
+
+    case OMP_NONE:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Non-OpenMP Time"));
+         abbr = dbe_strdup (GTXT ("Excl. Non-OMP"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Non-OpenMP Time"));
+         abbr = dbe_strdup (GTXT ("Incl. Non-OMP"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Non-OpenMP Time"));
+         abbr = dbe_strdup (GTXT ("Attr. Non-OMP"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected Non-OpenMP metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case OMP_OVHD:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive OpenMP Overhead Time"));
+         abbr = dbe_strdup (GTXT ("Excl. OMP ovhd."));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive OpenMP Overhead Time"));
+         abbr = dbe_strdup (GTXT ("Incl. OMP ovhd."));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed OpenMP Overhead Time"));
+         abbr = dbe_strdup (GTXT ("Attr. OMP ovhd."));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OpenMP Overhead metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case OMP_WORK:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive OpenMP Work Time"));
+         abbr = dbe_strdup (GTXT ("Excl. OMP Work"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive OpenMP Work Time"));
+         abbr = dbe_strdup (GTXT ("Incl. OMP Work"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed OpenMP Work Time"));
+         abbr = dbe_strdup (GTXT ("Attr. OMP Work"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OpenMP Work metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case OMP_IBAR:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive OpenMP Implicit Barrier Time"));
+         abbr = dbe_strdup (GTXT ("Excl. OMP i-barr."));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive OpenMP Implicit Barrier Time"));
+         abbr = dbe_strdup (GTXT ("Incl. OMP i-barr."));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed OpenMP Implicit Barrier Time"));
+         abbr = dbe_strdup (GTXT ("Attr. OMP i-barr."));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OpenMP Implicit Barrier metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case OMP_EBAR:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive OpenMP Explicit Barrier Time"));
+         abbr = dbe_strdup (GTXT ("Excl. OMP e-barr."));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive OpenMP Explicit Barrier Time"));
+         abbr = dbe_strdup (GTXT ("Incl. OMP e-barr."));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed OpenMP Explicit Barrier Time"));
+         abbr = dbe_strdup (GTXT ("Attr. OMP e-barr."));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OpenMP Explicit Barrier metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case OMP_WAIT:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive OpenMP Wait Time"));
+         abbr = dbe_strdup (GTXT ("Excl. OMP Wait"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive OpenMP Wait Time"));
+         abbr = dbe_strdup (GTXT ("Incl. OMP Wait"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed OpenMP Wait Time"));
+         abbr = dbe_strdup (GTXT ("Attr. OMP Wait"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OpenMP Wait metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case OMP_SERL:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive OpenMP Serial Time"));
+         abbr = dbe_strdup (GTXT ("Excl. OMP serl"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive OpenMP Serial Time"));
+         abbr = dbe_strdup (GTXT ("Incl. OMP serl"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed OpenMP Serial Time"));
+         abbr = dbe_strdup (GTXT ("Attr. OMP serl"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OpenMP Slave Idle metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case OMP_RDUC:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive OpenMP Reduction Time"));
+         abbr = dbe_strdup (GTXT ("Excl. OMP rduc"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive OpenMP Reduction Time"));
+         abbr = dbe_strdup (GTXT ("Incl. OMP rduc"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed OpenMP Reduction Time"));
+         abbr = dbe_strdup (GTXT ("Attr. OMP rduc"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OpenMP Reduction metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case OMP_LKWT:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive OpenMP Lock Wait Time"));
+         abbr = dbe_strdup (GTXT ("Excl. OMP lkwt"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive OpenMP Lock Wait Time"));
+         abbr = dbe_strdup (GTXT ("Incl. OMP lkwt"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed OpenMP Lock Wait Time"));
+         abbr = dbe_strdup (GTXT ("Attr. OMP lkwt"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OpenMP Lock Wait metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case OMP_CTWT:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive OpenMP Critical Section Wait Time"));
+         abbr = dbe_strdup (GTXT ("Excl. OMP ctwt"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive OpenMP Critical Section Wait Time"));
+         abbr = dbe_strdup (GTXT ("Incl. OMP ctwt"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed OpenMP Critical Section Wait Time"));
+         abbr = dbe_strdup (GTXT ("Attr. OMP ctwt"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OpenMP Critical Section Wait metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case OMP_ODWT:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive OpenMP Ordered Section Wait Time"));
+         abbr = dbe_strdup (GTXT ("Excl. OMP odwt"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive OpenMP Ordered Section Wait Time"));
+         abbr = dbe_strdup (GTXT ("Incl. OMP odwt"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed OpenMP Ordered Section Wait Time"));
+         abbr = dbe_strdup (GTXT ("Attr. OMP odwt"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OpenMP Ordered Section Wait metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case OMP_MSTR:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive OpenMP Master Serial Time"));
+         abbr = dbe_strdup (GTXT ("Excl. OMP ser."));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive OpenMP Master Serial Time"));
+         abbr = dbe_strdup (GTXT ("Incl. OMP ser."));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed OpenMP Master Serial Time"));
+         abbr = dbe_strdup (GTXT ("Attr. OMP ser."));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OpenMP Master Serial metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case OMP_SNGL:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive OpenMP Single Region Time"));
+         abbr = dbe_strdup (GTXT ("Excl. OMP sngl"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive OpenMP Single Region Time"));
+         abbr = dbe_strdup (GTXT ("Incl. OMP sngl"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed OpenMP Single Region Time"));
+         abbr = dbe_strdup (GTXT ("Attr. OMP sngl"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OpenMP Single Region metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case OMP_ORDD:
+      abbr_unit = dbe_strdup (GTXT ("sec."));
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive OpenMP Ordered Region Time"));
+         abbr = dbe_strdup (GTXT ("Excl. OMP ordd"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive OpenMP Ordered Region Time"));
+         abbr = dbe_strdup (GTXT ("Incl. OMP ordd"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed OpenMP Ordered Region Time"));
+         abbr = dbe_strdup (GTXT ("Attr. OMP ordd"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected OpenMP Ordered Region metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case RACCESS:
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Race Accesses"));
+         abbr = dbe_strdup (GTXT ("Excl. Race Accesses"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Race Accesses"));
+         abbr = dbe_strdup (GTXT ("Incl. Race Accesses"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Race Accesses"));
+         abbr = dbe_strdup (GTXT ("Attr. Race Accesses"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected Race Access metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    case DEADLOCKS:
+      if (st == EXCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Exclusive Deadlocks"));
+         abbr = dbe_strdup (GTXT ("Excl. Deadlocks"));
+       }
+      else if (st == INCLUSIVE)
+       {
+         name = dbe_strdup (GTXT ("Inclusive Deadlocks"));
+         abbr = dbe_strdup (GTXT ("Incl. Deadlocks"));
+       }
+      else if (st == ATTRIBUTED)
+       {
+         name = dbe_strdup (GTXT ("Attributed Deadlocks"));
+         abbr = dbe_strdup (GTXT ("Attr. Deadlocks"));
+       }
+      else
+       {
+         name = dbe_sprintf (GTXT ("Unexpected Deadlocks metric subtype %d"), st);
+         abbr = dbe_strdup (NTXT ("??"));
+       }
+      break;
+    default:
+      abort ();
+    }
+} //Metric::set_subtype
+
+static bool
+is_width_ok (int lines, size_t width, size_t *tlen, int last)
+{
+  size_t len = 0;
+  for (int i = 0; i <= last; i++)
+    {
+      if (len != 0)
+       len++;
+      if (len + tlen[i] > width)
+       {
+         if (--lines == 0)
+           return false;
+         len = 0;
+       }
+      len += tlen[i];
+    }
+  return true;
+}
+
+void
+Metric::legend_width (HistMetric *hitem, int gap)
+{
+  size_t tlen[MAX_LEN];
+  char *tok[MAX_LEN], buf[MAX_LEN], unit[MAX_LEN];
+  hitem->width = hitem->maxtime_width;
+  if (hitem->maxvalue_width > 0)
+    {
+      if (hitem->width > 0)
+       hitem->width++;
+      hitem->width += hitem->maxvalue_width;
+    }
+  if (is_pvisible ())
+    {
+      if (hitem->width > 0)
+       {
+         hitem->width++;
+       }
+      hitem->width += 6; // adjust to change format from xx.yy%
+    }
+  snprintf (buf, sizeof (buf), "%s", get_abbr ());
+  size_t max_len = hitem->width;
+  if (legend)
+    {
+      size_t legend_len = strlen (legend);
+      if (max_len < legend_len)
+       max_len = legend_len;
+    }
+  tok[0] = buf;
+  int last = 0;
+  for (int i = 0;; i++)
+    {
+      if (buf[i] == ' ')
+       {
+         buf[i] = '\0';
+         while (buf[i + 1] == ' ')
+           i++;
+         tlen[last] = strlen (tok[last]);
+         if (max_len < tlen[last])
+           max_len = tlen[last];
+         last++;
+         tok[last] = buf + i + 1;
+       }
+      else if (buf[i] == '\0')
+       {
+         tlen[last] = strlen (tok[last]);
+         if (max_len < tlen[last])
+           max_len = tlen[last];
+         if (tlen[last] == 0 && last > 0)
+           last--;
+         break;
+       }
+    }
+
+  *unit = '\0'; // get the extra unit tokens
+  int max_lines = 3;
+  if (is_tvisible ())
+    {
+      char *s = GTXT ("sec.");
+      if ((get_visbits () & VAL_DELTA) != 0)
+       s = GTXT ("delta");
+      else if ((get_visbits () & VAL_RATIO) != 0)
+       s = GTXT ("ratio");
+      long len = strlen (s);
+      if (hitem->maxtime_width < len)
+       {
+         hitem->width += len - hitem->maxtime_width;
+         hitem->maxtime_width = len;
+       }
+      snprintf (unit, sizeof (unit), "%*s", (int) hitem->maxtime_width, s);
+    }
+  if (is_visible ())
+    {
+      char *s = NTXT ("");
+      if (!is_tvisible ())
+       {
+         if ((get_visbits () & VAL_DELTA) != 0)
+           s = GTXT ("delta");
+         else if ((get_visbits () & VAL_RATIO) != 0)
+           s = GTXT ("ratio");
+         else if ((get_value_styles () & VAL_TIMEVAL) != 0 && !is_time_val ())
+           s = GTXT ("sec.");
+       }
+      long len = strlen (s);
+      if (hitem->maxvalue_width < len)
+       {
+         hitem->width += len - hitem->maxvalue_width;
+         hitem->maxvalue_width = len;
+       }
+      if (*unit)
+       {
+         max_lines = 2;
+         len = strlen (unit);
+         snprintf (unit + len, sizeof (unit) - len, " %*s",
+                   (int) hitem->maxvalue_width, s);
+       }
+      else
+       snprintf (unit, sizeof (unit), "%*s", (int) hitem->maxvalue_width, s);
+    }
+  if (is_pvisible ())
+    {
+      max_lines = 2;
+      if (*unit)
+       {
+         size_t len = strlen (unit);
+         snprintf (unit + len, sizeof (unit) - len, GTXT ("      %%"));
+       }
+      else
+       snprintf (unit, sizeof (unit), GTXT ("     %%"));
+    }
+  for (size_t i = strlen (unit); i > 0;)
+    { // remove trailing spaces
+      i--;
+      if (unit[i] != ' ')
+       break;
+      unit[i] = 0;
+    }
+
+  if (*unit)
+    {
+      last++;
+      tlen[last] = strlen (unit);
+      tok[last] = unit;
+      if (max_len < tlen[last])
+       max_len = tlen[last];
+      if (max_lines == 3 && *unit == ' ')
+       {
+         char *str = unit;
+         while (*str == ' ')
+           str++;
+         tlen[last] = strlen (str);
+         tok[last] = str;
+       }
+    }
+
+  int last1 = max_lines == 3 ? last : last - 1;
+  while (!is_width_ok (max_lines, max_len, tlen, last1))
+    max_len++;
+  hitem->width = max_len + gap;
+
+  char *legends[3];
+  legends[0] = hitem->legend1;
+  legends[1] = hitem->legend2;
+  legends[2] = hitem->legend3;
+  for (int i = 0, ind = 0; i < 3; i++)
+    {
+      char *str = legends[i];
+      *str = 0;
+      for (; ind <= last; ind++)
+       {
+         if (*unit && (ind == last))
+           {
+             // Try to put 'unit' in 'legend3'
+             if (i != 2)
+               {
+                 tok[last] = unit; // restore a formated 'unit'
+                 break;
+               }
+           }
+         size_t len = strlen (str);
+         if (len != 0)
+           {
+             if (len + 1 + tlen[ind] > max_len)
+               break;
+             snprintf (str + len, MAX_LEN - len, NTXT (" %s"), tok[ind]);
+           }
+         else
+           {
+             if (len + tlen[ind] > max_len)
+               break;
+             snprintf (str + len, MAX_LEN - len, NTXT ("%s"), tok[ind]);
+           }
+       }
+    }
+}
+
+int
+Metric::get_real_visbits ()
+{
+  int v = visbits;
+  if (!is_time_val () && (visbits & (VAL_TIMEVAL | VAL_VALUE)) != 0)
+    {
+      v &= ~(VAL_TIMEVAL | VAL_VALUE);
+      v |= (get_value_styles () & (VAL_TIMEVAL | VAL_VALUE));
+    }
+  return v;
+}
+
+char *
+Metric::get_vis_string (int vis)
+{
+  char *vis_str;
+  if (subtype == STATIC)
+    vis_str = NTXT ("");
+  else
+    {
+      int v;
+      if (is_time_val ())
+       v = vis & (VAL_TIMEVAL | VAL_VALUE | VAL_PERCENT);
+      else
+       {
+         v = vis & VAL_PERCENT;
+         if ((vis & (VAL_TIMEVAL | VAL_VALUE)) != 0)
+           v |= (get_value_styles () & (VAL_TIMEVAL | VAL_VALUE));
+       }
+      switch (v)
+       {
+       case VAL_TIMEVAL:
+         vis_str = NTXT (".");
+         break;
+       case VAL_VALUE:
+         vis_str = NTXT ("+");
+         break;
+       case VAL_TIMEVAL | VAL_VALUE:
+         vis_str = NTXT (".+");
+         break;
+       case VAL_PERCENT:
+         vis_str = NTXT ("%");
+         break;
+       case VAL_TIMEVAL | VAL_PERCENT:
+         vis_str = NTXT (".%");
+         break;
+       case VAL_VALUE | VAL_PERCENT:
+         vis_str = NTXT ("+%");
+         break;
+       case VAL_TIMEVAL | VAL_VALUE | VAL_PERCENT:
+         vis_str = NTXT (".+%");
+         break;
+       default:
+         vis_str = NTXT ("!");
+         break;
+       }
+    }
+  return vis_str;
+}
+
+char *
+Metric::get_vis_str ()
+{
+  char *vis_str = NULL;
+  if (visbits == -1)
+    {
+      // unitialized, return all possible with a trailing -
+      if (subtype == STATIC)
+       vis_str = NTXT (".-");
+      else if (is_time_val ())
+       vis_str = NTXT (".+%-");
+      else
+       vis_str = NTXT (".%-");
+    }
+  else
+    vis_str = get_vis_string (get_real_visbits ());
+  return vis_str;
+}
+
+void
+Metric::set_dmetrics_visbits (int dmetrics_visbits)
+{
+  visbits = VAL_NA; // clear global state
+
+  // process the "show" bits
+  int _visbits = dmetrics_visbits & ~VAL_HIDE_ALL;
+  assert (_visbits != -1);
+  if (_visbits == 0)
+    return; // done.  (Ignore VAL_HIDE_ALL since there's nothing to hide.)
+  if (get_subtype () == STATIC)
+    // percent, time value not applicable
+    visbits = VAL_VALUE;
+  else
+    {
+      // now or in the bits, but manage . and + according to the is_time_val setting
+      if (is_time_val () == 0)
+       {
+         if ((_visbits & VAL_VALUE) || (_visbits & VAL_TIMEVAL))
+           visbits |= VAL_VALUE;
+       }
+      else
+       visbits |= (_visbits & (VAL_VALUE | VAL_TIMEVAL));
+      visbits |= (_visbits & (VAL_PERCENT | VAL_RATIO | VAL_DELTA));
+    }
+  // process the "hide" bit
+  if (dmetrics_visbits & VAL_HIDE_ALL)
+    visbits |= VAL_HIDE_ALL;
+}
+
+void
+Metric::set_vvisible (bool set)
+{
+  if (set)
+    {
+      visbits |= VAL_VALUE;
+      visbits &= ~VAL_HIDE_ALL;
+    }
+  else
+    visbits &= ~VAL_VALUE;
+}
+
+void
+Metric::set_tvisible (bool set)
+{
+  if (set)
+    {
+      visbits |= VAL_TIMEVAL;
+      visbits &= ~VAL_HIDE_ALL;
+    }
+  else
+    visbits &= ~VAL_TIMEVAL;
+}
+
+void
+Metric::set_pvisible (bool set)
+{
+  if (set)
+    {
+      visbits |= VAL_PERCENT;
+      visbits &= ~VAL_HIDE_ALL;
+    }
+  else
+    visbits &= ~VAL_PERCENT;
+}
+
+char *
+Metric::get_mcmd (bool allPossible)
+{
+  char *sc = NTXT (""); // subtype == STATIC
+  char *hide;
+  char *vis = get_vis_string (allPossible ? get_value_styles ()
+                             : get_real_visbits ());
+  if (subtype == INCLUSIVE)
+    sc = NTXT ("i");
+  else if (subtype == EXCLUSIVE)
+    sc = NTXT ("e");
+  else if (subtype == ATTRIBUTED)
+    sc = NTXT ("a");
+  else if (subtype == DATASPACE)
+    sc = NTXT ("d");
+  if (allPossible)
+    hide = NTXT ("");
+  else if (visbits == VAL_NA || (visbits & VAL_HIDE_ALL) != 0)
+    hide = NTXT ("!");
+  else
+    hide = NTXT ("");
+
+  char *mcmd = get_cmd ();
+  return dbe_sprintf (GTXT ("%s%s%s%s"), sc, hide, vis, mcmd);
+}
+
+char *
+Metric::dump ()
+{
+  int len = 4;
+  BaseMetric *bm = (BaseMetric *) this;
+  char *s = bm->dump ();
+  char *msg = dbe_sprintf ("%s\n%*c subtype=%d time_val=%d vis=%d tvis=%d"
+                          " pvis=%d\n%*c abbr='%s' cmd='%s' name='%s'\n",
+                          STR (s), len, ' ', get_subtype (), is_time_val (),
+                          is_visible (), is_tvisible (), is_pvisible (),
+                          len, ' ', STR (get_abbr ()), STR (get_cmd ()),
+                          STR (get_name ()));
+  free (s);
+  return msg;
+}
+
diff --git a/gprofng/src/Metric.h b/gprofng/src/Metric.h
new file mode 100644 (file)
index 0000000..a2b3778
--- /dev/null
@@ -0,0 +1,188 @@
+/* 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 _METRIC_H
+#define _METRIC_H
+
+#include "dbe_structs.h"
+#include "vec.h"
+#include "enums.h"
+#include "BaseMetric.h"
+
+#define MAX_LEN  1024
+
+class Expression;
+
+// The metric class defines the metrics that are available. The metrics are
+// registered when the experiment's log file is read.
+class Metric : public BaseMetric
+{
+public:
+
+  typedef struct HistMetricS
+  {
+    int width;
+    int maxvalue_width;
+    int maxtime_width;
+    char legend1[MAX_LEN];
+    char legend2[MAX_LEN];
+    char legend3[MAX_LEN];
+    int indFirstExp;        // only for -compare=[delta|ratio]
+    int indTimeVal;         // only for HWC time-converted metrics
+    void update_max (struct HistMetricS *hm);
+    void init ();
+  } HistMetric;
+
+  Metric (const Metric& item);      // copy constructor
+  Metric (BaseMetric *item, SubType st);
+  Metric (char *_name, SubType st); // for derived metrics
+  virtual ~Metric ();
+
+  char *get_mcmd (bool);        // e.user, a.total, etc. NOTI18N
+  int get_real_visbits ();      // methods for managing visibility
+  ValueTag get_vtype2 ();       // takes comparison visbits into account
+  void set_dmetrics_visbits (int _dmetrics_visbits);
+
+  // fetch various fields from a Metric
+  SubType
+  get_subtype ()
+  {
+    return subtype;
+  }
+
+  char *
+  get_name ()
+  {
+    return name;
+  }
+
+  char *
+  get_abbr ()
+  {
+    return abbr;
+  }
+
+  char *
+  get_abbr_unit ()
+  {
+    return abbr_unit;
+  }
+
+  BaseMetric *
+  get_base_metric ()
+  {
+    return baseMetric;
+  }
+
+  int
+  get_visbits ()
+  {
+    return visbits;
+  }
+
+  void
+  set_raw_visbits (int _visbits)
+  {
+    visbits = _visbits;
+  }
+
+  void
+  clear_all_visbits ()
+  {
+    visbits = VAL_NA;
+  }
+
+  void
+  enable_all_visbits ()
+  {
+    visbits = get_value_styles ();
+  }
+
+
+#define VAL_IS_HIDDEN(n) ((n) == -1 || (n) == VAL_NA || ((n) & VAL_HIDE_ALL) != 0)
+
+  bool
+  is_any_visible ()
+  {
+    return !VAL_IS_HIDDEN (visbits)
+           && (visbits & (VAL_VALUE | VAL_TIMEVAL | VAL_PERCENT));
+  }
+
+  bool
+  is_value_visible ()
+  {
+    return (visbits & VAL_VALUE) != 0
+           || (!is_time_val () && (visbits & VAL_TIMEVAL) != 0);
+  }
+
+  bool
+  is_time_visible ()
+  {
+    return is_time_val () && (visbits & VAL_TIMEVAL) != 0;
+  }
+
+  bool
+  is_visible ()
+  {
+    return !VAL_IS_HIDDEN (visbits) && is_value_visible ();
+  }
+
+  bool
+  is_tvisible ()
+  {
+    return !VAL_IS_HIDDEN (visbits) && is_time_visible ();
+  }
+
+  bool
+  is_pvisible ()
+  {
+    return !VAL_IS_HIDDEN (visbits) && (visbits & VAL_PERCENT) != 0;
+  }
+
+  bool
+  is_time_val ()
+  {
+    int v = VAL_TIMEVAL | VAL_VALUE;
+    return (get_value_styles () & v) == v;
+  }
+
+  // per-bit handling of visbits
+  // Note: Forces VAL_HIDE_ALL to zero. Use only on temporary Metric objects.
+  void set_vvisible (bool set);
+  void set_tvisible (bool set);
+  void set_pvisible (bool set);
+
+  void set_subtype (SubType st);
+  void legend_width (HistMetric *hitem, int gap);
+  char *get_vis_str ();
+  char *get_vis_string (int vis);
+  char *dump ();
+
+
+private:
+  BaseMetric *baseMetric;
+  SubType subtype; // specific variant for this Metric
+  char *name;
+  char *abbr;
+  char *abbr_unit;
+  int visbits; // ValueType, e.g. VAL_VALUE|VAL_TIMEVAL
+};
+
+#endif  /* _METRIC_H */
diff --git a/gprofng/src/MetricList.cc b/gprofng/src/MetricList.cc
new file mode 100644 (file)
index 0000000..7596524
--- /dev/null
@@ -0,0 +1,1075 @@
+/* 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 "util.h"
+#include "Command.h"
+#include "DbeSession.h"
+#include "MetricList.h"
+#include "StringBuilder.h"
+
+//  Build a metric reference list
+MetricList::MetricList (Vector<BaseMetric*> *base_metrics, MetricType _mtype)
+{
+  mtype = _mtype;
+  items = new Vector<Metric*>;
+  sort_ref_index = 0;
+  sort_reverse = false;
+
+  Metric *mitem;
+  // loop over the base_metrics, and add in all the appropriate subtypes
+  for (long i = 0, sz = base_metrics ? base_metrics->size () : 0; i < sz; i++)
+    {
+      BaseMetric *mtr = base_metrics->get (i);
+      if (mtr->is_internal ())
+       continue;
+      switch (mtype)
+       {
+       case MET_DATA:
+         if ((mtr->get_flavors () & BaseMetric::DATASPACE) != 0)
+           {
+             mitem = new Metric (mtr, BaseMetric::DATASPACE);
+             items->append (mitem);
+           }
+         break;
+
+       case MET_INDX:
+         {
+           if ((mtr->get_flavors () & BaseMetric::INCLUSIVE) != 0
+               || (mtr->get_flavors () & BaseMetric::EXCLUSIVE) != 0)
+             {
+               int index2;
+               Metric *item2 = NULL;
+               bool found = false;
+               Vec_loop (Metric*, items, index2, item2)
+               {
+                 if (item2->get_subtype () == BaseMetric::EXCLUSIVE
+                     && dbe_strcmp (item2->get_cmd (), mtr->get_cmd ()) == 0)
+                   {
+                     found = true;
+                     break;
+                   }
+               }
+               if (found == false)
+                 {
+                   mitem = new Metric (mtr, BaseMetric::EXCLUSIVE);
+                   items->append (mitem);
+                 }
+             }
+         }
+         break;
+
+       case MET_CALL:
+       case MET_CALL_AGR:
+         if ((mtr->get_flavors () & BaseMetric::ATTRIBUTED) != 0)
+           {
+             mitem = new Metric (mtr, BaseMetric::ATTRIBUTED);
+             items->append (mitem);
+           }
+         // now fall through to add exclusive and inclusive
+
+       case MET_NORMAL:
+       case MET_COMMON:
+         if (mtr->get_flavors () & BaseMetric::EXCLUSIVE)
+           {
+             mitem = new Metric (mtr, BaseMetric::EXCLUSIVE);
+             items->append (mitem);
+           }
+         if (mtr->get_flavors () & BaseMetric::INCLUSIVE)
+           {
+             mitem = new Metric (mtr, BaseMetric::INCLUSIVE);
+             items->append (mitem);
+           }
+         break;
+       case MET_SRCDIS:
+         if (mtr->get_flavors () & BaseMetric::INCLUSIVE)
+           {
+             mitem = new Metric (mtr, BaseMetric::INCLUSIVE);
+             items->append (mitem);
+           }
+         break;
+       case MET_IO:
+         {
+           if (mtr->get_packet_type () == DATA_IOTRACE
+               && ((mtr->get_flavors () & BaseMetric::INCLUSIVE) != 0
+                   || (mtr->get_flavors () & BaseMetric::EXCLUSIVE) != 0))
+             {
+               int index2;
+               Metric *item2 = NULL;
+               bool found = false;
+               Vec_loop (Metric*, items, index2, item2)
+               {
+                 if (item2->get_subtype () == BaseMetric::EXCLUSIVE
+                     && dbe_strcmp (item2->get_cmd (), mtr->get_cmd ()) == 0)
+                   {
+                     found = true;
+                     break;
+                   }
+               }
+               if (found == false)
+                 {
+                   mitem = new Metric (mtr, BaseMetric::EXCLUSIVE);
+                   items->append (mitem);
+                 }
+             }
+         }
+         break;
+       case MET_HEAP:
+         {
+           if (mtr->get_packet_type () == DATA_HEAP
+               && ((mtr->get_flavors () & BaseMetric::INCLUSIVE) != 0
+                   || (mtr->get_flavors () & BaseMetric::EXCLUSIVE) != 0))
+             {
+               int index2;
+               Metric *item2 = NULL;
+               bool found = false;
+               Vec_loop (Metric*, items, index2, item2)
+               {
+                 if ((item2->get_subtype () == BaseMetric::EXCLUSIVE) &&
+                     (dbe_strcmp (item2->get_cmd (), mtr->get_cmd ()) == 0))
+                   {
+                     found = true;
+                     break;
+                   }
+               }
+               if (found == false)
+                 {
+                   mitem = new Metric (mtr, BaseMetric::EXCLUSIVE);
+                   items->append (mitem);
+                 }
+             }
+         }
+         break;
+       }
+
+      // add the static
+      if (mtr->get_flavors () & BaseMetric::STATIC)
+       {
+         switch (mtype)
+           {
+           case MET_NORMAL:
+           case MET_COMMON:
+           case MET_CALL:
+           case MET_CALL_AGR:
+           case MET_SRCDIS:
+             mitem = new Metric (mtr, BaseMetric::STATIC);
+             items->append (mitem);
+             break;
+           default:
+             if (mtr->get_type () == BaseMetric::ONAME)
+               {
+                 mitem = new Metric (mtr, BaseMetric::STATIC);
+                 items->append (mitem);
+               }
+             break;
+           }
+       }
+    }
+  // set all metrics visible
+  for (long i = 0, sz = items ? items->size () : 0; i < sz; i++)
+    items->get (i)->enable_all_visbits ();
+}
+
+// Constructor for an empty list -- items will be added one at a time
+MetricList::MetricList (MetricType _mtype)
+{
+  mtype = _mtype;
+  items = new Vector<Metric*>;
+  sort_ref_index = 0;
+  sort_reverse = false;
+}
+
+MetricList::~MetricList ()
+{
+  Destroy (items);
+}
+
+// Duplicate a metric list
+MetricList::MetricList (MetricList *old)
+{
+  mtype = old->mtype;
+
+  // get an empty vector
+  items = new Vector<Metric*>;
+  Metric *item;
+  Metric *nitem;
+  int index;
+  sort_ref_index = old->get_sort_ref_index ();
+  sort_reverse = old->get_sort_rev ();
+  Vec_loop (Metric*, old->items, index, item)
+  {
+    nitem = new Metric (*item);
+    items->append (nitem);
+  }
+}
+
+// set_metrics:
+//     Sets the particular metric list, according to the metric spec
+//      If fromRcFile, updates dbeSession->get_reg_metrics_tree() with new defaults.
+char *
+MetricList::set_metrics (const char *mspec, bool fromRcFile,
+                        DerivedMetrics * /* derived_metrics */)
+{
+  BaseMetric::SubType subtypes[10];
+  int nsubtypes;
+  int dmetrics_vis; // literal translation of metrics/dmetrics %.+
+  bool parseOK = false;
+  char *errbuf;
+  Vector<Metric*> *old_items = items;
+  items = new Vector<Metric*>;
+  Vector<BaseMetric*> *base_items = dbeSession->get_base_reg_metrics ();
+
+  // and copy the input specification
+  char *buf = dbe_strdup (mspec);
+
+  // append metric items from parsing the string
+  for (char *mcmd = strtok (buf, NTXT (":")); mcmd != NULL;
+         mcmd = strtok (NULL, NTXT (":")))
+    {
+      // parse the single metric_spec, based on the type of list being constructed, into:
+      //       a vector of SubTypes (any of [iead] or STATIC)
+      //       a integer mask for the visibility bits
+      //       and the string name of the base metric
+      //           it might be "all", "any", or "hwc" or it should match a metric in the list
+      //           it might also be "bit", meaning any bit-computed metric
+      char *mname = parse_metric_spec (mcmd, subtypes, &nsubtypes,
+                                      &dmetrics_vis, &parseOK);
+      if (!parseOK)
+       {
+         // error parsing the metric specification
+         // not from an rc file, it's an error
+         if (!fromRcFile)
+           {
+             delete base_items;
+             items->destroy ();
+             delete items;
+             items = old_items;
+             free (buf);
+             return mname;
+           }
+         continue;
+       }
+
+      // loop over subtypes requested
+      // set the visibility of and sort order according to the vis bits,
+      //       and the order of encounter in the processing
+      int ret = add_matching_dmetrics (base_items, mname, subtypes, nsubtypes,
+                                      dmetrics_vis, fromRcFile);
+      if (ret != 0 && !fromRcFile)
+       {
+         if (ret == 1)
+           errbuf = dbe_sprintf (GTXT ("No data recorded to support metric specification: %s\n"),
+                                 mcmd);
+         else
+           errbuf = dbe_sprintf (GTXT ("Metric specification for `%s' has appeared before in %s"),
+                                   mcmd, mspec);
+         delete base_items;
+         items->destroy ();
+         delete items;
+         items = old_items;
+         free (buf);
+         return errbuf;
+       }
+    } // we've processed the entire spec
+
+  // update metric defaults
+  if (fromRcFile)
+    {
+      for (long i = 0, sz = items->size (); i < sz; i++)
+       {
+         Metric *m = items->get (i);
+         int visbits = m->get_visbits ();
+         BaseMetric::SubType subtype = m->get_subtype ();
+         BaseMetric *reg_bm = m->get_base_metric ();
+         reg_bm->set_default_visbits (subtype, visbits);
+         BaseMetricTreeNode *mtree = dbeSession->get_reg_metrics_tree ();
+         BaseMetricTreeNode *bmtnode = mtree->register_metric (m);
+         BaseMetric *tree_bm = bmtnode->get_BaseMetric ();
+         tree_bm->set_default_visbits (subtype, visbits);
+       }
+    }
+
+  // ensure that name is present, remove hidden metrics
+  nsubtypes = 1;
+  for (long i = items->size () - 1; i >= 0; i--)
+    {
+      Metric *m = items->fetch (i);
+      if (!m->is_any_visible ())
+       {
+         delete m;
+         items->remove (i);
+         continue;
+       }
+      if (m->get_type () == BaseMetric::ONAME)
+       nsubtypes = 0;
+    }
+
+  // did we get at least one valid match?
+  if (items->size () == 0 && !fromRcFile)
+    {
+      errbuf = dbe_sprintf (GTXT ("No valid metrics specified in `%s'\n"), mspec);
+      delete base_items;
+      items->destroy ();
+      delete items;
+      items = old_items;
+      free (buf);
+      return errbuf;
+    }
+
+  if (nsubtypes == 1)
+    {
+      subtypes[0] = BaseMetric::STATIC;
+      (void) add_matching_dmetrics (base_items, NTXT ("name"), subtypes, 1, VAL_VALUE, true);
+    }
+
+  // replace the old list of items, with the new set
+  if (old_items)
+    {
+      old_items->destroy ();
+      delete old_items;
+    }
+  set_fallback_sort ();
+  free (buf);
+  delete base_items;
+  return NULL;
+}
+
+void
+MetricList::set_fallback_sort ()
+{
+  // sort by first visible of the appropriate flavor
+  char *sortcmd = NULL;
+  switch (mtype)
+    {
+    case MET_NORMAL:
+    case MET_COMMON:
+      sortcmd = NTXT ("ei.any:name");
+      break;
+    case MET_SRCDIS:
+      sortcmd = NTXT ("i.any:name");
+      break;
+    case MET_CALL:
+    case MET_CALL_AGR:
+      sortcmd = NTXT ("a.any:name");
+      break;
+    case MET_DATA:
+      sortcmd = NTXT ("d.any:name");
+      break;
+    case MET_INDX:
+      sortcmd = NTXT ("e.any:name");
+      break;
+    case MET_IO:
+      sortcmd = NTXT ("e.any:name");
+      break;
+    case MET_HEAP:
+      sortcmd = NTXT ("e.any:name");
+      break;
+    }
+  if (NULL != sortcmd)
+    (void) set_sort (sortcmd, true);
+}
+
+void
+MetricList::set_metrics (MetricList *mlist)
+{
+  // verify that the type is appropriate for the call
+  if (mtype == MET_NORMAL || mtype == MET_COMMON
+      || (mlist->mtype != MET_NORMAL && mlist->mtype != MET_COMMON))
+    abort ();
+
+  Vector<Metric*> *mlist_items = mlist->get_items ();
+  items->destroy ();
+  items->reset ();
+
+  int sort_ind = mlist->get_sort_ref_index ();
+  for (int i = 0, mlist_sz = mlist_items->size (); i < mlist_sz; i++)
+    {
+      Metric *mtr = mlist_items->fetch (i);
+      if (!mtr->is_any_visible ())
+       continue;
+
+      //  Add a new Metric with probably a new sub_type to this->items:
+      //    for MET_CALL and MET_CALL_AGR the matching entry to an e. or i. is itself
+      //    for MET_DATA, the matching entry to an e. or i. is the d. metric
+      //    for MET_INDX, the matching entry to an e. or i. is the e. metric
+      //    for MET_IO, the matching entry to an e. or i. is the e. metric
+      //    for MET_HEAP, the matching entry to an e. or i. is the e. metric
+      //    Save static entries (SIZES and ADDRESS) only for MET_NORMAL, MET_CALL, MET_CALL_AGR, MET_SRCDIS
+      switch (mtr->get_type ())
+       {
+       case BaseMetric::SIZES:
+       case BaseMetric::ADDRESS:
+         switch (mtype)
+           {
+           case MET_NORMAL:
+           case MET_COMMON:
+           case MET_CALL:
+           case MET_CALL_AGR:
+           case MET_SRCDIS:
+             break;
+           default:
+             continue;
+           }
+         break;
+       default:
+         break;
+       }
+
+      BaseMetric::SubType st = mtr->get_subtype ();
+      if (st != BaseMetric::STATIC)
+       {
+         if (mtype == MET_CALL || mtype == MET_CALL_AGR)
+           {
+             if ((mtr->get_flavors () & BaseMetric::ATTRIBUTED) == 0)
+               continue;
+             st = BaseMetric::ATTRIBUTED;
+           }
+         else if (mtype == MET_DATA)
+           {
+             if ((mtr->get_flavors () & BaseMetric::DATASPACE) == 0)
+               continue;
+             st = BaseMetric::DATASPACE;
+           }
+         else if (mtype == MET_INDX)
+           {
+             if ((mtr->get_flavors () & BaseMetric::EXCLUSIVE) == 0)
+               continue;
+             st = BaseMetric::EXCLUSIVE;
+           }
+         else if (mtype == MET_IO)
+           {
+             if (mtr->get_packet_type () != DATA_IOTRACE ||
+                 (mtr->get_flavors () & BaseMetric::EXCLUSIVE) == 0)
+               continue;
+             st = BaseMetric::EXCLUSIVE;
+           }
+         else if (mtype == MET_HEAP)
+           {
+             if (mtr->get_packet_type () != DATA_HEAP ||
+                 (mtr->get_flavors () & BaseMetric::EXCLUSIVE) == 0)
+               continue;
+             st = BaseMetric::EXCLUSIVE;
+           }
+         else if (mtype == MET_SRCDIS)
+           {
+             if ((mtr->get_flavors () & BaseMetric::INCLUSIVE) == 0)
+               continue;
+             st = BaseMetric::INCLUSIVE;
+           }
+       }
+
+      bool found = false;
+      for (int i1 = 0, items_sz = items->size (); i1 < items_sz; i1++)
+       {
+         Metric *m1 = items->fetch (i1);
+         if (mtr->get_id () == m1->get_id () && st == m1->get_subtype ())
+           {
+             if (sort_ind == i)
+               sort_ind = i1;
+             found = true;
+             break;
+           }
+       }
+      if (found)
+       continue;
+      Metric *m = new Metric (*mtr);
+      m->set_subtype (st);
+      m->set_raw_visbits (mtr->get_visbits ());
+      if (sort_ind == i)
+       sort_ind = items->size ();
+      items->append (m);
+    }
+  if (sort_ind >= items->size ())
+    sort_ind = 0;
+  if (mtype == MET_IO)
+    sort_ind = 0;
+  if (mtype == MET_HEAP)
+    sort_ind = 0;
+  sort_ref_index = sort_ind;
+
+}
+
+
+// set_sort:
+//     Sets the sort for the metric list to the first metric
+//     in mspec that is present; if fromRcFile is false, then
+//     only one metric may be specified.  The requested sort
+//     metric must be visible, or it won't  be in the metric list
+
+char *
+MetricList::set_sort (const char *mspec, bool fromRcFile)
+{
+  char *mcmd;
+  BaseMetric::SubType subtypes[10];
+  int nsubtypes;
+  int vis;
+  bool parseOK = false;
+  bool reverse = false;
+  char buf[BUFSIZ];
+  char *list = buf;
+  char *mname;
+
+  // copy the input specification
+  snprintf (buf, sizeof (buf), NTXT ("%s"), mspec);
+  char *listp = list;
+  if (*listp == '-')
+    {
+      // reverse sort specified
+      reverse = true;
+      listp++;
+    }
+
+  // search for metric items from parsing the string
+  while ((mcmd = strtok (listp, NTXT (":"))) != NULL)
+    {
+      listp = NULL; // let strtok keep track
+
+      // parse the single metric_spec, based on the type of list being constructed, into:
+      //       a vector of SubTypes (any of [iead] or STATIC)
+      //       a integer mask for the visibility bits
+      //       and the string name of the base metric
+      mname = parse_metric_spec (mcmd, subtypes, &nsubtypes, &vis, &parseOK);
+      if (!parseOK)
+       {
+         // error parsing the metric specification
+         // not from an rc file, it's an error
+         if (!fromRcFile)
+           return (mname);
+         continue;
+       }
+      if (VAL_IS_HIDDEN (vis))
+       continue;
+
+      // loop over subtypes requested to find metric
+      // add a metric of that subtype, with specified vis.bits
+      for (int i = 0; i < nsubtypes; i++)
+       {
+         // make sure the subtype is acceptable
+         if ((mtype == MET_CALL || mtype == MET_CALL_AGR)
+             && subtypes[i] != BaseMetric::ATTRIBUTED
+             && subtypes[i] != BaseMetric::STATIC)
+             return dbe_sprintf (GTXT ("Inclusive, Exclusive, or Data metrics cannot be specified for caller-callee sort: %s\n"),
+                                 mcmd);
+         if (mtype == MET_DATA && subtypes[i] != BaseMetric::DATASPACE
+             && subtypes[i] != BaseMetric::STATIC)
+             return dbe_sprintf (GTXT ("Inclusive, Exclusive, or Attributed metrics cannot be specified for data-derived sort: %s\n"),
+                                 mcmd);
+         if (mtype == MET_INDX && subtypes[i] != BaseMetric::EXCLUSIVE
+                                  && subtypes[i] != BaseMetric::STATIC)
+           return dbe_sprintf (GTXT ("Inclusive, Data or Attributed metrics cannot be specified for index sort: %s\n"),
+                               mcmd);
+         if ((mtype == MET_NORMAL || mtype == MET_COMMON
+              || mtype == MET_SRCDIS)
+             && (subtypes[i] == BaseMetric::DATASPACE
+                 || subtypes[i] == BaseMetric::ATTRIBUTED))
+           return dbe_sprintf (GTXT ("Data or Attributed metrics cannot be specified for sort: %s\n"), mcmd);
+         if (set_sort_metric (mname, subtypes[i], reverse))
+           return NULL;
+       }
+      // continue looking at entries
+    }
+
+  // not found on the list at all
+  switch (mtype)
+    {
+    case MET_NORMAL:
+    case MET_COMMON:
+    case MET_SRCDIS:
+      return dbe_sprintf (GTXT ("Invalid sort specification: %s\n"), mspec);
+    case MET_CALL:
+    case MET_CALL_AGR:
+      return dbe_sprintf (GTXT ("Invalid caller-callee sort specification: %s\n"),
+                         mspec);
+    case MET_DATA:
+      return dbe_sprintf (GTXT ("Invalid data-derived sort specification: %s\n"),
+                         mspec);
+    case MET_INDX:
+      return dbe_sprintf (GTXT ("Invalid index sort specification: %s\n"),
+                         mspec);
+    case MET_IO:
+      return dbe_sprintf (GTXT ("Invalid I/O sort specification: %s\n"), mspec);
+    case MET_HEAP:
+      return dbe_sprintf (GTXT ("Invalid heap sort specification: %s\n"),
+                         mspec);
+    }
+  return NULL;
+}
+
+// set_sort to the metric with the given visible index
+
+void
+MetricList::set_sort (int visindex, bool reverse)
+{
+  Metric *mitem;
+  if (visindex < items->size ())
+    {
+      mitem = items->fetch (visindex);
+      if (mitem->is_any_visible ())
+       {
+         sort_ref_index = visindex;
+         sort_reverse = reverse;
+         return;
+       }
+    }
+  set_fallback_sort ();
+}
+
+bool
+MetricList::set_sort_metric (char *mname, BaseMetric::SubType mst, bool reverse)
+{
+  bool any = false, hwc = false, bit = false;
+
+  // check keywords 'any', 'all', 'bit' and 'hwc'
+  if (!strcasecmp (mname, Command::ANY_CMD))
+    any = true;
+  else if (!strcasecmp (mname, Command::ALL_CMD))
+    any = true;
+  else if (!strcasecmp (mname, Command::HWC_CMD))
+    hwc = true;
+  else if (!strcasecmp (mname, Command::BIT_CMD))
+    bit = true;
+
+  for (int i = 0, items_sz = items->size (); i < items_sz; i++)
+    {
+      Metric *m = items->fetch (i);
+      if (mst == m->get_subtype ()
+         && (any || (hwc && m->get_type () == BaseMetric::HWCNTR)
+             || (bit && m->get_cmd ()
+                 && strncmp (Command::BIT_CMD, m->get_cmd (),
+                             strlen (Command::BIT_CMD)) == 0)
+             || dbe_strcmp (mname, m->get_cmd ()) == 0))
+       {
+         sort_ref_index = i;
+         sort_reverse = reverse;
+         return true;
+       }
+    }
+  return false;
+}
+
+// Print to a file of a list of metrics from a supplied vector
+//     Debug flag = 1, prints the short name and address of the list
+//     Debug flag = 2, prints the details of the list
+void
+MetricList::print_metric_list (FILE *dis_file, char *leader, int debug)
+{
+  Metric *item;
+  int index;
+  char fmt_name[64];
+  fprintf (dis_file, NTXT ("%s"), leader);
+  if (items == NULL)
+    {
+      fprintf (dis_file, GTXT ("NULL metric list can not be printed; aborting"));
+      abort ();
+    }
+
+  if (items->size () == 0)
+    {
+      fprintf (dis_file, GTXT ("metric list is empty; aborting\n"));
+      abort ();
+    }
+
+  // if debugging, print list address and string, and sort name
+  if (debug != 0)
+    {
+      char *s = get_metrics ();
+      fprintf (dis_file, "\tmetriclist at 0x%lx: %s, %lld metrics; sort by %s\n",
+              (unsigned long) this, s, (long long) items->size (),
+              get_sort_name ());
+      free (s);
+      if (debug == 1)
+       return;
+    }
+
+  // Find the longest metric name & command
+  size_t max_len = 0;
+  size_t max_len2 = 0;
+
+  Vec_loop (Metric*, items, index, item)
+  {
+    // get the name
+    char *mn = item->get_name ();
+    size_t len = strlen (mn);
+    if (max_len < len)
+      max_len = len;
+
+    mn = item->get_mcmd (true);
+    len = strlen (mn);
+    if (max_len2 < len)
+      max_len2 = len;
+    free (mn);
+
+  }
+  if (debug == 2)
+    snprintf (fmt_name, sizeof (fmt_name), "%%%ds: %%-%ds", (int) max_len,
+             (int) max_len2);
+  else
+    snprintf (fmt_name, sizeof (fmt_name), "%%%ds: %%s", (int) max_len);
+
+  Vec_loop (Metric*, items, index, item)
+  {
+    char *mcmd = item->get_mcmd (true);
+    fprintf (dis_file, fmt_name, item->get_name (), mcmd);
+    free (mcmd);
+    if (debug == 2)
+      fprintf (dis_file, "\t[st %2d, VT %d, vis = %4s, T=%d, sort = %c]",
+              item->get_subtype (), item->get_vtype (),
+              item->get_vis_str (), item->is_time_val (),
+              sort_ref_index == index ? 'Y' : 'N');
+    fputc ('\n', dis_file);
+  }
+
+  fputc ('\n', dis_file);
+  fflush (dis_file);
+}
+
+// Return a string formatted from a vector of metrics
+//     string is in the form suitable for a "metrics <string>" command
+char *
+MetricList::get_metrics ()
+{
+  Metric *item;
+  int index;
+  StringBuilder sb;
+  Vec_loop (Metric*, items, index, item)
+  {
+    if (sb.length () != 0)
+      sb.append (':');
+    char *mcmd = item->get_mcmd (false);
+    sb.append (mcmd);
+    free (mcmd);
+  }
+  return sb.toString ();
+}
+
+int
+MetricList::get_listorder (Metric *mtr)
+{
+  for (int i = 0, items_sz = items->size (); i < items_sz; i++)
+    {
+      Metric *m = items->fetch (i);
+      if (m->get_subtype () == mtr->get_subtype ()
+         && m->get_id () == mtr->get_id ())
+       return i;
+    }
+  return -1;
+}
+
+int
+MetricList::get_listorder (char *cmd, BaseMetric::SubType st, const char *expr)
+{
+  for (long i = 0, items_sz = items->size (); i < items_sz; i++)
+    {
+      Metric *m = items->fetch (i);
+      if (m->get_subtype () == st && dbe_strcmp (m->get_cmd (), cmd) == 0
+         && dbe_strcmp (m->get_expr_spec (), expr) == 0)
+       return (int) i;
+    }
+  return -1;
+}
+
+Metric *
+MetricList::find_metric_by_name (char *cmd)
+{
+  for (long i = 0, items_sz = items->size (); i < items_sz; i++)
+    {
+      Metric *m = items->fetch (i);
+      if (dbe_strcmp (m->get_cmd (), cmd) == 0)
+       return m;
+    }
+  return NULL;
+}
+
+//  find a metric by name and subtype
+Metric *
+MetricList::find_metric (char *cmd, BaseMetric::SubType st)
+{
+  int i = get_listorder (cmd, st);
+  if (i < 0)
+    return NULL;
+  return items->fetch (i);
+}
+
+//  Get the sort metric from a list; forces sort by first if not set
+Metric *
+MetricList::get_sort_metric ()
+{
+  int i = get_sort_ref_index ();
+  return i >= 0 ? items->fetch (i) : NULL;
+}
+
+char *
+MetricList::get_sort_name ()
+{
+  Metric *item = get_sort_metric ();
+  if (item == NULL)
+    return dbe_strdup (NTXT (""));
+  char *n = item->get_name ();
+  return sort_reverse ? dbe_sprintf ("-%s", n) : dbe_strdup (n);
+}
+
+char *
+MetricList::get_sort_cmd ()
+{
+  char *buf;
+  Metric *item = get_sort_metric ();
+  if (item == NULL)
+    return dbe_strdup (NTXT (""));
+  char *n = item->get_mcmd (false);
+  if (sort_reverse)
+    {
+      buf = dbe_sprintf (NTXT ("-%s"), n);
+      free (n);
+    }
+  else
+    buf = n;
+  return buf;
+}
+
+Metric *
+MetricList::append (BaseMetric *bm, BaseMetric::SubType st, int visbits)
+{
+  for (long i = 0, sz = items->size (); i < sz; i++)
+    {
+      Metric *m = items->get (i);
+      if (m->get_id () == bm->get_id () && m->get_subtype () == st)
+       return NULL;
+    }
+  Metric *met = new Metric (bm, st);
+  met->set_dmetrics_visbits (visbits);
+  items->append (met);
+  return met;
+}
+
+int
+MetricList::add_matching_dmetrics (Vector<BaseMetric*> *base_items,
+                                  char *mcmd, BaseMetric::SubType *_subtypes,
+                                  int nsubtypes, int dmetrics_visbits,
+                                  bool fromRcFile)
+{
+  bool any = false, hwc = false, bit = false;
+  int got_metric = 1;
+
+  // check keywords 'any', 'all', 'bit', and 'hwc'
+  if (!strcasecmp (mcmd, Command::ANY_CMD))
+    any = true;
+  else if (!strcasecmp (mcmd, Command::ALL_CMD))
+    any = true;
+  else if (!strcasecmp (mcmd, Command::HWC_CMD))
+    hwc = true;
+  else if (!strcasecmp (mcmd, Command::BIT_CMD))
+    bit = true;
+
+  BaseMetric::SubType *subtypes = _subtypes;
+  BaseMetric::SubType all_subtypes[2] =
+    { BaseMetric::EXCLUSIVE, BaseMetric::INCLUSIVE };
+
+  if (nsubtypes == 0 || (nsubtypes == 1 && subtypes[0] == BaseMetric::STATIC))
+    {
+      // user did not specify ei; treat as wildcard and supply both.
+      subtypes = all_subtypes;
+      nsubtypes = 2;
+    }
+
+  // scan the metrics to find all matches
+  for (int i = 0, base_sz = base_items->size (); i < base_sz; i++)
+    {
+      BaseMetric *item = base_items->fetch (i);
+      if (!(any || (hwc && item->get_type () == BaseMetric::HWCNTR)
+           || (bit && item->get_cmd ()
+               && strncmp (item->get_cmd (), Command::BIT_CMD,
+                           strlen (Command::BIT_CMD)) == 0)
+           || dbe_strcmp (item->get_cmd (), mcmd) == 0))
+       continue;
+      if (item->is_internal ())
+       continue;
+      if (item->get_flavors () & BaseMetric::STATIC)
+       {
+         got_metric = 0;
+         int vis = item->get_type () != BaseMetric::ONAME ?
+                 dmetrics_visbits : VAL_VALUE;
+         if (append (item, BaseMetric::STATIC, vis) == NULL && !fromRcFile)
+           return 2;
+         continue;
+       }
+
+      // special case for omp metrics: make visible only if
+      // omp data has been collected
+      if (!dbeSession->is_omp_available ()
+         && (strcasecmp (mcmd, "ompwork") == 0
+             || strcasecmp (mcmd, "ompwait") == 0))
+         continue;
+
+      for (int j = 0; j < nsubtypes; j++)
+       {
+         if (append (item, subtypes[j], dmetrics_visbits) == NULL
+             && !fromRcFile)
+           return 2;
+       }
+      got_metric = 0;
+      if (!(any || hwc || bit))
+       break;
+    }
+  return got_metric;
+}
+
+// parse a single metric specification, to give:
+//     a vector of subtypes, and a count of the number of them
+//     an integer visibility
+//     return the string for the metric name
+
+char *
+MetricList::parse_metric_spec (char *mcmd, BaseMetric::SubType *subtypes,
+                              int *nsubtypes, int *dmetrics_visb, bool *isOK)
+{
+  size_t len_vtype;
+  int index;
+  int vis;
+  bool got_e, got_i, got_a, got_d;
+  char *str = mcmd;
+  char *str2;
+
+  *isOK = true;
+
+  // For dynamic metrics, each keyword is of the form  <flavor><visibility><metric-name>
+  // For static metrics, each keyword is of the form [<visibility>]<metric-name>
+  // <flavor> can be either "i" for inclusive or "e" for exclusive
+  // <visibility> can be any combination of "." (to show the metric as a time),
+  //    "%" (to show it as a percentage), "+" (to show it as a count), and "!" (turn off the metric)
+
+  // find subtype
+  index = 0;
+  size_t len_subtype = strspn (str, NTXT ("eiad"));
+  str2 = str + len_subtype;
+
+  // find vis
+  if (len_subtype == 0)
+    {
+      // only a . or ! is possible if no subtypes
+      len_vtype = strspn (str2, NTXT (".!"));
+      vis = VAL_VALUE;
+    }
+  else
+    {
+      len_vtype = strspn (str2, NTXT (".+%!"));
+      vis = VAL_NA;
+    }
+
+  // if no visibility bits, there can't be a subtype
+  if (len_vtype == 0)
+    len_subtype = 0;
+
+  if (len_subtype == 0)
+    {
+      // must be a static metric
+      subtypes[index++] = BaseMetric::STATIC;
+      vis = VAL_VALUE;
+    }
+  else
+    {
+      // figure out which subtypes are specified
+      got_e = got_i = got_a = got_d = false;
+      for (size_t i = 0; i < len_subtype; i++)
+       {
+         str += len_subtype;
+         if (mcmd[i] == 'e')
+           { // exclusive
+             if (mtype == MET_DATA)
+               {
+                 *isOK = false;
+                 return dbe_sprintf (GTXT ("Invalid metric specification: %s inapplicable for data metrics\n"),
+                                     mcmd);
+               }
+             if (!got_e)
+               {
+                 got_e = true;
+                 subtypes[index++] = BaseMetric::EXCLUSIVE;
+               }
+           }
+         else if (mcmd[i] == 'i')
+           { // inclusive
+             if (mtype == MET_DATA)
+               {
+                 *isOK = false;
+                 return dbe_sprintf (GTXT ("Invalid metric specification: %s inapplicable for data metrics\n"),
+                                     mcmd);
+               }
+             if (mtype == MET_INDX)
+               {
+                 *isOK = false;
+                 return dbe_sprintf (GTXT ("Invalid metric specification: %s inapplicable for index metrics\n"),
+                                     mcmd);
+               }
+             if (!got_i)
+               {
+                 got_i = true;
+                 subtypes[index++] = BaseMetric::INCLUSIVE;
+               }
+           }
+         else if (mcmd[i] == 'a')
+           { // attributed
+             if (mtype != MET_CALL && mtype != MET_CALL_AGR)
+               {
+                 *isOK = false;
+                 return dbe_sprintf (GTXT ("Invalid metric specification: %s applicable for caller-callee metrics only\n"),
+                                     mcmd);
+               }
+             if (!got_a)
+               {
+                 got_a = true;
+                 subtypes[index++] = BaseMetric::ATTRIBUTED;
+               }
+           }
+         else if (mcmd[i] == 'd')
+           { // data-space
+             if (mtype != MET_DATA)
+               {
+                 *isOK = false;
+                 return dbe_sprintf (GTXT ("Invalid metric specification: %s applicable for data-derived metrics only\n"),
+                                     mcmd);
+               }
+             if (!got_d)
+               {
+                 got_d = true;
+                 subtypes[index++] = BaseMetric::DATASPACE;
+               }
+           }
+       }
+    }
+  *nsubtypes = index;
+
+  // now determine the visiblity bits
+  if (len_vtype > 0)
+    {
+      for (size_t i = 0; i < len_vtype; i++)
+       {
+         if (str2[i] == '+')
+           vis = (vis | VAL_VALUE);
+         else if (str2[i] == '.')
+           vis = (vis | VAL_TIMEVAL);
+         else if (str2[i] == '%')
+           vis = (vis | VAL_PERCENT);
+         else if (str2[i] == '!')
+           vis = (vis | VAL_HIDE_ALL);
+       }
+    }
+  *dmetrics_visb = vis;
+  return mcmd + len_subtype + len_vtype;
+}
diff --git a/gprofng/src/MetricList.h b/gprofng/src/MetricList.h
new file mode 100644 (file)
index 0000000..b8486c1
--- /dev/null
@@ -0,0 +1,163 @@
+/* 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 _METRICLIST_H
+#define _METRICLIST_H
+
+#include "dbe_structs.h"
+#include "vec.h"
+#include "enums.h"
+#include "Metric.h"
+#include "DerivedMetrics.h"
+#include <stdio.h>
+
+//
+// The MetricList class is used to manage a list of metrics
+
+class MetricList
+{
+public:
+
+  MetricList (Vector<BaseMetric*> *base_metrics, MetricType type);
+  MetricList (MetricList *old);
+  MetricList (MetricType _mtype);
+  ~MetricList ();
+
+  // Methods concerning a list of metrics
+  // set metrics -- text, caller-callee, data, and index flavors
+  //    flavor depends on mtype in the list
+  //    returns NULL if OK, or an error string if not
+  //    always returns NULL if fromRcFile is TRUE
+  char *set_metrics (const char *metric_cmd, bool fromRcFile, DerivedMetrics *derived_metrics);
+
+  // update the caller-callee or dataspace metrics to match normal metrics
+  //   It is assumed that this->mtype is MET_CALL, MET_DATA, or MET_INDX and
+  //   that metrics_list->mtype is MET_NORMAL
+  void set_metrics (MetricList *metrics_list);
+
+  // produce a string for the metrics from a vector
+  char *get_metrics ();
+
+  // set the sort metric for a list from a metric string
+  //   returns NULL if OK, or an error string if not
+  char *set_sort (const char *metric_cmd, bool fromRcFile);
+
+  // set the sort metric for a list from the first visible index
+  void set_fallback_sort ();
+
+  // set the sort metric for a list from a visible index
+  void set_sort (int visindex, bool reverse);
+
+  char *get_sort_name ();   // get the name of the sort metric from a vector
+
+  bool
+  get_sort_rev ()   // get the boolean reverse for the sort metric
+  {
+    return sort_reverse;
+  }
+
+  void
+  set_sort_rev (bool v)
+  {
+    sort_reverse = v;
+  }
+
+  int
+  get_sort_ref_index ()
+  {
+    return sort_ref_index;
+  }
+
+  void
+  set_sort_ref_index (int ind)
+  {
+    sort_ref_index = ind;
+  }
+
+  bool set_sort_metric (char *metric_cmd, BaseMetric::SubType mst, bool reverse);
+  Metric *find_metric (char *cmd, BaseMetric::SubType st);
+  Metric *find_metric_by_name (char *cmd);
+  int get_listorder (char *cmd, BaseMetric::SubType st, const char *expr = NULL);
+  int get_listorder (Metric *mtr);
+  Metric *get_sort_metric ();       // get the sort metric from a vector
+  char *get_sort_cmd ();            // get the command name of the sort metric
+
+  MetricType
+  get_type ()
+  {
+    return mtype;
+  }
+
+  Vector<Metric*> *
+  get_items ()          // get the vector of metrics from the list
+  {
+    return items;
+  }
+
+  Metric *
+  get (long i)
+  {
+    return items->get (i);
+  }
+
+  void
+  put (long i, Metric *m)
+  {
+    items->put (i, m);
+  }
+
+  void
+  append (Metric *m)
+  {
+    items->append (m);
+  }
+
+  long
+  size ()
+  {
+    return items ? items->size () : 0;
+  }
+
+  Metric *append (BaseMetric *bm, BaseMetric::SubType st, int visbits);
+
+  // produce a list of all metrics from a vector
+  void print_metric_list (FILE *dis_file, char *leader, int debug);
+
+  // Add any and all matching metrics to the growing list
+  // return value is zero for OK, 1 for no match
+  int add_matching_dmetrics (Vector<BaseMetric*> *base_items, char *cmd,
+                   BaseMetric::SubType *subtypes, int nsubtypes,
+                   int dmetrics_vis, // literal translation of dmetrics +. etc.
+                    bool fromRcFile);
+
+private:
+  // parse a metric specification substring, based on type of list
+  char *parse_metric_spec (char *cmd, BaseMetric::SubType *subtypes,
+                          int *nsubtypes, int *dmetrics_visb, bool *isOK);
+
+  Vector<Metric*> *items;
+  MetricType mtype;
+
+  // the sort reference index
+  int sort_ref_index;
+  bool sort_reverse;
+};
+
+#endif  /* _METRICLIST_H */
diff --git a/gprofng/src/Module.cc b/gprofng/src/Module.cc
new file mode 100644 (file)
index 0000000..1e61b42
--- /dev/null
@@ -0,0 +1,1840 @@
+/* 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 <unistd.h>
+#include <ar.h>
+#include <ctype.h>
+#include <sys/param.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "DataObject.h"
+#include "Function.h"
+#include "DbeView.h"
+#include "MetricList.h"
+#include "Module.h"
+#include "ClassFile.h"
+#include "LoadObject.h"
+#include "Disasm.h"
+#include "CompCom.h"
+#include "Dwarf.h"
+#include "DbeFile.h"
+#include "PathTree.h"
+#include "Elf.h"
+
+Module::Module ()
+{
+  lang_code = Sp_lang_unknown;
+  flags = 0;
+  status = AE_NOTREAD;
+  openSourceFlag = AE_NOTREAD;
+  hexVisible = false;
+  disPath = NULL;
+  stabsPath = NULL;
+  stabsTmp = NULL;
+  disName = NULL;
+  stabsName = NULL;
+  indexStabsLink = NULL;
+  file_name = NULL;
+  functions = new Vector<Function*>;
+  loadobject = NULL;
+  dot_o_file = NULL;
+  main_source = dbeSession->get_Unknown_Source ();
+  srcContext = main_source;
+  includes = new Vector<SourceFile*>;
+  includes->append (main_source);
+  curr_inc = NULL;
+  fragmented = 0;
+  hwcprof = 0;
+  hdrOffset = 0;
+  hasDwarf = false;
+  hasStabs = false;
+  readStabs = false;
+  comComs = NULL;
+  infoList = NULL;
+  datatypes = NULL;
+  objStabs = NULL;
+  disasm = NULL;
+  comp_flags = NULL;
+  comp_dir = NULL;
+  linkerStabName = NULL;
+  disMTime = (time_t) 0;
+  stabsMTime = (time_t) 0;
+  real_timestamp = 0;
+  curr_timestamp = 0;
+  src_items = NULL;
+  dis_items = NULL;
+  data_items = NULL;
+  cur_dbev = NULL;
+  maximum = NULL;
+  maximum_inc = NULL;
+  empty = NULL;
+  inlinedSubr = NULL;
+}
+
+Module::~Module ()
+{
+  removeStabsTmp ();
+  delete includes;
+  if (comComs != NULL)
+    {
+      comComs->destroy ();
+      delete comComs;
+    }
+  free (comp_flags);
+  free (comp_dir);
+  free (linkerStabName);
+  free (disPath);
+  free (stabsPath);
+  free (disName);
+  free (stabsName);
+  delete functions;
+  free (file_name);
+  if (indexStabsLink)
+    // Remove a link to the current module
+    indexStabsLink->indexStabsLink = NULL;
+
+  if (dot_o_file)
+    {
+      delete dot_o_file->dbeFile;
+      delete dot_o_file;
+    }
+  delete src_items;
+  delete dis_items;
+  delete disasm;
+  free (inlinedSubr);
+  if (lang_code != Sp_lang_java)
+    delete dbeFile;
+
+}
+
+Stabs *
+Module::openDebugInfo ()
+{
+  setFile ();
+  objStabs = loadobject->openDebugInfo (disPath);
+  return objStabs;
+}
+
+void
+Module::removeStabsTmp ()
+{
+  // Remove temporary *.o (got from *.a) after reading Stabs
+  if (stabsTmp != NULL)
+    {
+      unlink (stabsTmp);
+      free (stabsTmp);
+      stabsTmp = NULL;
+    }
+}
+
+int64_t
+Module::get_size ()
+{
+  Function *fp;
+  int index;
+  int64_t result = 0;
+  Vec_loop (Function*, functions, index, fp)
+  {
+    result += fp->size;
+  }
+  return result;
+}
+
+bool
+Module::is_fortran ()
+{
+  return Stabs::is_fortran (lang_code);
+}
+
+SourceFile *
+Module::findSource (const char *fname, bool create)
+{
+  SourceFile *sf = NULL;
+  if (loadobject && loadobject->firstExp)
+    sf = loadobject->firstExp->get_source (fname);
+  if (sf == NULL)
+    sf = dbeSession->createSourceFile (fname);
+  for (int i = 0, sz = includes ? includes->size () : 0; i < sz; i++)
+    {
+      SourceFile *sf1 = includes->fetch (i);
+      if (sf == sf1)
+       return sf;
+    }
+  if (create)
+    {
+      if (includes == NULL)
+       includes = new Vector<SourceFile*>;
+      includes->append (sf);
+      return sf;
+    }
+  return NULL;
+}
+
+SourceFile *
+Module::setIncludeFile (char *includeFile)
+{
+  curr_inc = NULL;
+  if (includeFile)
+    curr_inc = findSource (includeFile, true);
+  return curr_inc;
+}
+
+char *
+Module::anno_str (char *fnm)
+{
+  char timebuf1[26], timebuf2[26];
+  const time_t real_time = (time_t) (unsigned int) real_timestamp;
+  const time_t curr_time = (time_t) (unsigned int) curr_timestamp;
+
+  switch (status)
+    {
+    case AE_OK:
+    case AE_NOTREAD:
+      return NULL;
+    case AE_NOSRC:
+      return dbe_sprintf (GTXT ("Source file `%s' not readable"),
+                         fnm ? fnm : file_name);
+    case AE_NOOBJ:
+      if (lang_code == Sp_lang_java)
+       {
+         Emsg *emsg = get_error ();
+         if (emsg)
+           {
+             char *s = dbe_strdup (emsg->get_msg ());
+             remove_msg (emsg);
+             return s;
+           }
+         return dbe_sprintf (GTXT ("Object file `%s.class' not readable"),
+                             name);
+       }
+      return dbe_sprintf (GTXT ("Object file `%s' not readable"), get_name ());
+    case AE_NOLOBJ:
+      if (lang_code == Sp_lang_java)
+       return dbe_sprintf (GTXT ("Object file `%s' not readable"),
+                           dbeFile ? dbeFile->get_name () : name);
+      return dbe_sprintf (GTXT ("Object file `%s' not readable"), loadobject->get_pathname ());
+    case AE_NOSTABS:
+      return dbe_sprintf (GTXT ("Error reading line-number information in object `%s'; source annotation not available"),
+                         stabsPath ? stabsPath : NTXT (""));
+    case AE_NOSYMTAB:
+      return dbe_sprintf (GTXT ("Error reading symbol table in object `%s'; disassembly annotation not available"),
+                         disPath ? disPath : NTXT (""));
+    case AE_TIMESRC:
+      return dbe_sprintf (GTXT ("Warning! Source file `%s' is newer than the experiment data"),
+                         main_source->dbeFile->getResolvedPath ());
+    case AE_TIMEDIS:
+      return dbe_sprintf (GTXT ("Warning! Object file `%s' is newer than the experiment data"),
+                         disName ? disName : NTXT (""));
+    case AE_TIMESTABS:
+      return dbe_sprintf (GTXT ("Warning! Object file `%s' is newer than the experiment data"),
+                         stabsName ? stabsName : NTXT (""));
+    case AE_TIMESTABS_DIFF:
+      snprintf (timebuf1, sizeof (timebuf1), NTXT ("%s"), ctime (&curr_time));
+      snprintf (timebuf2, sizeof (timebuf2), NTXT ("%s"), ctime (&real_time));
+      timebuf1[24] = timebuf2[24] = '\0';
+      return dbe_sprintf (GTXT ("Warning! Object file `%s' is not the same one that was linked into executable.\n"
+                               "\tObject file: `%s'\n\tcompiled on: %s\n"
+                               "\tExecutable contains object file compiled on: %s"),
+                         getResolvedObjectPath (), getResolvedObjectPath (),
+                         timebuf1, timebuf2);
+    case AE_OTHER:
+    default:
+      return dbe_strdup (GTXT ("Annotation computation error"));
+    }
+}//anno_str
+
+LoadObject *
+Module::createLoadObject (const char *lo_name)
+{
+  LoadObject *lo = new LoadObject (lo_name);
+  lo->dbeFile->filetype |= DbeFile::F_DOT_O;
+  return lo;
+}
+
+static bool
+tsIsNewer (time_t t1, time_t t2)
+{
+  return t1 != 0 && t2 != 0 && t1 < t2;
+}
+
+Module::Anno_Errors
+Module::checkTimeStamp (bool chkDis)
+{
+  /* Check the linked and the real object timestamps due to bug #4796329 */
+  if (real_timestamp && curr_timestamp && real_timestamp != curr_timestamp)
+    return AE_TIMESTABS_DIFF;
+
+  time_t srctime = main_source->getMTime ();
+  for (int index = 0; index < dbeSession->nexps (); index++)
+    {
+      time_t mtime = dbeSession->get_exp (index)->get_mtime ();
+      if (tsIsNewer (mtime, srctime))
+       return AE_TIMESRC;
+      if (tsIsNewer (mtime, stabsMTime))
+       return AE_TIMESTABS;
+      if (chkDis && tsIsNewer (mtime, disMTime))
+       return AE_TIMEDIS;
+    }
+  return AE_OK;
+}//checkTimeStamp
+
+static size_t
+get_ar_size (char *s, size_t len)
+{
+  size_t sz = 0;
+  for (size_t i = 0; i < len; i++)
+    {
+      if (s[i] < '0' || s[i] > '9')
+       break;
+      sz = sz * 10 + (s[i] - '0');
+    }
+  return sz;
+}
+
+static void
+dump_hdr_field (char *nm, char *s, size_t len)
+{
+  Dprintf (DEBUG_READ_AR, NTXT ("  %s "), nm);
+  for (size_t i = 0; i < len; i++)
+    Dprintf (DEBUG_READ_AR, "%c", isprint (s[i]) ? s[i] : '?');
+  Dprintf (DEBUG_READ_AR, NTXT ("  "));
+  for (size_t i = 0; i < len; i++)
+    Dprintf (DEBUG_READ_AR, NTXT (" %d"), s[i]);
+  Dprintf (DEBUG_READ_AR, NTXT (" \n"));
+}
+
+static void
+dump_ar_hdr (int lineNum, struct ar_hdr *hdr)
+{
+  if (DEBUG_READ_AR)
+    {
+      Dprintf (DEBUG_READ_AR, NTXT ("Module::read_ar %d\n"), lineNum);
+      dump_hdr_field (NTXT ("ar_name"), hdr->ar_name, sizeof (hdr->ar_name));
+      dump_hdr_field (NTXT ("ar_date"), hdr->ar_date, sizeof (hdr->ar_date));
+      dump_hdr_field (NTXT ("ar_uid"), hdr->ar_uid, sizeof (hdr->ar_uid));
+      dump_hdr_field (NTXT ("ar_gid"), hdr->ar_gid, sizeof (hdr->ar_gid));
+      dump_hdr_field (NTXT ("ar_mode"), hdr->ar_mode, sizeof (hdr->ar_mode));
+      dump_hdr_field (NTXT ("ar_size"), hdr->ar_size, sizeof (hdr->ar_size));
+      dump_hdr_field (NTXT ("ar_fmag"), hdr->ar_fmag, sizeof (hdr->ar_fmag));
+    }
+}
+
+bool
+Module::read_ar (int ar, int obj, char *obj_base)
+{
+  struct ar_hdr hdr; // Archive header
+  char magic[SARMAG]; // Magic string from archive
+  Dprintf (DEBUG_READ_AR, "Module::read_ar %d %p %s %s \n", __LINE__,
+          this, STR (obj_base), STR (get_name ()));
+  // Check the magic string
+  if ((read_from_file (ar, magic, SARMAG) != SARMAG)
+       || strncmp (magic, ARMAG, SARMAG))
+    return false;
+
+  // Read and skip the first file in the archive (index file to ld)
+  if (read_from_file (ar, &hdr, sizeof (hdr)) != sizeof (hdr))
+    return false;
+  DEBUG_CODE dump_ar_hdr (__LINE__, &hdr);
+  if (lseek (ar, get_ar_size (hdr.ar_size, sizeof (hdr.ar_size)), SEEK_CUR)
+            == -1)
+    return false;
+
+  // Read the string file where it keeps long file names (if exist)
+  if (read_from_file (ar, &hdr, sizeof (hdr)) != sizeof (hdr))
+    return false;
+  DEBUG_CODE dump_ar_hdr (__LINE__, &hdr);
+  char *longnames = NULL; // Area with names longer than ~13
+  size_t longnames_size = 0;
+  if (!strncmp (hdr.ar_name, NTXT ("//"), 2))
+    {
+      longnames_size = get_ar_size (hdr.ar_size, sizeof (hdr.ar_size));
+      longnames = (char *) malloc (longnames_size + 1);
+      int64_t cnt = read_from_file (ar, longnames, longnames_size);
+      if (cnt != (int64_t) longnames_size)
+       {
+         free (longnames);
+         return false;
+       }
+      longnames[longnames_size] = 0;
+    }
+  else
+    // back out, no long file names
+    lseek (ar, -(sizeof (hdr)), SEEK_CUR);
+
+  // Search the ar for the object file name
+  char ar_buf[sizeof (hdr.ar_name) + 1];
+  ar_buf[sizeof (hdr.ar_name)] = 0;
+  while (1)
+    {
+      if (read_from_file (ar, &hdr, sizeof (hdr)) != sizeof (hdr))
+       break;
+      DEBUG_CODE dump_ar_hdr (__LINE__, &hdr);
+      char *ar_name;
+      if (hdr.ar_name[0] != '/')
+       { // Name is in the header
+         for (size_t i = 0; i < sizeof (hdr.ar_name); i++)
+           {
+             if (hdr.ar_name[i] == '/')
+               {
+                 ar_buf[i] = 0;
+                 break;
+               }
+             ar_buf[i] = hdr.ar_name[i];
+           }
+         ar_name = ar_buf;
+       }
+      else if (hdr.ar_name[1] == ' ')
+       { // Name is blank
+         ar_buf[0] = 0;
+         ar_name = ar_buf;
+       }
+      else
+       { // Name is in the string table
+         if (longnames == NULL)
+           break;
+         size_t offset = get_ar_size (hdr.ar_name + 1,
+                                      sizeof (hdr.ar_name) - 1);
+         if (offset >= longnames_size)
+           break;
+         for (size_t i = offset; i < longnames_size; i++)
+           {
+             if (longnames[i] == '/')
+               {
+                 longnames[i] = 0;
+                 break;
+               }
+           }
+         ar_name = longnames + offset;
+       }
+      Dprintf (DEBUG_READ_AR, "Module::read_ar %d ar_name=%s\n", __LINE__,
+              ar_name);
+
+      if (streq (ar_name, obj_base))
+       { // create object file
+         free (longnames);
+         for (size_t objsize = get_ar_size (hdr.ar_size, sizeof (hdr.ar_size));
+                 objsize > 0;)
+           {
+             char buf[MAXPATHLEN];
+             size_t n = objsize < sizeof (buf) ? objsize : sizeof (buf);
+             int64_t cnt = read_from_file (ar, buf, n);
+             if (cnt != (int64_t) n)
+               return false;
+             cnt = write (obj, buf, n);
+             if (cnt != (int64_t) n)
+               return false;
+             objsize -= n;
+           }
+         return true;
+       }
+      if (lseek (ar, get_ar_size (hdr.ar_size, sizeof (hdr.ar_size)),
+                SEEK_CUR) == -1)
+       break;
+    }
+  free (longnames);
+  return false;
+}
+
+static char *
+get_obj_name_from_lib (char *nm)
+{
+  char *base = strrchr (nm, '(');
+  if (base)
+    {
+      size_t last = strlen (base) - 1;
+      if (base[last] == ')')
+       return base;
+    }
+  return NULL;
+}
+
+bool
+Module::setFile ()
+{
+  if ((loadobject->flags & SEG_FLAG_DYNAMIC) != 0)
+    return true;
+  if ((loadobject->dbeFile->filetype & DbeFile::F_FICTION) != 0)
+    return false;
+  if ((flags & MOD_FLAG_UNKNOWN) != 0)
+    return true;
+
+  if (lang_code == Sp_lang_java)
+    {
+      if (dbeFile->get_need_refind ())
+       {
+         char *fnm = dbeFile->get_location ();
+         stabsPath = dbe_strdup (fnm);
+         stabsName = dbe_strdup (fnm);
+         disPath = dbe_strdup (fnm);
+         disName = dbe_strdup (fnm);
+         stabsMTime = dbeFile->sbuf.st_mtime;
+       }
+      return dbeFile->get_location () != NULL;
+    }
+
+  if (dbeFile == NULL)
+    {
+      char *objname = get_obj_name_from_lib (name);
+      if (objname)
+       {
+         // in the format of libpath(obj)
+         objname = dbe_strdup (objname + 1);
+         size_t last = strlen (objname) - 1;
+         objname[last] = '\0';
+       }
+      dbeFile = new DbeFile (objname ? objname : name);
+      free (objname);
+      dbeFile->filetype |= DbeFile::F_DOT_O;
+    }
+  if (dbeFile->get_need_refind ())
+    {
+      disMTime = (time_t) 0;
+      stabsMTime = (time_t) 0;
+      free (disName);
+      free (stabsName);
+      disName = NULL;
+      stabsName = NULL;
+
+      // Find the Executable/Shared-Object file of module
+      char *path = loadobject->dbeFile->get_location ();
+      if (path)
+       {
+         disPath = strdup (path);
+         disName = strdup (path);
+         disMTime = loadobject->dbeFile->sbuf.st_mtime;
+       }
+
+      char *objname = get_obj_name_from_lib (name);
+      if (objname)
+       {
+         // in the format of libpath(obj)
+         char *namebuf = dbe_strdup (name);
+         char *base = namebuf + (objname - name);
+         *base = '\0';
+         base++;
+         size_t last = strlen (base) - 1;
+         base[last] = '\0';
+         stabsTmp = dbeSession->get_tmp_file_name (base, false);
+         dbeSession->tmp_files->append (strdup (stabsTmp));
+
+         DbeFile *dbf = dbeSession->getDbeFile (namebuf,
+                                       DbeFile::F_DOT_A_LIB | DbeFile::F_FILE);
+         path = dbf->get_location ();
+         int ar = -1, obj = -1;
+         if (path != NULL)
+           {
+             ar = open64 (path, O_RDONLY | O_LARGEFILE);
+             if (ar != -1)
+               obj = open64 (stabsTmp, O_CREAT | O_WRONLY | O_LARGEFILE, 0600);
+           }
+         if (ar != -1 && obj != -1 && read_ar (ar, obj, base))
+           {
+             dbeFile->set_location (stabsTmp);
+             dbeFile->check_access (stabsTmp); // init 'sbuf'
+             dbeFile->sbuf.st_mtime = 0; // Don't check timestamps
+             dbeFile->container = dbf;
+             stabsPath = strdup (stabsTmp);
+             stabsName = strdup (path);
+             stabsMTime = dbeFile->sbuf.st_mtime;
+           }
+         else
+           {
+             removeStabsTmp ();
+             objname = NULL;
+           }
+         if (ar != -1)
+           close (ar);
+         if (obj != -1)
+           close (obj);
+         free (namebuf);
+       }
+      if (objname == NULL)
+       {
+         path = dbeFile->get_location ();
+         if (path != NULL)
+           {
+             stabsPath = strdup (path);
+             stabsName = strdup (path);
+             stabsMTime = hasDwarf ? 0 : dbeFile->sbuf.st_mtime;
+           }
+       }
+
+      // First, try to access the symbol table of the module itself
+      // If failed, access the symbol table of the executable
+      if (stabsPath == NULL)
+       {
+         if (disPath == NULL)
+           return false;
+         stabsPath = strdup (disPath);
+         stabsName = strdup (disName);
+         stabsMTime = disMTime;
+       }
+      else if (disPath == NULL)
+       {
+         disPath = strdup (stabsPath);
+         disName = strdup (stabsName);
+         disMTime = stabsMTime;
+       }
+    }
+  return stabsPath != NULL;
+}
+
+// openStabs -- open mappings from PCs to source lines
+bool
+Module::openStabs (bool all)
+{
+  if ((loadobject->flags & SEG_FLAG_DYNAMIC) != 0
+      || (flags & MOD_FLAG_UNKNOWN) != 0)
+    return true;
+  if (loadobject->platform == Java)
+    {
+      setIncludeFile (NULL);
+      readFile ();
+      return ( status == AE_OK);
+    }
+  if (readStabs)
+    return true;
+
+  // Read Stabs info.
+  int64_t Inode = main_source->getInode ();
+  char *fname = strrchr (file_name, (int) '/');
+  char *mname = strrchr (main_source->get_name (), (int) '/');
+  if (fname && mname && !streq (fname, mname))
+    {
+      SourceFile *sf = findSource (file_name, false);
+      if (sf != NULL)
+       Inode = sf->getInode ();
+    }
+
+  comComs = new Vector<ComC*>;
+  Stabs *stabs = openDebugInfo ();
+  if (stabs == NULL)
+    return false;
+  int st = stabs->read_stabs (Inode, this, comComs, true);
+  if (!hasDwarf && hasStabs && !streq (stabsPath, disPath))
+    {
+      // Read stabs from .o file
+      if (dot_o_file == NULL)
+       {
+         if (dbeFile->get_location ())
+           {
+             dot_o_file = createLoadObject (dbeFile->get_name ());
+             dot_o_file->dbeFile->set_location (dbeFile->get_location ());
+             dot_o_file->dbeFile->sbuf = dbeFile->sbuf;
+             dot_o_file->dbeFile->container = dbeFile->container;
+           }
+       }
+      if (dot_o_file
+         && dot_o_file->sync_read_stabs () == LoadObject::ARCHIVE_SUCCESS)
+       {
+         Stabs *stabs_o = dot_o_file->objStabs;
+         if (stabs_o)
+           {
+             st = stabs_o->read_stabs (Inode, this,
+                                       comComs->size () > 0 ? NULL : comComs);
+             Elf *elf_o = stabs_o->openElf (false);
+             if (elf_o->dwarf)
+               stabs->read_dwarf_from_dot_o (this);
+           }
+       }
+    }
+  if (all)
+    read_hwcprof_info ();
+
+  readStabs = true;
+  return st == Stabs::DBGD_ERR_NONE;
+}
+
+char *
+Module::get_disasm (uint64_t inst_address, uint64_t end_address,
+                  uint64_t start_address, uint64_t address, int64_t &inst_size)
+{
+  return disasm->get_disasm (inst_address, end_address, start_address,
+                            address, inst_size);
+}
+
+void
+Module::read_stabs (bool all)
+{
+  if (openSourceFlag == AE_NOTREAD)
+    {
+      openSourceFlag = AE_OK;
+      if (lang_code == Sp_lang_java)
+       {
+         char *clpath = file_name;
+         if (clpath == NULL || strcmp (clpath, "<Unknown>") == 0)
+           clpath = ClassFile::get_java_file_name (name, false);
+         main_source = findSource (clpath, true);
+         main_source->dbeFile->filetype |= DbeFile::F_JAVA_SOURCE;
+         if (clpath != file_name)
+           free (clpath);
+       }
+      else
+       main_source = findSource (file_name, true);
+      if (setFile ())
+       openStabs (all);
+    }
+}
+
+bool
+Module::openDisPC ()
+{
+  if (disasm == NULL)
+    {
+      if (!(loadobject->flags & SEG_FLAG_DYNAMIC) && loadobject->platform != Java)
+       {
+         // Read Stabs & Symbol tables
+         if (openDebugInfo () == NULL)
+           return false;
+         if (!objStabs->read_symbols (functions))
+           return false;
+       }
+      disasm = new Disasm (loadobject->platform, objStabs);
+    }
+  return true;
+}
+
+static SourceFile *cmpSrcContext; // Use only for func_cmp
+
+static int
+func_cmp (const void *a, const void *b)
+{
+  Function *fp1 = *((Function **) a);
+  Function *fp2 = *((Function **) b);
+  return fp1->func_cmp (fp2, cmpSrcContext);
+}
+
+bool
+Module::computeMetrics (DbeView *dbev, Function *func, MetricList *metrics,
+                       Histable::Type type, bool src_metric,
+                       bool func_scope, SourceFile *source)
+{
+  name_idx = metrics->get_listorder (NTXT ("name"), Metric::STATIC);
+  if (name_idx < 0)
+    {
+      metrics->print_metric_list (stderr,
+                                 GTXT ("Fatal: no name metric in Module::computeMetrics mlist:\n"),
+                                 1);
+      abort ();
+    }
+
+  // Now find the metrics for size and address, if present
+  size_index = metrics->get_listorder (NTXT ("size"), Metric::STATIC);
+  addr_index = metrics->get_listorder (NTXT ("address"), Metric::STATIC);
+
+  // free the old cached data for both src and disassembly
+  //   If it's disassembly with visible source metrics, we use both
+  if (dis_items)
+    {
+      delete dis_items;
+      dis_items = NULL;
+    }
+  if (src_items)
+    {
+      delete src_items;
+      src_items = NULL;
+    }
+
+  // ask the DbeView to generate new data to be cached
+  if (src_metric || type == Histable::LINE)
+    {
+      Histable *obj = (func_scope) ? (Histable*) func : (Histable*)this;
+      if (lang_code == Sp_lang_java)
+       obj = func_scope ? (Histable *) func :
+             (source && source->get_type () == Histable::SOURCEFILE ?
+              (Histable *) source : (Histable *) this);
+      src_items = dbev->get_hist_data (metrics, Histable::LINE, 0,
+                                      Hist_data::MODL, obj, source);
+    }
+  if (type == Histable::INSTR)
+    dis_items = dbev->get_hist_data (metrics, Histable::INSTR, 0,
+                              Hist_data::MODL,
+                              func_scope ? (Histable*) func : (Histable*) this,
+                              source);
+
+  Hist_data *cur_hist_data;
+  if (type == Histable::INSTR)
+    cur_hist_data = dis_items;
+  else
+    cur_hist_data = src_items;
+
+  Vector<Metric*> *items = cur_hist_data->get_metric_list ()->get_items ();
+  long sz = items->size ();
+  empty = new TValue[sz];
+  memset (empty, 0, sizeof (TValue) * sz);
+  for (long i = 0; i < sz; i++)
+    empty[i].tag = items->get (i)->get_vtype ();
+  return true;
+}
+
+// Method to get annotated source or disassembly for the module
+//     or a function within it
+Hist_data *
+Module::get_data (DbeView *dbev, MetricList *mlist, Histable::Type type,
+                 TValue *ftotal, SourceFile *srcFile, Function *func,
+                 Vector<int> *marks, int threshold, int vis_bits,
+                 int src_visible, bool hex_vis, bool func_scope,
+                 bool /*src_only*/, Vector<int_pair_t> *marks2d,
+                 Vector<int_pair_t> *marks2d_inc)
+{
+  cur_dbev = dbev;
+  srcContext = srcFile ? srcFile : main_source;
+  read_stabs ();
+  status = AE_OK;
+  dbev->warning_msg = NULL;
+  dbev->error_msg = NULL;
+  if (type == Histable::LINE)
+    {
+      if (!srcContext->readSource ())
+       {
+         status = AE_NOSRC;
+         dbev->error_msg = anno_str (srcContext->get_name ());
+         return NULL;
+       }
+      if (!computeMetrics (dbev, func, mlist, type, false, func_scope, srcContext))
+       {
+         status = AE_OTHER;
+         dbev->error_msg = anno_str ();
+         return NULL;
+       }
+      status = checkTimeStamp (false);
+    }
+  else
+    { // Histable::INSTR
+      Anno_Errors src_status = AE_OK;
+      if (!srcContext->readSource ())
+       {
+         src_status = AE_NOSRC;
+         dbev->error_msg = anno_str (srcContext->get_name ());
+       }
+      if (!setFile ())
+       status = AE_NOLOBJ;
+      else
+       {
+         if (!openStabs ())
+           src_status = AE_NOSTABS;
+         if (!openDisPC ())
+           status = AE_NOSYMTAB;
+       }
+      if (status != AE_OK)
+       {
+         dbev->error_msg = anno_str ();
+         return NULL;
+       }
+      if (src_status != AE_OK && func != NULL)
+       {
+         if (loadobject->platform == Java && (func->flags & FUNC_FLAG_NATIVE) != 0)
+           {
+             append_msg (CMSG_ERROR,
+                         GTXT ("`%s' is a native method; byte code not available\n"),
+                         func->get_name ());
+             status = AE_NOOBJ;
+             dbev->error_msg = anno_str ();
+             return NULL;
+           }
+         func_scope = true;
+       }
+      // get the disassembly-line metric data
+      if (!computeMetrics (dbev, func, mlist, type,
+                          (src_visible & SRC_METRIC) != 0,
+                          func_scope, srcContext))
+       {
+         status = AE_OTHER;
+         dbev->error_msg = anno_str ();
+         return NULL;
+       }
+      status = checkTimeStamp (true);
+    }
+  total = ftotal;
+
+  // initialize line number
+  init_line ();
+
+  // initialize data -- get duplicate metric list for the line texts
+  // pick up the metric list from the computed data
+  MetricList *nmlist = NULL;
+  if (type == Histable::INSTR)
+    {
+      mlist = dis_items->get_metric_list ();
+      nmlist = new MetricList (mlist);
+      data_items = new Hist_data (nmlist, Histable::INSTR, Hist_data::MODL);
+      data_items->set_status (dis_items->get_status ());
+      set_dis_data (func, vis_bits, dbev->get_cmpline_visible (),
+                   src_visible, hex_vis, func_scope,
+                   dbev->get_funcline_visible ());
+    }
+  else
+    {
+      mlist = src_items->get_metric_list ();
+      nmlist = new MetricList (mlist);
+      data_items = new Hist_data (nmlist, Histable::LINE, Hist_data::MODL);
+      data_items->set_status (src_items->get_status ());
+      set_src_data (func_scope ? func : NULL, vis_bits,
+                   dbev->get_cmpline_visible (),
+                   dbev->get_funcline_visible ());
+    }
+  data_items->compute_minmax ();
+
+  Metric *mitem;
+  int index;
+  Hist_data::HistItem *max_item;
+  TValue *value;
+  Hist_data::HistItem *max_item_inc;
+  TValue *value_inc;
+  double dthreshold = threshold / 100.0;
+
+  int sz = data_items->get_metric_list ()->get_items ()->size ();
+  maximum = new TValue[sz];
+  maximum_inc = new TValue[sz];
+  memset (maximum, 0, sizeof (TValue) * sz);
+  memset (maximum_inc, 0, sizeof (TValue) * sz);
+  max_item = data_items->get_maximums ();
+  max_item_inc = data_items->get_maximums_inc ();
+
+  Vec_loop (Metric*, data_items->get_metric_list ()->get_items (), index, mitem)
+  {
+    maximum_inc[index].tag = maximum[index].tag = mitem->get_vtype ();
+
+    if (mitem->get_subtype () == Metric::STATIC)
+      continue;
+    if (!mitem->is_visible () && !mitem->is_tvisible ()
+       && !mitem->is_pvisible ())
+      continue;
+
+    value = &max_item->value[index];
+    value_inc = &max_item_inc->value[index];
+
+    double dthresh;
+    if (mitem->is_zeroThreshold () == true)
+      dthresh = 0;
+    else
+      dthresh = dthreshold;
+    switch (value->tag)
+      {
+      case VT_INT:
+       maximum[index].i = (int) (dthresh * (double) value->i);
+       maximum_inc[index].i = (int) (dthresh * (double) value_inc->i);
+       break;
+      case VT_DOUBLE:
+       maximum[index].d = dthresh * value->d;
+       maximum_inc[index].d = dthresh * value_inc->d;
+       break;
+      case VT_LLONG:
+       maximum[index].ll = (unsigned long long) (dthresh * (double) value->ll);
+       maximum_inc[index].ll = (unsigned long long)
+               (dthresh * (double) value_inc->ll);
+       break;
+      case VT_ULLONG:
+       maximum[index].ull = (unsigned long long)
+               (dthresh * (double) value->ull);
+       maximum_inc[index].ull = (unsigned long long)
+               (dthresh * (double) value_inc->ull);
+       break;
+      default:
+       // not needed for non-numerical metrics
+       break;
+      }
+  }
+
+  // mark all high values
+  for (int index1 = 0; index1 < data_items->size (); index1++)
+    {
+      Hist_data::HistItem *hi = data_items->fetch (index1);
+      int index2;
+      Vec_loop (Metric*, nmlist->get_items (), index2, mitem)
+      {
+       bool mark = false;
+       if (mitem->get_subtype () == Metric::STATIC)
+         continue;
+       if (!mitem->is_visible () && !mitem->is_tvisible ()
+           && !mitem->is_pvisible ())
+         continue;
+
+       switch (hi->value[index2].tag)
+         {
+         case VT_DOUBLE:
+           if (nmlist->get_type () == MET_SRCDIS
+               && data_items->get_callsite_mark ()->get (hi->obj))
+             {
+               if (hi->value[index2].d > maximum_inc[index2].d)
+                 mark = true;
+               break;
+             }
+           if (hi->value[index2].d > maximum[index2].d)
+             mark = true;
+           break;
+         case VT_INT:
+           if (nmlist->get_type () == MET_SRCDIS
+               && data_items->get_callsite_mark ()->get (hi->obj))
+             {
+               if (hi->value[index2].i > maximum_inc[index2].i)
+                 mark = true;
+               break;
+             }
+           if (hi->value[index2].i > maximum[index2].i)
+             mark = true;
+           break;
+         case VT_LLONG:
+           if (nmlist->get_type () == MET_SRCDIS
+               && data_items->get_callsite_mark ()->get (hi->obj))
+             {
+               if (hi->value[index2].ll > maximum_inc[index2].ll)
+                 mark = true;
+               break;
+             }
+           if (hi->value[index2].ll > maximum[index2].ll)
+             mark = true;
+           break;
+         case VT_ULLONG:
+           if (nmlist->get_type () == MET_SRCDIS
+               && data_items->get_callsite_mark ()->get (hi->obj))
+             {
+               if (hi->value[index2].ull > maximum_inc[index2].ull)
+                 mark = true;
+               break;
+             }
+           if (hi->value[index2].ull > maximum[index2].ull)
+             mark = true;
+           break;
+           // ignoring the following cases (why?)
+         case VT_SHORT:
+         case VT_FLOAT:
+         case VT_HRTIME:
+         case VT_LABEL:
+         case VT_ADDRESS:
+         case VT_OFFSET:
+           break;
+         }
+       if (mark)
+         {
+           marks->append (index1);
+           break;
+         }
+      }
+    }
+
+  // mark all high values to marks2d
+  if (marks2d != NULL && marks2d_inc != NULL)
+    {
+      for (int index1 = 0; index1 < data_items->size (); index1++)
+       {
+         Hist_data::HistItem *hi = data_items->fetch (index1);
+         int index2;
+         Vec_loop (Metric*, nmlist->get_items (), index2, mitem)
+         {
+           Metric::SubType subType = mitem->get_subtype ();
+           if (subType == Metric::STATIC)
+             continue;
+           if (!mitem->is_visible () && !mitem->is_tvisible ()
+               && !mitem->is_pvisible ())
+             continue;
+           switch (hi->value[index2].tag)
+             {
+             case VT_DOUBLE:
+               if (nmlist->get_type () == MET_SRCDIS
+                   && data_items->get_callsite_mark ()->get (hi->obj))
+                 {
+                   if (hi->value[index2].d > maximum_inc[index2].d)
+                     {
+                       int_pair_t pair = {index1, index2};
+                       marks2d_inc->append (pair);
+                     }
+                   break;
+                 }
+               if (hi->value[index2].d > maximum[index2].d)
+                 {
+                   int_pair_t pair = {index1, index2};
+                   marks2d->append (pair);
+                 }
+               break;
+             case VT_INT:
+               if (nmlist->get_type () == MET_SRCDIS
+                   && data_items->get_callsite_mark ()->get (hi->obj))
+                 {
+                   if (hi->value[index2].i > maximum_inc[index2].i)
+                     {
+                       int_pair_t pair = {index1, index2};
+                       marks2d_inc->append (pair);
+                     }
+                   break;
+                 }
+               if (hi->value[index2].i > maximum[index2].i)
+                 {
+                   int_pair_t pair = {index1, index2};
+                   marks2d->append (pair);
+                 }
+               break;
+             case VT_LLONG:
+               if (nmlist->get_type () == MET_SRCDIS
+                   && data_items->get_callsite_mark ()->get (hi->obj))
+                 {
+                   if (hi->value[index2].ll > maximum_inc[index2].ll)
+                     {
+                       int_pair_t pair = {index1, index2};
+                       marks2d_inc->append (pair);
+                     }
+                   break;
+                 }
+               if (hi->value[index2].ll > maximum[index2].ll)
+                 {
+                   int_pair_t pair = {index1, index2};
+                   marks2d->append (pair);
+                 }
+               break;
+             case VT_ULLONG:
+               if (nmlist->get_type () == MET_SRCDIS
+                   && data_items->get_callsite_mark ()->get (hi->obj))
+                 {
+                   if (hi->value[index2].ull > maximum_inc[index2].ull)
+                     {
+                       int_pair_t pair = {index1, index2};
+                       marks2d_inc->append (pair);
+                     }
+                   break;
+                 }
+               if (hi->value[index2].ull > maximum[index2].ull)
+                 {
+                   int_pair_t pair = {index1, index2};
+                   marks2d->append (pair);
+                 }
+               break;
+             case VT_SHORT:
+             case VT_FLOAT:
+             case VT_HRTIME:
+             case VT_LABEL:
+             case VT_ADDRESS:
+             case VT_OFFSET:
+               break;
+             }
+         }
+       }
+    }
+
+  // free memory used by Computing & Printing metrics
+  delete[] maximum;
+  delete[] maximum_inc;
+  delete[] empty;
+  maximum = NULL;
+  maximum_inc = NULL;
+  empty = NULL;
+  dbev->warning_msg = anno_str ();
+  return data_items;
+}
+
+Vector<uint64_t> *
+Module::getAddrs (Function *func)
+{
+  uint64_t start_address = func->img_offset;
+  uint64_t end_address = start_address + func->size;
+  int64_t inst_size = 0;
+
+  // initialize "disasm" if necessary
+  if (!openDisPC ())
+    return NULL;
+
+  Vector<uint64_t> *addrs = new Vector<uint64_t>;
+  for (uint64_t inst_address = start_address; inst_address < end_address;)
+    {
+      char *s = disasm->get_disasm (inst_address, end_address, start_address,
+                                   func->img_offset, inst_size);
+      free (s);
+      addrs->append (inst_address - start_address);
+      inst_address += inst_size;
+      if (inst_size == 0)
+       break;
+    }
+  return addrs;
+}
+
+void
+Module::init_line ()
+{
+  // initialize the compiler commentary data
+  cindex = 0;
+  if (comComs != NULL && comComs->size () > 0)
+    cline = comComs->fetch (cindex)->line;
+  else
+    cline = -1;
+
+  sindex = 0;
+  if (src_items && src_items->size () > 0)
+    sline = ((DbeLine*) src_items->fetch (0)->obj)->lineno;
+  else
+    sline = -1;
+
+  dindex = 0;
+  mindex = 0;
+  mline = -1;
+  if (dis_items && dis_items->size () > 0)
+    {
+      daddr = (DbeInstr*) dis_items->fetch (0)->obj;
+
+      // After sorting all HistItems with PCLineFlag appear
+      // at the end of the list. Find the first one.
+      for (mindex = dis_items->size () - 1; mindex >= 0; mindex--)
+       {
+         Hist_data::HistItem *item = dis_items->fetch (mindex);
+         if (!(((DbeInstr*) item->obj)->flags & PCLineFlag))
+           break;
+         mline = (unsigned) (((DbeInstr*) item->obj)->addr);
+       }
+      mindex++;
+    }
+  else
+    daddr = NULL;
+}
+
+void
+Module::set_src_data (Function *func, int vis_bits, int cmpline_visible,
+                     int funcline_visible)
+{
+  Function *curr_func = NULL;
+
+  // start at the top of the file, and loop over all lines in the file (source context)
+  for (curline = 1; curline <= srcContext->getLineCount (); curline++)
+    {
+      // Before writing the line, see if there's compiler commentary to insert
+      if (cline == curline)
+       set_ComCom (vis_bits);
+
+      // Find out if we need to print zero metrics with the line
+      DbeLine *dbeline = srcContext->find_dbeline (NULL, curline);
+      Anno_Types type = AT_SRC_ONLY;
+      if (dbeline->dbeline_func_next)
+       {
+         if (func)
+           for (DbeLine *dl = dbeline->dbeline_func_next; dl; dl = dl->dbeline_func_next)
+             {
+               if (dl->func == func)
+                 {
+                   type = AT_SRC;
+                   break;
+                 }
+             }
+         else
+           type = AT_SRC;
+       }
+
+      if (funcline_visible)
+       { // show red lines
+         // is there a function index line to insert?
+         Function *func_next = NULL;
+         for (DbeLine *dl = dbeline; dl; dl = dl->dbeline_func_next)
+           {
+             Function *f = dl->func;
+             if (f && f->line_first == curline
+                 && f->getDefSrc () == srcContext)
+               {
+                 if (lang_code == Sp_lang_java
+                     && (f->flags & FUNC_FLAG_DYNAMIC))
+                   continue;
+                 if (cur_dbev && cur_dbev->get_path_tree ()->get_func_nodeidx (f))
+                   {
+                     func_next = f;
+                     break;
+                   }
+                 else if (func_next == NULL)
+                   func_next = f;
+               }
+           }
+         if (func_next && curr_func != func_next)
+           {
+             curr_func = func_next;
+             char *func_name = curr_func->get_name ();
+             if (is_fortran () && streq (func_name, NTXT ("MAIN_")))
+               func_name = curr_func->get_match_name ();
+             Hist_data::HistItem *item =
+                     src_items->new_hist_item (curr_func, AT_FUNC, empty);
+             item->value[name_idx].l = dbe_sprintf (GTXT ("<Function: %s>"),
+                                                    func_name);
+             data_items->append_hist_item (item);
+           }
+       } // end of red line
+      set_src (type, dbeline); // add the source line
+    } //  end of loop over source lines
+
+  // See if compiler flags are set; if so, append them
+  if (cmpline_visible && comp_flags)
+    {
+      Hist_data::HistItem *item = src_items->new_hist_item (NULL, AT_EMPTY,
+                                                           empty);
+      item->value[name_idx].l = strdup (NTXT (""));
+      data_items->append_hist_item (item);
+      item = src_items->new_hist_item (NULL, AT_COM, empty);
+      item->value[name_idx].l = dbe_sprintf (GTXT ("Compile flags: %s"),
+                                            comp_flags);
+      data_items->append_hist_item (item);
+    }
+}
+
+void
+Module::set_dis_data (Function *func, int vis_bits, int cmpline_visible,
+                     int src_visible, bool hex_vis, bool func_scope,
+                     int funcline_visible)
+{
+  bool nextFile = false;
+
+  // initialize the source output, if any
+  curline = (srcContext->getLineCount () > 0) ? 1 : -1;
+  if (func)
+    nextFile = srcContext != func->getDefSrc ();
+  curr_inc = srcContext;
+
+  bool src_code = (src_visible & SRC_CODE);
+  Anno_Types src_type = (src_visible & SRC_METRIC) ? AT_SRC : AT_SRC_ONLY;
+
+  char *img_fname = func ? func->img_fname : NULL;
+
+  // Build a new Function list
+  Vector<Function*> *FuncLst = new Vector<Function*>;
+  if (func_scope)
+    {
+      if (func)
+       FuncLst->append (func);
+    }
+  else
+    {
+      for (int i = 0, sz = functions ? functions->size () : 0; i < sz; i++)
+       {
+         Function *fitem = functions->fetch (i);
+         if (fitem != fitem->cardinal ())
+           continue;
+         if (img_fname == NULL)
+           img_fname = fitem->img_fname;
+         if (fitem->img_fname == NULL || strcmp (fitem->img_fname, img_fname))
+           continue;
+         FuncLst->append (fitem);
+       }
+    }
+  if (FuncLst->size () == 0)
+    { // no function is good
+      delete FuncLst;
+      return;
+    }
+  cmpSrcContext = srcContext;
+  FuncLst->sort (func_cmp);
+
+  disasm->set_hex_visible (hex_vis);
+  for (int index = 0, sz = FuncLst->size (); index < sz; index++)
+    {
+      Function *fitem = FuncLst->fetch (index);
+      uint64_t start_address, end_address;
+      int64_t inst_size;
+      if (fitem->getDefSrc () != srcContext && curline > 0)
+       {
+         // now flush the left source line, if available
+         for (; curline <= srcContext->getLineCount (); curline++)
+           {
+             // see if there's a compiler comment line to dump
+             if (cline == curline)
+               set_ComCom (vis_bits);
+             if (src_code)
+               set_src (src_type, srcContext->find_dbeline (curline));
+           }
+         curline = -1;
+       }
+
+      curr_inc = NULL;
+      // disassemble one function
+      start_address = objStabs ?
+             objStabs->mapOffsetToAddress (fitem->img_offset) : 0;
+      end_address = start_address + fitem->size;
+      inst_size = 0;
+
+      disasm->set_addr_end (end_address);
+      if ((loadobject->flags & SEG_FLAG_DYNAMIC)
+          && loadobject->platform != Java)
+       disasm->set_img_name (img_fname);
+
+      for (uint64_t inst_address = start_address; inst_address < end_address;)
+       {
+         uint64_t address = inst_address - start_address;
+         DbeInstr *instr = fitem->find_dbeinstr (0, address);
+         DbeLine *dbeline = (DbeLine *) (instr->convertto (Histable::LINE));
+         if (instr->lineno == -1 && dbeline && dbeline->lineno > 0)
+           instr->lineno = dbeline->lineno;
+
+         // now write the unannotated source line, if available
+         if (curline > 0)
+           { // source is present
+             int lineno = curline - 1;
+             if (instr->lineno != -1)
+               {
+                 if (dbeline && streq (dbeline->sourceFile->get_name (),
+                                       srcContext->get_name ()))
+                   lineno = instr->lineno;
+               }
+             else if (curr_inc == NULL && srcContext == fitem->def_source
+                      && fitem->line_first > 0)
+               lineno = fitem->line_first;
+
+             for (; curline <= lineno; curline++)
+               {
+                 // see if there's a compiler comment line to dump
+                 if (cline == curline)
+                   set_ComCom (vis_bits);
+                 if (mline == curline)
+                   set_MPSlave ();
+                 if (src_code)
+                   set_src (src_type, srcContext->find_dbeline (curline));
+                 if (curline >= srcContext->getLineCount ())
+                   {
+                     curline = -1;
+                     break;
+                   }
+               }
+           }
+
+         if (funcline_visible)
+           { // show red lines
+             if (!curr_inc || (dbeline && curr_inc != dbeline->sourceFile))
+               {
+                 Hist_data::HistItem *item = dis_items->new_hist_item (dbeline, AT_FUNC, empty);
+                 curr_inc = dbeline ? dbeline->sourceFile : srcContext;
+                 char *str;
+                 if (curr_inc != srcContext)
+                   {
+                     char *fileName = curr_inc->dbeFile->getResolvedPath ();
+                     str = dbe_sprintf (GTXT ("<Function: %s, instructions from source file %s>"),
+                                        fitem->get_name (), fileName);
+                   }
+                 else
+                   str = dbe_sprintf (GTXT ("<Function: %s>"),
+                                      fitem->get_name ());
+                 item->value[name_idx].l = str;
+                 data_items->append_hist_item (item);
+               }
+           }
+
+         char *dis_str = get_disasm (inst_address, end_address, start_address,
+                                     fitem->img_offset, inst_size);
+         if (inst_size == 0)
+           break;
+         else if (instr->size == 0)
+           instr->size = (unsigned int) inst_size;
+         inst_address += inst_size;
+
+         // stomp out control characters
+         for (size_t i = 0, len = strlen (dis_str); i < len; i++)
+           {
+             if (dis_str[i] == '\t')
+               dis_str[i] = ' ';
+           }
+
+         for (int i = 0; i < bTargets.size (); i++)
+           {
+             target_info_t *bTarget = bTargets.fetch (i);
+             if (bTarget->offset == fitem->img_offset + address)
+               {
+                 // insert a new line for the bTarget
+                 size_t colon = strcspn (dis_str, NTXT (":"));
+                 char *msg = GTXT ("*  <branch target>");
+                 size_t len = colon + strlen (msg);
+                 len = (len < 50) ? (50 - len) : 1;
+                 char *new_dis_str = dbe_sprintf ("%.*s%s%*c  <===----<<<",
+                                                  (int) colon, dis_str, msg,
+                                                  (int) len, ' ');
+                 DbeInstr *bt = fitem->find_dbeinstr (PCTrgtFlag, address);
+                 bt->lineno = instr->lineno;
+                 bt->size = 0;
+                 set_dis (bt, AT_DIS, nextFile, new_dis_str);
+                 break;
+               }
+           }
+
+         // AnalyzerInfo/Datatype annotations
+         if (infoList != NULL)
+           {
+             inst_info_t *info = NULL;
+             int pinfo;
+             Vec_loop (inst_info_t*, infoList, pinfo, info)
+             {
+               if (info->offset == fitem->img_offset + address) break;
+             }
+             if (info != NULL)
+               { // got a matching memop
+                 char typetag[400];
+                 typetag[0] = '\0';
+                 long t;
+                 datatype_t *dtype = NULL;
+                 Vec_loop (datatype_t*, datatypes, t, dtype)
+                 {
+                   if (dtype->datatype_id == info->memop->datatype_id)
+                     break;
+                 }
+                 if (datatypes != NULL)
+                   {
+                     size_t len = strlen (typetag);
+                     if (dtype == NULL || t == datatypes->size ())
+                       snprintf (typetag + len, sizeof (typetag) - len, "%s",
+                                 PTXT (DOBJ_UNSPECIFIED));
+                     else if (dtype->dobj == NULL)
+                       snprintf (typetag + len, sizeof (typetag) - len, "%s",
+                                 PTXT (DOBJ_UNDETERMINED));
+                     else
+                       snprintf (typetag + len, sizeof (typetag) - len, "%s",
+                                 dtype->dobj->get_name ());
+                   }
+                 if (strlen (typetag) > 1)
+                   {
+                     char *new_dis_str;
+                     new_dis_str = dbe_sprintf ("%-50s  %s", dis_str, typetag);
+                     free (dis_str);
+                     dis_str = new_dis_str;
+                   }
+               }
+           }
+         set_dis (instr, AT_DIS, nextFile, dis_str);
+       }
+    }
+
+  // now flush the left source line, if available
+  if (curline > 0)
+    { // source is present
+      for (; curline <= srcContext->getLineCount (); curline++)
+       {
+         // see if there's a compiler comment line to dump
+         if (cline == curline)
+           set_ComCom (vis_bits);
+
+         if (src_code)
+           set_src (src_type, srcContext->find_dbeline (curline));
+       }
+    }
+
+  // See if compiler flags are set; if so, append them
+  if (cmpline_visible && comp_flags)
+    {
+      Hist_data::HistItem *item = dis_items->new_hist_item (NULL, AT_EMPTY,
+                                                           empty);
+      item->value[name_idx].l = dbe_strdup (NTXT (""));
+      data_items->append_hist_item (item);
+      item = dis_items->new_hist_item (NULL, AT_COM, empty);
+      item->value[name_idx].l = dbe_sprintf (GTXT ("Compile flags: %s"),
+                                            comp_flags);
+      data_items->append_hist_item (item);
+    }
+  delete FuncLst;
+}
+
+// set_src -- inserts one or more lines into the growing data list
+void
+Module::set_src (Anno_Types type, DbeLine *dbeline)
+{
+  Hist_data::HistItem *item;
+
+  // Flush items that are not represented in source
+  while (sline >= 0 && sline < curline)
+    {
+      item = src_items->fetch (sindex);
+      if (((DbeLine*) item->obj)->lineno > 0)
+       set_one (item, AT_QUOTE, item->obj->get_name ());
+
+      if (++sindex < src_items->size ()) // get next line with metrics
+       sline = ((DbeLine*) src_items->fetch (sindex)->obj)->lineno;
+      else
+       sline = -1;
+    }
+
+  //  write values in the metric fields for the given source line
+  if (curline == sline)
+    { // got metrics for this line
+      item = src_items->fetch (sindex);
+      if (((DbeLine*) item->obj)->lineno > 0)
+       set_one (item, AT_SRC, srcContext->getLine (curline));
+
+      if (++sindex < src_items->size ()) // get next line metric index
+       sline = ((DbeLine*) src_items->fetch (sindex)->obj)->lineno;
+      else
+       sline = -1;
+    }
+  else
+    {
+      item = data_items->new_hist_item (dbeline, type, empty);
+      if (size_index != -1)
+       item->value[size_index].ll = dbeline->get_size ();
+      if (addr_index != -1)
+       item->value[addr_index].ll = dbeline->get_addr ();
+      item->value[name_idx].l = dbe_strdup (srcContext->getLine (curline));
+      data_items->append_hist_item (item);
+    }
+}
+
+void
+Module::set_dis (DbeInstr *instr, Anno_Types type, bool nextFile, char *dis_str)
+{
+  // Flush items that are not represented in disassembly
+  while (daddr && daddr->pc_cmp (instr) < 0)
+    {
+      if (!nextFile)
+       set_one (dis_items->fetch (dindex), AT_QUOTE, daddr->get_name ());
+      if (++dindex < dis_items->size ()) // get next line metric index
+       daddr = (DbeInstr*) dis_items->fetch (dindex)->obj;
+      else
+       daddr = NULL;
+    }
+
+  // Write values in the metric fields for the given pc index value
+  if (instr->inlinedInd >= 0)
+    {
+      StringBuilder sb;
+      sb.append (dis_str);
+      instr->add_inlined_info (&sb);
+      free (dis_str);
+      dis_str = sb.toString ();
+    }
+  if (daddr && daddr->pc_cmp (instr) == 0)
+    {
+      Hist_data::HistItem *item = data_items->new_hist_item (instr, type,
+                                             dis_items->fetch (dindex)->value);
+      item->value[name_idx].tag = VT_LABEL;
+      item->value[name_idx].l = dis_str;
+      data_items->append_hist_item (item);
+      if (dis_items->get_callsite_mark ()->get (dis_items->fetch (dindex)->obj))
+       data_items->get_callsite_mark ()->put (item->obj, 1);
+
+      if (++dindex < dis_items->size ()) // get next line metric index
+       daddr = (DbeInstr*) dis_items->fetch (dindex)->obj;
+      else
+       daddr = NULL;
+    }
+  else
+    {
+      // create a new item for this PC
+      Hist_data::HistItem *item = dis_items->new_hist_item (instr, type, empty);
+      if (size_index != -1)
+       item->value[size_index].ll = instr->size;
+      if (addr_index != -1)
+       item->value[addr_index].ll = instr->get_addr ();
+      item->value[name_idx].tag = VT_LABEL;
+      item->value[name_idx].l = dis_str;
+      data_items->append_hist_item (item);
+    }
+}
+
+void
+Module::set_MPSlave ()
+{
+  Hist_data::HistItem *item;
+  Function *fp;
+  int index;
+
+  // write the inclusive metrics for slave threads
+  while (mline == curline)
+    {
+      item = dis_items->fetch (mindex);
+      DbeInstr *instr = (DbeInstr *) item->obj;
+      Vec_loop (Function*, functions, index, fp)
+      {
+       if (fp->derivedNode == instr)
+         {
+           set_one (item, AT_QUOTE, (fp->isOutlineFunction) ?
+                    GTXT ("<inclusive metrics for outlined functions>") :
+                    GTXT ("<inclusive metrics for slave threads>"));
+           break;
+         }
+      }
+
+      mindex++;
+      if (mindex < dis_items->size ())
+       mline = (unsigned) ((DbeInstr*) (dis_items->fetch (mindex)->obj))->addr;
+      else
+       mline = -1;
+    }
+}//set_MPSlave
+
+void
+Module::set_one (Hist_data::HistItem *org_item, Anno_Types type,
+                const char *text)
+{
+  if (org_item == NULL)
+    return;
+  Hist_data::HistItem *item = data_items->new_hist_item (org_item->obj, type,
+                                                        org_item->value);
+  item->value[name_idx].tag = VT_LABEL;
+  item->value[name_idx].l = dbe_strdup (text);
+  data_items->append_hist_item (item);
+  if (org_item != NULL && src_items != NULL
+      && src_items->get_callsite_mark ()->get (org_item->obj))
+    data_items->get_callsite_mark ()->put (item->obj, 1);
+}//set_one
+
+void
+Module::set_ComCom (int vis_bits)
+{
+  Hist_data::HistItem *item;
+  Function *func = dbeSession->get_Unknown_Function ();
+
+  if (vis_bits)
+    {
+      // precede the compiler commentary with a blank line
+      item = data_items->new_hist_item (func, AT_EMPTY, empty);
+      item->value[name_idx].l = dbe_strdup (NTXT (""));
+      data_items->append_hist_item (item);
+    }
+  while (cline == curline)
+    {
+      ComC *comm = comComs->fetch (cindex);
+      if (comm->visible & vis_bits)
+       {
+         // write the compiler commentary
+         item = data_items->new_hist_item (func, AT_COM, empty);
+         item->value[name_idx].l = dbe_strdup (comm->com_str);
+         data_items->append_hist_item (item);
+       }
+      if (++cindex < comComs->size ())
+       cline = comComs->fetch (cindex)->line;
+      else
+       cline = -1;
+    }
+}
+
+void
+Module::dump_dataobjects (FILE *out)
+{
+  int index;
+  datatype_t *dtype;
+  Vec_loop (datatype_t*, datatypes, index, dtype)
+  {
+    fprintf (out, NTXT ("[0x%08X,%6lld] %4d %6d %s "), dtype->datatype_id,
+            dtype->dobj ? dtype->dobj->id : 0LL,
+            dtype->memop_refs, dtype->event_data,
+            (dtype->dobj != NULL ? (dtype->dobj->get_name () ?
+                dtype->dobj->get_name () : "<NULL>") : "<no object>"));
+#if DEBUG
+    Histable* scope = dtype->dobj ? dtype->dobj->get_scope () : NULL;
+    if (scope != NULL)
+      {
+       switch (scope->get_type ())
+         {
+         case Histable::LOADOBJECT:
+         case Histable::FUNCTION:
+           fprintf (out, NTXT ("%s"), scope->get_name ());
+           break;
+         case Histable::MODULE:
+           {
+             char *filename = get_basename (scope->get_name ());
+             fprintf (out, NTXT ("%s"), filename);
+             break;
+           }
+         default:
+           fprintf (out, NTXT ("\tUnexpected scope %d:%s"),
+                    scope->get_type (), scope->get_name ());
+         }
+      }
+#endif
+    fprintf (out, NTXT ("\n"));
+  }
+}
+
+void
+Module::set_name (char *str)
+{
+  free (name);
+  name = str;
+}
+
+void
+Module::read_hwcprof_info ()
+{
+  if (hwcprof == 0)
+    {
+      hwcprof = 1;
+      Stabs *stabs = openDebugInfo ();
+      if (stabs)
+       stabs->read_hwcprof_info (this);
+    }
+}
+
+void
+Module::reset_datatypes ()
+{
+  for (int i = 0, sz = datatypes ? datatypes->size () : -1; i < sz; i++)
+    {
+      datatype_t *t = datatypes->fetch (i);
+      t->event_data = 0;
+    }
+}
+
+DataObject *
+Module::get_dobj (uint32_t dtype_id)
+{
+  read_hwcprof_info ();
+  for (int i = 0, sz = datatypes ? datatypes->size () : -1; i < sz; i++)
+    {
+      datatype_t *t = datatypes->fetch (i);
+      if (t->datatype_id == dtype_id)
+       {
+         t->event_data++;
+         return t->dobj;
+       }
+    }
+  return NULL;
+}
+
+int
+Module::readFile ()
+{
+  return AE_OK;
+}
+
+Vector<Histable*> *
+Module::get_comparable_objs ()
+{
+  update_comparable_objs ();
+  if (comparable_objs || dbeSession->expGroups->size () <= 1 || loadobject == NULL)
+    return comparable_objs;
+  Vector<Histable*> *comparableLoadObjs = loadobject->get_comparable_objs ();
+  if (comparableLoadObjs == NULL)
+    return NULL;
+  comparable_objs = new Vector<Histable*>(comparableLoadObjs->size ());
+  for (int i = 0, sz = comparableLoadObjs->size (); i < sz; i++)
+    {
+      Module *mod = NULL;
+      LoadObject *lo = (LoadObject*) comparableLoadObjs->fetch (i);
+      if (lo)
+       {
+         mod = lo->get_comparable_Module (this);
+         if (mod)
+           mod->comparable_objs = comparable_objs;
+       }
+      comparable_objs->store (i, mod);
+    }
+  dump_comparable_objs ();
+  return comparable_objs;
+}
+
+JMethod *
+Module::find_jmethod (const char *nm, const char *sig)
+{
+  // Vladimir: Probably we should not use linear search
+  for (long i = 0, sz = VecSize (functions); i < sz; i++)
+    {
+      JMethod *jmthd = (JMethod*) functions->get (i);
+      char *jmt_name = jmthd->get_name (Histable::SHORT);
+      if (strcmp (jmt_name, nm) == 0
+         && strcmp (jmthd->get_signature (), sig) == 0)
+       return jmthd;
+    }
+  return NULL;
+}
diff --git a/gprofng/src/Module.h b/gprofng/src/Module.h
new file mode 100644 (file)
index 0000000..39c4322
--- /dev/null
@@ -0,0 +1,284 @@
+/* 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 _MODULE_H
+#define _MODULE_H
+
+// A Module object represents a .o file that was used to build up a segement.
+//     Its main function is to compute source and disassembly annotations
+// Text reordering and/or function outlining imply that a module may
+//     not be contiguous.
+
+#include "Histable.h"
+#include "Hist_data.h"
+
+#define MOD_FLAG_UNKNOWN 0x01
+
+class LoadObject;
+class MetricList;
+class ComC;
+class Disasm;
+class Hist_data;
+class Stabs;
+class SourceFile;
+class DataObject;
+class JMethod;
+template <class ITEM> class Vector;
+
+class InlinedSubr
+{
+public:
+  InlinedSubr ();
+  DbeLine *dbeLine;
+  Function *func;
+  char *fname;
+  uint64_t low_pc;
+  uint64_t high_pc;
+  int level;
+
+  bool
+  contains (InlinedSubr *p)
+  {
+    return low_pc <= p->low_pc && high_pc >= p->high_pc;
+  }
+
+  bool
+  contains (uint64_t pc)
+  {
+    return low_pc <= pc && high_pc > pc;
+  }
+};
+
+class Module : public HistableFile
+{
+public:
+  // Annotated Source or Disassembly
+  enum Anno_Errors
+  {
+    AE_OK,
+    AE_NOTREAD,
+    AE_NOSRC,
+    AE_NOOBJ,
+    AE_NOLOBJ,
+    AE_NOSTABS,
+    AE_NOSYMTAB,
+    AE_TIMESRC,
+    AE_TIMEDIS,
+    AE_TIMESTABS,
+    AE_TIMESTABS_DIFF,
+    AE_OTHER
+  };
+
+  // The following enums are duplicated in Java
+  enum Anno_Types
+  {
+    AT_LIST = 0,
+    AT_SRC,
+    AT_SRC_ONLY,
+    AT_DIS,
+    AT_COM,
+    AT_QUOTE,
+    AT_FUNC,
+    AT_EMPTY,
+    AT_DIS_ONLY
+  };
+
+  Module ();
+  virtual ~Module ();
+  virtual int64_t get_size ();
+  virtual void set_name (char *str);
+  virtual Vector<Histable*> *get_comparable_objs ();
+  virtual int readFile ();
+
+  virtual Histable_type
+  get_type ()
+  {
+    return MODULE;
+  }
+
+  inline Anno_Errors
+  get_status ()
+  {
+    return status;
+  }
+
+  inline void
+  set_file_name (char *fnm)
+  {
+    free (file_name);
+    file_name = fnm;
+  }
+
+  // get error string
+  char *anno_str (char *fnm = NULL);
+
+  // generate annotated source/disassembly data
+  Hist_data *get_data (DbeView *dbev, MetricList *mlist,
+                      Histable::Type type, TValue *ftotal, SourceFile *srcFile,
+                      Function *func, Vector<int> *marks, int threshold,
+                      int vis_bits, int src_visible, bool hex_visible,
+                      bool func_scope, bool src_only,
+                      Vector<int_pair_t> *marks2d = NULL,
+                      Vector<int_pair_t> *marks2d_inc = NULL);
+
+  Vector<uint64_t> *getAddrs (Function *func);
+  SourceFile *setIncludeFile (char *includeFile);
+
+  SourceFile *
+  getIncludeFile ()
+  {
+    return curr_inc;
+  }
+
+  SourceFile *
+  getMainSrc ()
+  {
+    return main_source;
+  }
+
+  char *
+  getResolvedObjectPath ()
+  {
+    return stabsPath ? stabsPath : get_name ();
+  }
+
+  char *
+  getDebugPath ()
+  {
+    setFile ();
+    return stabsPath;
+  }
+
+  void read_stabs (bool all = true);
+  void dump_dataobjects (FILE *out);
+  DataObject *get_dobj (uint32_t dtype_id);
+  void reset_datatypes ();
+  void read_hwcprof_info ();
+  bool is_fortran ();
+  SourceFile *findSource (const char *fname, bool create);
+  bool openStabs (bool all = true);
+  LoadObject *createLoadObject (const char *lo_name);
+  JMethod *find_jmethod (const char *nm, const char *sig);
+
+  unsigned int flags;               // flags used for marking traversals
+  Sp_lang_code lang_code;           // What is source lang. in module
+  char *file_name;                  // Full path to actual source file
+  Vector<Function*> *functions;     // Unordered list of functions
+  LoadObject *loadobject;           // Parent loadobject
+  LoadObject *dot_o_file;           // The .o file with debug information
+  unsigned fragmented;              // -xF used when compiling module
+  int real_timestamp;               // Linked timestamp from N_OPT stab
+  int curr_timestamp;               // Current object timestamp from N_OPT stab
+  char *comp_flags;                 // compiler flags used to compile module
+  char *comp_dir;                   // directory used to compile module
+  char *linkerStabName;             // Name from 'N_UNDF' stab
+  Stabs *objStabs;                  // stabs of object file
+  bool readStabs;
+  bool hasStabs;
+  bool hasDwarf;
+  uint64_t hdrOffset;               // offset in .debug_info
+  unsigned hwcprof;                 // hwcprof info status
+  Vector<inst_info_t*> *infoList;   // merged list
+  Vector<memop_info_t*> ldMemops;   // load instructions
+  Vector<memop_info_t*> stMemops;   // store instructions
+  Vector<memop_info_t*> pfMemops;   // prefetch instructions
+  Vector<target_info_t*> bTargets;  // branch targets
+  Vector<datatype_t*> *datatypes;   // object type descriptors
+  Vector<SourceFile*> *includes;
+  Module *indexStabsLink;           // correspondent module for the .o file
+  InlinedSubr *inlinedSubr;
+
+protected:
+  void removeStabsTmp (); // Remove temporary *.o (got from *.a)
+
+  // Check timestamp, warn users if src/dis/stabs later than exp.
+  Anno_Errors checkTimeStamp (bool chkDis);
+
+  // Set paths for reading Stabs and Symbols
+  bool read_ar (int ar, int obj, char *obj_base);
+  bool setFile ();
+
+  // Open appropriate symbol tables, construct set of PC ranges,
+  //   and maps to source lines for each PC
+  Stabs *openDebugInfo ();
+
+  // Construct PC index table
+  bool openDisPC ();
+
+  // Compute data--scan data to compute metrics per-src-line/dis-line
+  bool computeMetrics (DbeView *dbev, Function *func, MetricList *mlist,
+                      Histable::Type type, bool src_metric,
+                      bool func_scope, SourceFile *source);
+  void init_line ();
+  void init_index (Hist_data *witems, int &wlindex, int &wmsize, int &wmindex);
+
+  void set_src_data (Function *func, int vis_bits, int cmpline_visible,
+                    int funcline_visible);
+  void set_dis_data (Function *func, int vis_bits, int cmpline_visible,
+                    int src_visible, bool hex_vis, bool func_scope,
+                    int funcline_visible);
+  void set_src (Anno_Types type, DbeLine *dbeline);
+  void set_dis (DbeInstr *instr, Anno_Types type, bool nextFile, char *dis_str);
+  void set_MPSlave ();
+  void set_one (Hist_data::HistItem *org_item, Anno_Types type, const char *text);
+  void set_ComCom (int vis_bits);
+
+  virtual char *get_disasm (uint64_t inst_address, uint64_t end_address,
+                           uint64_t start_address, uint64_t f_offset,
+                           int64_t &inst_size);
+
+  Anno_Errors status;
+  Anno_Errors openSourceFlag;
+  bool hexVisible;          // show hex code in disasm
+  time_t disMTime;          // Creating time for disassembly
+  time_t stabsMTime;        // Creating time for stabs
+  SourceFile *main_source;
+  SourceFile *curr_inc;     // pointer to include file or NULL
+  SourceFile *srcContext;
+  Vector<ComC*> *comComs;   // table of compiler comments
+  Disasm *disasm;
+  Hist_data *src_items;
+  Hist_data *dis_items;
+  Hist_data *data_items;
+  DbeView * cur_dbev;
+  TValue *total;
+  TValue *maximum;
+  TValue *maximum_inc;
+  TValue *empty;
+  int name_idx;         // index of name metric in list for src/dis
+  int size_index;       // index of size metric in list for src/dis
+  int addr_index;       // index of address metric in list for src/dis
+
+  int curline;          // line# of next source line to be processed
+  int cindex, cline;    // index and src line of next compiler-comment
+  int sindex, sline;    // index and src line of next item in src_items
+  int dindex;
+  DbeInstr *daddr;      // pointer to next DbeInstr with metrics
+  int mindex;           // MP index and src line of next metric-value
+  int mline;            // MP line to be processed by source
+
+  char *disPath;        // path for disassembly
+  char *stabsPath;      // path for reading stabs
+  char *stabsTmp;       // temporary *.o from *.a
+  char *disName;        // library/path for disassembly
+  char *stabsName;      // library/path for stabs
+};
+
+#endif /* _MODULE_H */
diff --git a/gprofng/src/Ovw_data.cc b/gprofng/src/Ovw_data.cc
new file mode 100644 (file)
index 0000000..2cd5718
--- /dev/null
@@ -0,0 +1,242 @@
+/* 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 <memory.h>
+#include <values.h>
+#include <assert.h>
+#include "Data_window.h"
+#include "Exp_Layout.h"
+#include "Table.h"
+#include "Ovw_data.h"
+#include "Sample.h"
+#include "data_pckts.h"
+#include "util.h"
+#include "i18n.h"
+
+void
+Ovw_data::sum (Ovw_data *data)
+{
+  Ovw_item data_totals = data->get_totals ();
+  if (totals == NULL)
+    {
+      totals = reset_item (new Ovw_item);
+      *totals = data_totals;
+      totals->start.tv_sec = totals->end.tv_sec = -1;
+      totals->start.tv_nsec = totals->end.tv_nsec = 0;
+    }
+  else
+    {
+      tsadd (&totals->duration, &data_totals.duration);
+      tsadd (&totals->tlwp, &data_totals.tlwp);
+      if (tstodouble (totals->duration) != 0)
+       totals->nlwp = tstodouble (totals->tlwp) / tstodouble (totals->duration);
+
+      for (int i = 0, size = totals->size; i < size; i++)
+       tsadd (&totals->values[i].t, &data_totals.values[i].t);
+    }
+}
+
+Ovw_data::Ovw_item *
+Ovw_data::reset_item (Ovw_data::Ovw_item *item)
+{
+  memset (item, 0, sizeof (*item));
+  return item;
+}
+
+Ovw_data::Ovw_item
+Ovw_data::get_totals ()
+{
+  // This routine will return the totals values for item in the sample.
+  // Compute maximums and totals only once, and save the result.
+  // On subsequent calls, just return the saved result.
+  // If maximums is NULL, then totals is also NULL
+  if (totals != NULL)
+    return *totals;
+
+  timestruc_t zero = {0, 0};
+  totals = reset_item (new Ovw_item);
+  totals->start.tv_sec = MAXINT; // new
+  totals->start.tv_nsec = MAXINT; // new
+  totals->start_label = totals->end_label = NTXT ("Total");
+  totals->type = VT_HRTIME;
+
+  int nsampsel = 0;
+  for (int index = 0; index < size (); index++)
+    {
+      Ovw_item item = fetch (index);
+      nsampsel++;
+
+      // Compute totals
+      for (int i = 0; i < OVW_NUMVALS + 1; i++)
+       tsadd (&totals->values[i].t, &item.values[i].t);
+
+      int_max (&totals->states, item.states);
+      tsadd (&totals->total.t, &item.total.t);
+      int_max (&totals->size, item.size);
+      tsadd (&totals->duration, &item.duration);
+      tsadd (&totals->tlwp, &item.tlwp);
+      totals->number += item.number;
+      if (tscmp (&totals->start, &item.start) > 0)
+       totals->start = item.start;
+      if (tscmp (&totals->end, &item.end) < 0)
+       totals->end = item.end;
+    }
+
+  if (totals->start.tv_sec == MAXINT && totals->start.tv_nsec == MAXINT)
+    totals->start = zero;
+  totals->nlwp = tstodouble (totals->tlwp) / tstodouble (totals->duration);
+
+  if (nsampsel == 0)
+    {
+      totals->size = OVW_NUMVALS + 1;
+      totals->start.tv_sec = totals->end.tv_sec = -1;
+      totals->start.tv_nsec = totals->end.tv_nsec = 0;
+      totals->nlwp = -1;
+    }
+  return *totals;
+}
+
+Ovw_data::Ovw_item
+Ovw_data::get_labels ()
+{
+  Ovw_item ovw_item;
+  Value *values;
+  memset (&ovw_item, 0, sizeof (Ovw_item));
+  values = &ovw_item.values[0];
+
+  char *stateUNames[/*LMS_NUM_STATES*/] = LMS_STATE_USTRINGS;
+  values[0].l = dbe_strdup (GTXT ("Leftover"));
+  values[OVW_LMS_USER + 1].l = stateUNames[LMS_USER];
+  values[OVW_LMS_SYSTEM + 1].l = stateUNames[LMS_SYSTEM];
+  values[OVW_LMS_WAIT_CPU + 1].l = stateUNames[LMS_WAIT_CPU];
+  values[OVW_LMS_USER_LOCK + 1].l = stateUNames[LMS_USER_LOCK];
+  values[OVW_LMS_TFAULT + 1].l = stateUNames[LMS_TFAULT];
+  values[OVW_LMS_DFAULT + 1].l = stateUNames[LMS_DFAULT];
+  values[OVW_LMS_KFAULT + 1].l = stateUNames[LMS_KFAULT];
+  values[OVW_LMS_SLEEP + 1].l = stateUNames[LMS_SLEEP];
+  values[OVW_LMS_STOPPED + 1].l = stateUNames[LMS_STOPPED];
+  values[OVW_LMS_TRAP + 1].l = stateUNames[LMS_TRAP];
+
+  ovw_item.size = OVW_NUMVALS + 1;
+  ovw_item.states = 0;
+  ovw_item.type = VT_LABEL;
+  return ovw_item;
+}
+
+Ovw_data::Ovw_data ()
+{
+  packets = NULL;
+  ovw_items = new Vector<Ovw_item*>;
+  totals = NULL;
+}
+
+Ovw_data::Ovw_data (DataView *_packets, hrtime_t exp_start)
+{
+  packets = _packets;
+  ovw_items = new Vector<Ovw_item*>;
+  totals = NULL;
+  long npackets = packets->getSize ();
+  for (long index = 0; index < npackets; index++)
+    {
+      Ovw_item *ovw_item = new Ovw_item;
+      memset (ovw_item, 0, sizeof (Ovw_item));
+      Sample *sample = (Sample*) packets->getObjValue (PROP_SMPLOBJ, index);
+      extract_data (ovw_item, sample);
+      hr2timestruc (&ovw_item->start, sample->get_start_time () - exp_start);
+      hr2timestruc (&ovw_item->end, sample->get_end_time () - exp_start);
+      //  No need to check for duration, as duration has to be > 0.
+      //  If not, it would have been found out in yyparse.
+      tssub (&ovw_item->duration, &ovw_item->end, &ovw_item->start);
+      ovw_item->number = sample->get_number ();
+      ovw_item->start_label = sample->get_start_label ();
+      ovw_item->end_label = sample->get_end_label ();
+
+      int size = ovw_item->size;
+      for (int j = 0; j < size; j++)
+       tsadd (&ovw_item->tlwp, &ovw_item->values[j].t);
+      if (tstodouble (ovw_item->duration) != 0)
+       ovw_item->nlwp = tstodouble (ovw_item->tlwp) /
+               tstodouble (ovw_item->duration);
+      ovw_items->append (ovw_item);
+    }
+}
+
+Ovw_data::~Ovw_data ()
+{
+  ovw_items->destroy ();
+  delete ovw_items;
+  delete totals;
+}
+
+void
+Ovw_data::extract_data (Ovw_data::Ovw_item *ovw_item, Sample *sample)
+{
+  // This routine break out the data in "data" into buckets in "ovw_item"
+  int index;
+  int states;
+  timestruc_t sum, rtime;
+  timestruc_t zero = {0, 0};
+  Value *values;
+  PrUsage *prusage = sample->get_usage ();
+  if (prusage == NULL)
+    prusage = new PrUsage;
+
+  values = &ovw_item->values[0];
+  hr2timestruc (&values[OVW_LMS_USER + 1].t, prusage->pr_utime);
+  hr2timestruc (&values[OVW_LMS_SYSTEM + 1].t, prusage->pr_stime);
+  hr2timestruc (&values[OVW_LMS_WAIT_CPU + 1].t, prusage->pr_wtime);
+  hr2timestruc (&values[OVW_LMS_USER_LOCK + 1].t, prusage->pr_ltime);
+  hr2timestruc (&values[OVW_LMS_TFAULT + 1].t, prusage->pr_tftime);
+  hr2timestruc (&values[OVW_LMS_DFAULT + 1].t, prusage->pr_dftime);
+  hr2timestruc (&values[OVW_LMS_TRAP + 1].t, prusage->pr_ttime);
+  hr2timestruc (&values[OVW_LMS_KFAULT + 1].t, prusage->pr_kftime);
+  hr2timestruc (&values[OVW_LMS_SLEEP + 1].t, prusage->pr_slptime);
+  hr2timestruc (&values[OVW_LMS_STOPPED + 1].t, prusage->pr_stoptime);
+  ovw_item->size = OVW_NUMVALS + 1;
+
+  //XXX: Compute values[0] as rtime - sum_of(other_times)
+  sum = zero;
+  states = 0;
+  for (index = 1; index < ovw_item->size; index++)
+    {
+      if (values[index].t.tv_sec != 0 || values[index].t.tv_nsec != 0)
+       states++;
+      tsadd (&sum, &values[index].t);
+    }
+
+  //  If the sum of all times is greater than rtime then adjust
+  //  rtime to be equal to sum and also adjust the pr_rtime field
+  hr2timestruc (&rtime, prusage->pr_rtime);
+  if (tscmp (&sum, &rtime) > 0)
+    {
+      ovw_item->total.t = sum;
+      values[0].t = zero;
+    }
+  else
+    {
+      ovw_item->total.t = rtime;
+      tssub (&rtime, &rtime, &sum);
+      tsadd (&values[0].t, &rtime);
+      states++;
+    }
+  ovw_item->type = VT_HRTIME;
+  ovw_item->states = states;
+}
diff --git a/gprofng/src/Ovw_data.h b/gprofng/src/Ovw_data.h
new file mode 100644 (file)
index 0000000..0c3372c
--- /dev/null
@@ -0,0 +1,102 @@
+/* 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 _OVW_DATA_H
+#define _OVW_DATA_H
+
+// An Ovw_data object is used to supply data for constructing an overview
+// display.
+
+#include "dbe_structs.h"
+
+class Sample;
+class DataView;
+
+class Ovw_data
+{
+public:
+
+  enum OVW_LMS_STORAGE
+  {// in display order, not LMS_* order
+    // Note: use same display order of LMS_* in: er.rc, TimelineVariable.java,
+    // Ovw_data.h, BaseMetricTreeNode.cc and Experiment.cc metric registration
+    OVW_LMS_USER,
+    OVW_LMS_SYSTEM,
+    OVW_LMS_TRAP,
+    OVW_LMS_USER_LOCK,
+    OVW_LMS_DFAULT,
+    OVW_LMS_TFAULT,
+    OVW_LMS_KFAULT,
+    OVW_LMS_STOPPED,
+    OVW_LMS_WAIT_CPU,
+    OVW_LMS_SLEEP,
+    OVW_NUMVALS         // must be last
+  };
+
+  // Ovw_item contains one slice of data
+  struct Ovw_item
+  {
+    Value values [OVW_NUMVALS + 1]; // Value list (value[0] is left over)
+    int states;                     // Number of non-zero states
+    Value total;                    // Total of all values
+    int size;                       // Number of values
+    timestruc_t start;              // Start time of sample
+    timestruc_t duration;           // Duration of sample
+    timestruc_t end;                // End time of sample
+    timestruc_t tlwp;               // Total LWP time
+    double nlwp;                    // Average number of LWPs
+    ValueTag type;                  // Type of value
+    int number;                     // Sample number
+    char *start_label;              // Sample start label
+    char *end_label;                // Sample end label
+  };
+
+  Ovw_data (DataView *, hrtime_t exp_start);
+  Ovw_data ();
+  ~Ovw_data ();
+  void sum (Ovw_data *data);
+  Ovw_item get_totals ();
+  Ovw_item get_labels ();
+
+  // zero out contents of Ovw_item
+  static Ovw_item *reset_item (Ovw_item *item);
+
+  int
+  size ()
+  {
+    return ovw_items->size ();
+  }
+
+  Ovw_item
+  fetch (int index)
+  {
+    return *ovw_items->fetch (index);
+  }
+
+private:
+  // Compute the values for "ovw_item" from "sample".
+  void extract_data (Ovw_item *ovw_item, Sample *sample);
+
+  Vector<Ovw_item*> *ovw_items;
+  Ovw_item *totals;             // Item to cache totals
+  DataView *packets;
+};
+
+#endif /* _OVW_DATA_H */
diff --git a/gprofng/src/PRBTree.cc b/gprofng/src/PRBTree.cc
new file mode 100644 (file)
index 0000000..5046a91
--- /dev/null
@@ -0,0 +1,480 @@
+/* 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.  */
+
+//    The Persistent Red-Black Tree
+//
+// Implementation is based on an algorithm described in
+// Sarnak, N., Tarjan, R., "Planar point location using
+// persistent search trees", in Communications of the ACM,
+// 1986, Vol.29, Number 7.
+//
+
+#include "config.h"
+#include <memory.h>
+#include <string.h>
+
+#include "vec.h"
+#include "PRBTree.h"
+
+#define ASSERT(x)
+
+#define IS_BLACK(x)     ((x)==NULL || (x)->color == Black)
+#define IS_RED(x)       ((x)!=NULL && (x)->color == Red)
+#define SET_BLACK(x)    if(x) x->color = Black
+#define SET_RED(x)      (x)->color = Red
+
+#define D_OPPOSITE(x) (((x)==Left) ? Right : Left )
+
+PRBTree::LMap::LMap (Key_t _key, void *_item)
+{
+  key = _key;
+  item = _item;
+  color = Red;
+  parent = NULL;
+  for (int i = 0; i < NPTRS; i++)
+    {
+      dir[i] = None;
+      chld[i] = NULL;
+      time[i] = 0;
+    }
+};
+
+PRBTree::LMap::LMap (const LMap& lm)
+{
+  key = lm.key;
+  item = lm.item;
+  color = lm.color;
+  parent = lm.parent;
+  for (int i = 0; i < NPTRS; i++)
+    {
+      dir[i] = None;
+      chld[i] = NULL;
+      time[i] = 0;
+    }
+};
+
+PRBTree::PRBTree ()
+{
+  roots = new Vector<LMap*>;
+  root = NULL;
+  times = new Vector<Time_t>;
+  rtts = (Time_t) 0;
+  curts = (Time_t) 0;
+  mlist = NULL;
+  vals = NULL;
+}
+
+PRBTree::~PRBTree ()
+{
+  while (mlist)
+    {
+      LMap *lm = mlist;
+      mlist = mlist->next;
+      delete lm;
+    }
+  delete times;
+  delete roots;
+  delete vals;
+}
+
+Vector<void *> *
+PRBTree::values ()
+{
+  if (vals == NULL)
+    {
+      vals = new Vector<void*>;
+      for (LMap *lm = mlist; lm; lm = lm->next)
+       vals->append (lm->item);
+    }
+  return vals;
+}
+
+PRBTree::LMap *
+PRBTree::rb_new_node (Key_t key, void *item)
+{
+  LMap *lm = new LMap (key, item);
+  lm->next = mlist;
+  mlist = lm;
+  return lm;
+}
+
+PRBTree::LMap *
+PRBTree::rb_new_node (LMap *lm)
+{
+  LMap *lmnew = new LMap (*lm);
+  lmnew->next = mlist;
+  mlist = lmnew;
+  return lmnew;
+}
+
+PRBTree::LMap *
+PRBTree::rb_child (LMap *lm, Direction d, Time_t ts)
+{
+  if (lm == NULL)
+    return NULL;
+  for (int i = 0; i < NPTRS; i++)
+    {
+      if (lm->time[i] > ts)
+       continue;
+      if (lm->dir[i] == d)
+       return lm->chld[i];
+      else if (lm->dir[i] == None)
+       break;
+    }
+  return NULL;
+}
+
+PRBTree::Direction
+PRBTree::rb_which_chld (LMap *lm)
+{
+  LMap *prnt = lm->parent;
+  if (prnt == NULL)
+    return None;
+  for (int i = 0; i < NPTRS; i++)
+    {
+      if (prnt->dir[i] == None)
+       break;
+      if (prnt->chld[i] == lm)
+       return (Direction) prnt->dir[i];
+    }
+  return None;
+}
+
+PRBTree::LMap *
+PRBTree::rb_neighbor (LMap *lm, Time_t ts)
+{
+  ASSERT (lm->dir[0] != None);
+  Direction d = D_OPPOSITE (lm->dir[0]);
+  LMap *y = NULL;
+  LMap *next = lm->chld[0];
+  while (next)
+    {
+      y = next;
+      next = rb_child (y, d, ts);
+    }
+  return y;
+}
+
+PRBTree::LMap *
+PRBTree::rb_copy_node (LMap *lm, Direction d)
+{
+  LMap *nlm = rb_new_node (lm);
+  rb_fix_chld (lm->parent, nlm, rb_which_chld (lm));
+  if (d == None)
+    {
+      d = Left;
+      rb_fix_chld (nlm, rb_child (lm, d, curts), d);
+    }
+
+  // copy the other child
+  Direction dd = D_OPPOSITE (d);
+  rb_fix_chld (nlm, rb_child (lm, dd, curts), dd);
+  return nlm;
+}
+
+PRBTree::LMap *
+PRBTree::rb_fix_chld (LMap *prnt, LMap *lm, Direction d)
+{
+
+  if (prnt == NULL)
+    {
+      // fixing root
+      ASSERT (d == None);
+      if (rtts == curts)
+       root = lm;
+      else
+       {
+         roots->append (root);
+         times->append (rtts);
+         root = lm;
+         rtts = curts;
+       }
+      if (lm != NULL)
+       lm->parent = prnt;
+      return prnt;
+    }
+
+  // If we already have a d-pointer at time curts, reuse it
+  for (int i = 0; prnt->time[i] == curts; i++)
+    {
+      if (prnt->dir[i] == d)
+       {
+         prnt->chld[i] = lm;
+         if (lm != NULL)
+           lm->parent = prnt;
+         return prnt;
+       }
+    }
+
+  if (prnt->dir[NPTRS - 1] != None)
+    prnt = rb_copy_node (prnt, d);
+  ASSERT (prnt->dir[NPTRS - 1] == None);
+
+  for (int i = NPTRS - 1; i > 0; i--)
+    {
+      prnt->dir[i] = prnt->dir[i - 1];
+      prnt->chld[i] = prnt->chld[i - 1];
+      prnt->time[i] = prnt->time[i - 1];
+    }
+  prnt->dir[0] = d;
+  prnt->chld[0] = lm;
+  prnt->time[0] = curts;
+  if (lm != NULL)
+    lm->parent = prnt;
+  return prnt;
+}
+
+PRBTree::LMap *
+PRBTree::rb_rotate (LMap *x, Direction d)
+{
+  Direction dd = D_OPPOSITE (d);
+  LMap *y = rb_child (x, dd, curts);
+  x = rb_fix_chld (x, rb_child (y, d, curts), dd);
+  rb_fix_chld (x->parent, y, rb_which_chld (x));
+  rb_fix_chld (y, x, d);
+  return x;
+}
+
+void
+PRBTree::rb_remove_fixup (LMap *x, LMap *prnt, Direction d0)
+{
+
+  while (IS_BLACK (x) && (x != root))
+    {
+      Direction d = (x == NULL) ? d0 : rb_which_chld (x);
+      Direction dd = D_OPPOSITE (d);
+      LMap *y = rb_child (prnt, dd, curts);
+      if (IS_RED (y))
+       {
+         SET_BLACK (y);
+         SET_RED (prnt);
+         prnt = rb_rotate (prnt, d);
+         y = rb_child (prnt, dd, curts);
+       }
+      LMap *y_d = rb_child (y, d, curts);
+      LMap *y_dd = rb_child (y, dd, curts);
+      if (IS_BLACK (y_d) && IS_BLACK (y_dd))
+       {
+         SET_RED (y);
+         x = prnt;
+         prnt = x->parent;
+       }
+      else
+       {
+         if (IS_BLACK (y_dd))
+           {
+             SET_BLACK (y_d);
+             SET_RED (y);
+             y = rb_rotate (y, dd);
+             prnt = y->parent->parent;
+             y = rb_child (prnt, dd, curts);
+             y_dd = rb_child (y, dd, curts);
+           }
+         y->color = prnt->color;
+         SET_BLACK (prnt);
+         SET_BLACK (y_dd);
+         prnt = rb_rotate (prnt, d);
+         break;
+       }
+    }
+  SET_BLACK (x);
+}
+
+PRBTree::LMap *
+PRBTree::rb_locate (Key_t key, Time_t ts, bool low)
+{
+  LMap *lm;
+  Direction d;
+  int i, lt, rt;
+  int tsz = times->size ();
+
+  if (ts >= rtts)
+    lm = root;
+  else
+    {
+      // exponential search
+      for (i = 1; i <= tsz; i = i * 2)
+       if (times->fetch (tsz - i) <= ts)
+         break;
+
+      if (i <= tsz)
+       {
+         lt = tsz - i;
+         rt = tsz - i / 2 - 1;
+       }
+      else
+       {
+         lt = 0;
+         rt = tsz - 1;
+       }
+      while (lt <= rt)
+       {
+         int md = (lt + rt) / 2;
+         if (times->fetch (md) <= ts)
+           lt = md + 1;
+         else
+           rt = md - 1;
+       }
+      if (rt < 0)
+       return NULL;
+      lm = roots->fetch (rt);
+    }
+
+  LMap *last_lo = NULL;
+  LMap *last_hi = NULL;
+  while (lm != NULL)
+    {
+      if (key >= lm->key)
+       {
+         last_lo = lm;
+         d = Right;
+       }
+      else
+       {
+         last_hi = lm;
+         d = Left;
+       }
+      lm = rb_child (lm, d, ts);
+    }
+  return low ? last_lo : last_hi;
+}
+
+//==================================================== Public interface
+
+bool
+PRBTree::insert (Key_t key, Time_t ts, void *item)
+{
+  LMap *lm, *y;
+  Direction d, dd;
+  if (ts > curts)
+    curts = ts;
+  else if (ts < curts)
+    return false; // can only update the current tree
+
+  // Insert in the tree in the usual way
+  y = NULL;
+  d = None;
+  for (LMap *next = root; next;)
+    {
+      y = next;
+      if (key == y->key)
+       {
+         // copy the node with both children
+         lm = rb_copy_node (y, None);
+         // but use the new item
+         lm->item = item;
+         return true;
+       }
+      d = (key < y->key) ? Left : Right;
+      next = rb_child (y, d, curts);
+    }
+  lm = rb_new_node (key, item);
+  rb_fix_chld (y, lm, d);
+
+  // Rebalance the tree
+  while (IS_RED (lm->parent))
+    {
+      d = rb_which_chld (lm->parent);
+      dd = D_OPPOSITE (d);
+
+      y = rb_child (lm->parent->parent, dd, curts);
+      if (IS_RED (y))
+       {
+         SET_BLACK (lm->parent);
+         SET_BLACK (y);
+         SET_RED (lm->parent->parent);
+         lm = lm->parent->parent;
+       }
+      else
+       {
+         if (rb_which_chld (lm) == dd)
+           {
+             lm = lm->parent;
+             lm = rb_rotate (lm, d);
+           }
+         SET_BLACK (lm->parent);
+         SET_RED (lm->parent->parent);
+         rb_rotate (lm->parent->parent, dd);
+       }
+    }
+
+  // Color the root Black
+  SET_BLACK (root);
+  return true;
+}
+
+bool
+PRBTree::remove (Key_t key, Time_t ts)
+{
+  LMap *lm, *x, *y, *prnt;
+  if (ts > curts)
+    curts = ts;
+  else if (ts < curts)
+    return false; // can only update the current tree
+
+  lm = rb_locate (key, curts, true);
+  if (lm == NULL || lm->key != key)
+    return false;
+
+  if (rb_child (lm, Left, curts) && rb_child (lm, Right, curts))
+    y = rb_neighbor (lm, curts);
+  else
+    y = lm;
+
+  x = rb_child (y, Left, curts);
+  if (x == NULL)
+    x = rb_child (y, Right, curts);
+
+  if (y != lm)
+    {
+      lm = rb_copy_node (lm, None); // copied with children
+      lm->key = y->key;
+      lm->item = y->item;
+    }
+
+  Direction d = rb_which_chld (y);
+  prnt = rb_fix_chld (y->parent, x, d);
+  if (IS_BLACK (y))
+    rb_remove_fixup (x, prnt, d);
+  return true;
+}
+
+void *
+PRBTree::locate (Key_t key, Time_t ts)
+{
+  LMap *lm = rb_locate (key, ts, true);
+  return lm ? lm->item : NULL;
+}
+
+void *
+PRBTree::locate_up (Key_t key, Time_t ts)
+{
+  LMap *lm = rb_locate (key, ts, false);
+  return lm ? lm->item : NULL;
+}
+
+void *
+PRBTree::locate_exact_match (Key_t key, Time_t ts)
+{
+  LMap *lm = rb_locate (key, ts, true);
+  if (lm && key == lm->key)
+    return lm->item;
+  return NULL;
+}
diff --git a/gprofng/src/PRBTree.h b/gprofng/src/PRBTree.h
new file mode 100644 (file)
index 0000000..1a6f07f
--- /dev/null
@@ -0,0 +1,106 @@
+/* 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.  */
+
+//
+//    The Persistent Red-Black Tree
+//
+
+#ifndef _PRBTREE_H
+#define _PRBTREE_H
+
+#include "dbe_types.h"
+template <class ITEM> class Vector;
+
+// The number of pointers in a node must be set greater than 2.
+// The higher the number the faster the search seems to be and
+// the more memory the tree takes.
+#define NPTRS   5
+
+class PRBTree
+{
+public:
+
+  typedef Vaddr Key_t;
+  typedef hrtime_t Time_t;
+
+  PRBTree ();
+  ~PRBTree ();
+
+  bool insert (Key_t key, Time_t ts, void *item);
+  bool remove (Key_t key, Time_t ts);
+  void *locate (Key_t key, Time_t ts);
+  void *locate_exact_match (Key_t key, Time_t ts);
+  void *locate_up (Key_t key, Time_t ts);
+  Vector<void *> *values ();
+
+private:
+
+  enum Color
+  {
+    Red,
+    Black
+  };
+
+  enum Direction
+  {
+    None,
+    Left,
+    Right
+  };
+
+  struct LMap
+  {
+    Key_t key;
+    void *item;
+    LMap *parent;
+    LMap *chld[NPTRS];
+    Time_t time[NPTRS];
+    char dir[NPTRS];
+    char color;
+    LMap *next;
+
+    LMap (Key_t _key, void *_item);
+    LMap (const LMap& lm);
+  };
+  friend struct LMap;
+
+  LMap *mlist; // The master list of all nodes
+  Vector<LMap*> *roots;
+  Vector<Time_t> *times;
+  Vector<void *> *vals;
+  LMap *root;
+  Time_t rtts;  // root timestamp
+  Time_t curts; // last update timestamp
+
+  LMap *rb_locate (Key_t key, Time_t ts, bool low);
+  LMap *rb_new_node (Key_t key, void *item);
+  LMap *rb_new_node (LMap *lm);
+  LMap *rb_copy_node (LMap *lm, Direction d);
+  LMap *rb_fix_chld (LMap *prnt, LMap *lm, Direction d);
+  LMap *rb_rotate (LMap *x, Direction d);
+  void rb_remove_fixup (LMap *x, LMap *prnt, Direction d0);
+
+  static LMap *rb_child (LMap *lm, Direction d, Time_t ts);
+  static Direction rb_which_chld (LMap *lm);
+  static LMap *rb_neighbor (LMap *lm, Time_t ts);
+
+};
+
+#endif /* _PRBTREE_H */
diff --git a/gprofng/src/PathTree.cc b/gprofng/src/PathTree.cc
new file mode 100644 (file)
index 0000000..798e55c
--- /dev/null
@@ -0,0 +1,2637 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+
+#include "util.h"
+#include "DefaultMap.h"
+#include "CacheMap.h"
+
+#include "DbeSession.h"
+#include "Application.h"
+#include "CallStack.h"
+#include "Emsg.h"
+#include "Experiment.h"
+#include "Expression.h"
+#include "Function.h"
+#include "Histable.h"
+#include "IndexObject.h"
+#include "MetricList.h"
+#include "Module.h"
+#include "DbeView.h"
+#include "Metric.h"
+#include "PathTree.h"
+#include "LoadObject.h"
+#include "Sample.h"
+#include "StringBuilder.h"
+#include "Table.h"
+
+// Define counts, rate for error warnings for statistical profiles
+#define MIN_PROF_CNT    100
+#define MAX_PROF_RATE   1000.
+
+#define NUM_DESCENDANTS(nd) ((nd)->descendants ? (nd)->descendants->size() : 0)
+#define IS_LEAF(nd)         ((nd)->descendants == NULL)
+
+#ifdef DEBUG
+#define DBG(__func) __func
+#else
+#define DBG(__func)
+#endif
+
+void
+PathTree::construct (DbeView *_dbev, int _indxtype, PathTreeType _pathTreeType)
+{
+  dbev = _dbev;
+  indxtype = _indxtype;
+  pathTreeType = _pathTreeType;
+  status = 0;
+  nchunks = 0;
+  chunks = NULL;
+  nodes = 1; // don't use node 0
+  nslots = 0;
+  slots = NULL;
+  root_idx = 0;
+  root = NULL;
+  depth = 1;
+  dnodes = 0;
+  phaseIdx = -1;
+  nexps = 0;
+  total_obj = NULL;
+  indx_expr = NULL;
+  statsq = NULL;
+  warningq = NULL;
+  cancel_ok = 1;
+  ptree_internal = NULL;
+  ftree_internal = NULL;
+  ftree_needs_update = false;
+  depth_map = NULL;
+  init ();
+}
+
+PathTree::~PathTree ()
+{
+  fini ();
+  for (long i = 0; i < nchunks; i++)
+    delete[] chunks[i];
+  delete[] chunks;
+}
+
+void
+PathTree::init ()
+{
+  fn_map = new DefaultMap<Function*, NodeIdx>;
+  stack_prop = PROP_NONE;
+  desc_htable_size = 511;
+  desc_htable_nelem = 0;
+  descHT = new hash_node_t*[desc_htable_size];
+  for (int i = 0; i < desc_htable_size; i++)
+    descHT[i] = NULL;
+  pathMap = new CacheMap<uint64_t, NodeIdx>;
+  statsq = new Emsgqueue (NTXT ("statsq"));
+  warningq = new Emsgqueue (NTXT ("warningq"));
+  if (indxtype < 0)
+    {
+      Function *ftotal = dbeSession->get_Total_Function ();
+      if (pathTreeType == PATHTREE_INTERNAL_FUNCTREE)
+       total_obj = ftotal;
+      else
+       total_obj = ftotal->find_dbeinstr (0, 0);
+      VMode view_mode = dbev->get_view_mode ();
+      if (view_mode == VMODE_MACHINE)
+       stack_prop = PROP_MSTACK;
+      else if (view_mode == VMODE_EXPERT)
+       stack_prop = PROP_XSTACK;
+      else if (view_mode == VMODE_USER)
+       {
+         stack_prop = PROP_USTACK;
+         if (dbeSession->is_omp_available ()
+             && pathTreeType == PATHTREE_INTERNAL_OMP)
+           stack_prop = PROP_XSTACK;
+       }
+    }
+  else
+    {
+      total_obj = new IndexObject (indxtype, (uint64_t) - 2);
+      total_obj->set_name (dbe_strdup (NTXT ("<Total>")));
+      char *idxname = dbeSession->getIndexSpaceName (indxtype);
+      if (streq (idxname, NTXT ("OMP_preg")))
+       stack_prop = PROP_CPRID;
+      else if (streq (idxname, NTXT ("OMP_task")))
+       stack_prop = PROP_TSKID;
+      else
+       indx_expr = dbeSession->getIndexSpaceExpr (indxtype);
+    }
+  root_idx = new_Node (0, total_obj, false);
+  root = NODE_IDX (root_idx);
+}
+
+void
+PathTree::fini ()
+{
+  // For each node free its descendants vector
+  // and reset the node list of its function
+  for (long i = 1; i < nodes; i++)
+    {
+      Node *node = NODE_IDX (i);
+      if (node->descendants)
+       delete node->descendants;
+    }
+  nodes = 1; // don't use node 0
+
+  for (int i = 0; i < nslots; i++)
+    {
+      int **tmp = slots[i].mvals;
+      for (long j = 0; j < nchunks; j++)
+       delete[] tmp[j];
+      delete[] tmp;
+    }
+  delete[] slots;
+  slots = NULL;
+  nslots = 0;
+  delete fn_map;
+  fn_map = NULL;
+  delete pathMap;
+  pathMap = NULL;
+  destroy (depth_map);
+  depth_map = NULL;
+  if (indxtype >= 0)
+    delete total_obj;
+
+  for (int i = 0; i < desc_htable_size; i++)
+    {
+      hash_node_t *p = descHT[i];
+      while (p)
+       {
+         hash_node_t *p1 = p;
+         p = p->next;
+         delete p1;
+       }
+    }
+  delete[] descHT;
+  delete statsq;
+  delete warningq;
+  depth = 1;
+  dnodes = 0;
+  phaseIdx = -1;
+  nexps = 0;
+  status = 0;
+}
+
+PtreePhaseStatus
+PathTree::reset ()
+{
+  if (pathTreeType == PATHTREE_INTERNAL_FUNCTREE)
+    return NORMAL; // never process reset for ftree_internal.
+
+  if (dbeSession->is_omp_available () && dbev->get_view_mode () == VMODE_USER
+      && pathTreeType == PATHTREE_MAIN && ptree_internal == NULL)
+    ptree_internal = new PathTree (dbev, indxtype, PATHTREE_INTERNAL_OMP);
+
+  if (phaseIdx != dbev->getPhaseIdx ())
+    {
+      fini ();
+      init ();
+      phaseIdx = dbev->getPhaseIdx ();
+      ftree_needs_update = true;
+    }
+  for (; nexps < dbeSession->nexps (); nexps++)
+    {
+      ftree_needs_update = true;
+      if (add_experiment (nexps) == CANCELED)
+       return CANCELED;
+    }
+
+  // LIBRARY_VISIBILITY
+  if (dbev->isNewViewMode ())
+    dbev->resetNewViewMode ();
+  if (dbev->isShowHideChanged ())
+    dbev->resetShowHideChanged ();
+  return NORMAL;
+}
+
+int
+PathTree::allocate_slot (int id, ValueTag vtype)
+{
+
+  int i;
+  int slot_idx = find_slot (id);
+  if (slot_idx >= 0)
+    {
+      DBG (assert (slots[slot_idx].vtype == vtype));
+      return slot_idx;
+    }
+  slot_idx = nslots++;
+
+  Slot *old_slots = slots;
+  slots = new Slot[nslots];
+  for (i = 0; i < slot_idx; i++)
+    slots[i] = old_slots[i];
+  delete[] old_slots;
+
+  slots[slot_idx].id = id;
+  slots[slot_idx].vtype = vtype;
+  int **ip = new int*[nchunks];
+  for (i = 0; i < nchunks; i++)
+    ip[i] = NULL;
+  slots[slot_idx].mvals = ip;
+
+  return slot_idx;
+}
+
+void
+PathTree::allocate_slots (Slot *new_slots, int new_nslots)
+{
+  // duplicates new_slots
+
+  // if previously had more slots than currently requested, delete the data from those slots.
+  for (int i = new_nslots; i < nslots; i++)
+    {
+      int **tmp = slots[i].mvals;
+      for (long j = 0; j < nchunks; j++)
+       delete tmp[j];
+      delete tmp;
+    }
+  if (new_nslots == 0)
+    {
+      nslots = new_nslots;
+      delete[] slots;
+      slots = NULL;
+      return;
+    }
+
+  Slot *old_slots = slots;
+  slots = new Slot[new_nslots];
+  for (int i = 0; i < new_nslots; i++)
+    {
+      slots[i] = new_slots[i]; // pick up id and vtype
+      if (i < nslots)
+       slots[i].mvals = old_slots[i].mvals;
+      else
+       {
+         if (nchunks == 0)
+           slots[i].mvals = NULL;
+         else
+           {
+             int **ip = new int*[nchunks];
+             for (long j = 0; j < nchunks; j++)
+               ip[j] = NULL;
+             slots[i].mvals = ip;
+           }
+       }
+    }
+  nslots = new_nslots;
+  delete old_slots;
+}
+
+int
+PathTree::find_slot (int id)
+{
+  for (int i = 0; i < nslots; i++)
+    if (slots[i].id == id)
+      return i;
+  return -1;
+}
+
+PathTree::NodeIdx
+PathTree::new_Node (NodeIdx anc, Histable *instr, bool leaf)
+{
+  if (nodes >= nchunks * CHUNKSZ)
+    {
+      long idx = nchunks++;
+
+      // Reallocate Node chunk array
+      Node **old_chunks = chunks;
+      chunks = new Node*[nchunks];
+      for (long k = 0; k < idx; k++)
+       chunks[k] = old_chunks[k];
+      delete[] old_chunks;
+
+      // Reallocate metric value chunk arrays.
+      for (int i = 0; i < nslots; i++)
+       {
+         int **mvals = new int*[nchunks];
+         for (long k = 0; k < idx; k++)
+           {
+             mvals[k] = slots[i].mvals[k];
+           }
+         delete[] slots[i].mvals;
+         slots[i].mvals = mvals;
+         slots[i].mvals[idx] = NULL;
+       }
+
+      // Allocate new chunk for nodes.
+      // Note that we don't need to allocate new chunks
+      // for metric values at this point as we rely on
+      // lazy allocation.
+      //
+      allocate_chunk (chunks, idx);
+    }
+  NodeIdx node_idx = nodes++;
+  Node *node = NODE_IDX (node_idx);
+  node->ancestor = anc;
+  node->descendants = leaf ? (Vector<NodeIdx>*)NULL : new Vector<NodeIdx>(2);
+  node->instr = instr;
+  Function *func = (Function*) (instr->convertto (Histable::FUNCTION));
+  node->funclist = fn_map->get (func);
+  fn_map->put (func, node_idx);
+  return node_idx;
+}
+
+PathTree::NodeIdx
+PathTree::find_path (Experiment *exp, DataView *dview, long recIdx)
+{
+  if (indx_expr != NULL)
+    {
+      Expression::Context ctx (dbev, exp, dview, recIdx);
+      uint64_t idx = indx_expr->eval (&ctx);
+      Histable *cur_obj = dbeSession->createIndexObject (indxtype, idx);
+      cur_obj->set_name_from_context (&ctx);
+      NodeIdx dsc_idx = find_in_desc_htable (root_idx, cur_obj, true);
+      depth = 2;
+      return dsc_idx;
+    }
+
+  bool showAll = dbev->isShowAll ();
+  int t_stack_prop = stack_prop;
+  void *stackId = dview->getObjValue (t_stack_prop, recIdx);
+  NodeIdx node_idx;
+  if (stackId != NULL)
+    {
+      // pathMap does not work with NULL key
+      node_idx = pathMap->get ((uint64_t) stackId);
+      if (node_idx != 0)
+       return node_idx;
+    }
+  Vector<Histable*> *stack = (Vector<Histable*>*)CallStack::getStackPCs (stackId, !showAll);
+  int stack_size = stack->size ();
+  if (stack_size == 0)
+    return root_idx;
+
+  node_idx = root_idx;
+  int thisdepth = 1;
+
+  for (int i = stack_size - 1; i >= 0; i--)
+    {
+      bool leaf = (i == 0);
+      Histable *cur_addr = stack->fetch (i);
+
+      // bail out of loop if load object API-only is set
+      // and this is not the top frame
+      // This is now done in HSTACK if hide is set
+
+      Function *func = (Function*) cur_addr->convertto (Histable::FUNCTION);
+      if (func != NULL)
+       {
+         Module *mod = func->module;
+         LoadObject *lo = mod->loadobject;
+         int segx = lo->seg_idx;
+         if (showAll && dbev->get_lo_expand (segx) == LIBEX_API
+             && i != stack_size - 1)
+           leaf = true;
+       }
+
+      NodeIdx dsc_idx = find_desc_node (node_idx, cur_addr, leaf);
+      thisdepth++;
+      node_idx = dsc_idx;
+
+      // LIBEX_API processing might have set leaf to true
+      if (leaf)
+       break;
+    }
+  if (thisdepth > depth)
+    depth = thisdepth;
+  delete stack;
+  pathMap->put ((uint64_t) stackId, node_idx);
+  return node_idx;
+}
+
+static int
+desc_node_comp (const void *s1, const void *s2, const void *ptree)
+{
+  PathTree::NodeIdx t1, t2;
+  t1 = *(PathTree::NodeIdx *)s1;
+  t2 = *(PathTree::NodeIdx *)s2;
+  PathTree* Ptree = (PathTree *) ptree;
+  PathTree::Node *n1 = Ptree->NODE_IDX (t1);
+  PathTree::Node *n2 = Ptree->NODE_IDX (t2);
+  Histable *d1 = n1->instr;
+  Histable *d2 = n2->instr;
+  if (d1->id < d2->id)
+    return -1;
+  else if (d1->id > d2->id)
+    return +1;
+  else
+    return 0;
+}
+
+PathTree::NodeIdx
+PathTree::find_in_desc_htable (NodeIdx node_idx, Histable *instr, bool leaf)
+{
+  unsigned int hash_code = (unsigned int) instr->id % desc_htable_size;
+  Node *node = NODE_IDX (node_idx);
+  hash_node_t *p = NULL;
+  for (p = descHT[hash_code]; p; p = p->next)
+    {
+      Node *dsc = NODE_IDX (p->nd);
+      Histable *dinstr = dsc->instr;
+      if (dinstr->id == instr->id && leaf == IS_LEAF (dsc))
+       return p->nd;
+    }
+  // Not found
+  NodeIdx dsc_idx = new_Node (node_idx, instr, leaf);
+  node->descendants->append (dsc_idx);
+  p = new hash_node_t ();
+  p->nd = dsc_idx;
+  p->next = descHT[hash_code];
+  descHT[hash_code] = p;
+  desc_htable_nelem++;
+
+  // time to resize
+  if (desc_htable_nelem == desc_htable_size)
+    {
+      int old_htable_size = desc_htable_size;
+      desc_htable_size = old_htable_size * 2 + 1;
+      hash_node_t **old_htable = descHT;
+      descHT = new hash_node_t*[desc_htable_size];
+      for (int i = 0; i < desc_htable_size; i++)
+       descHT[i] = NULL;
+
+      for (int i = 0; i < old_htable_size; i++)
+       if (old_htable[i] != NULL)
+         {
+           hash_node *old_p;
+           hash_node_t *hash_p = old_htable[i];
+           while (hash_p != NULL)
+             {
+               hash_node_t *new_p = new hash_node_t ();
+               new_p->nd = hash_p->nd;
+               Node *dnode = NODE_IDX (hash_p->nd);
+               Histable *dnode_instr = dnode->instr;
+               hash_code = (unsigned int) dnode_instr->id % desc_htable_size;
+               new_p->next = descHT[hash_code];
+               descHT[hash_code] = new_p;
+               old_p = hash_p;
+               hash_p = hash_p->next;
+               delete old_p;
+             }
+         }
+      delete[] old_htable;
+    }
+  return dsc_idx;
+}
+
+PathTree::NodeIdx
+PathTree::find_desc_node (NodeIdx node_idx, Histable *instr, bool leaf)
+{
+  // Binary search. All nodes are ordered by Histable::id.
+
+  // We have a special case when two nodes with the same
+  //   id value may co-exist: one representing a leaf node and
+  //   another one representing a call site.
+  Node *node = NODE_IDX (node_idx);
+  int left = 0;
+  int right = NUM_DESCENDANTS (node) - 1;
+  while (left <= right)
+    {
+      int index = (left + right) / 2;
+      NodeIdx dsc_idx = node->descendants->fetch (index);
+      Node *dsc = NODE_IDX (dsc_idx);
+      Histable *dinstr = dsc->instr;
+      if (instr->id < dinstr->id)
+       right = index - 1;
+      else if (instr->id > dinstr->id)
+       left = index + 1;
+      else if (leaf == IS_LEAF (dsc))
+       return dsc_idx;
+      else if (leaf)
+       right = index - 1;
+      else
+       left = index + 1;
+    }
+
+  // None was found. Create one.
+  NodeIdx dsc_idx = new_Node (node_idx, instr, leaf);
+  node->descendants->insert (left, dsc_idx);
+  return dsc_idx;
+}
+
+PtreePhaseStatus
+PathTree::process_packets (Experiment *exp, DataView *packets, int data_type)
+{
+  Expression::Context ctx (dbev, exp);
+  char *progress_bar_msg = NULL;
+  int progress_bar_percent = -1;
+
+  Vector<BaseMetric*> *mlist = dbev->get_all_reg_metrics ();
+  Vector<BaseMetric*> mlist2;
+  StringBuilder stb;
+  for (int midx = 0, mlist_sz = mlist->size (); midx < mlist_sz; ++midx)
+    {
+      BaseMetric *mtr = mlist->fetch (midx);
+      if (mtr->get_packet_type () == data_type &&
+         (mtr->get_expr () == NULL || mtr->get_expr ()->passes (&ctx)))
+       {
+         Hwcentry *hwc = mtr->get_hw_ctr ();
+         if (hwc)
+           {
+             stb.setLength (0);
+             // XXX this should be done at metric registration
+             Collection_params *col_params = exp->get_params ();
+             for (int i = 0; i < MAX_HWCOUNT; i++)
+               {
+                 // We may have duplicate counters in col_params,
+                 // check for all (see 5081284).
+                 if (dbe_strcmp (hwc->name, col_params->hw_aux_name[i]) == 0)
+                   {
+                     if (stb.length () != 0)
+                       stb.append (NTXT ("||"));
+                     stb.append (NTXT ("HWCTAG=="));
+                     stb.append (i);
+                   }
+               }
+             if (stb.length () == 0)
+               continue;
+             stb.append (NTXT ("&& ((HWCINT & "));
+             stb.append ((long long) HWCVAL_ERR_FLAG);
+             stb.append (NTXT (")==0)"));
+             char *s = stb.toString ();
+             mtr->set_cond_spec (s);
+             free (s);
+           }
+         ValueTag vtype = mtr->get_vtype ();
+         switch (vtype)
+           {
+           case VT_INT:
+           case VT_ULLONG:
+           case VT_LLONG:
+             break; // nothing to do
+           default:
+             vtype = VT_ULLONG; // ym: not sure when this would happen
+             break;
+           }
+         allocate_slot (mtr->get_id (), vtype);
+         mlist2.append (mtr);
+       }
+    }
+
+  Slot **mslots = new Slot*[mlist2.size ()];
+  for (int midx = 0, mlist_sz = mlist2.size (); midx < mlist_sz; ++midx)
+    {
+      BaseMetric *mtr = mlist2.fetch (midx);
+      int id = mtr->get_id ();
+      int slot_ind = find_slot (id);
+      mslots[midx] = SLOT_IDX (slot_ind);
+    }
+
+  for (long i = 0, packets_sz = packets->getSize (); i < packets_sz; ++i)
+    {
+      if (dbeSession->is_interactive ())
+       {
+         if (NULL == progress_bar_msg)
+           progress_bar_msg = dbe_sprintf (GTXT ("Processing Experiment: %s"),
+                                         get_basename (exp->get_expt_name ()));
+         int val = (int) (100 * i / packets_sz);
+         if (val > progress_bar_percent)
+           {
+             progress_bar_percent += 10;
+             if (theApplication->set_progress (val, progress_bar_msg)
+                 && cancel_ok)
+               {
+                 delete[] mslots;
+                 return CANCELED;
+               }
+           }
+       }
+
+      NodeIdx path_idx = 0;
+      ctx.put (packets, i);
+
+      for (int midx = 0, mlist_sz = mlist2.size (); midx < mlist_sz; ++midx)
+       {
+         BaseMetric *mtr = mlist2.fetch (midx);
+         if (mtr->get_cond () != NULL && !mtr->get_cond ()->passes (&ctx))
+           continue;
+
+         int64_t mval = mtr->get_val ()->eval (&ctx);
+         if (mval == 0)
+           continue;
+         if (path_idx == 0)
+           path_idx = find_path (exp, packets, i);
+         NodeIdx node_idx = path_idx;
+         Slot *mslot = mslots[midx];
+         while (node_idx)
+           {
+             INCREMENT_METRIC (mslot, node_idx, mval);
+             node_idx = NODE_IDX (node_idx)->ancestor;
+           }
+       }
+    }
+  if (dbeSession->is_interactive ())
+    free (progress_bar_msg);
+  delete[] mslots;
+  if (indx_expr != NULL)
+    root->descendants->sort ((CompareFunc) desc_node_comp, this);
+  return NORMAL;
+}
+
+DataView *
+PathTree::get_filtered_events (int exp_index, int data_type)
+{
+  if (indx_expr != NULL)
+    {
+      IndexObjType_t *indexObj = dbeSession->getIndexSpace (indxtype);
+      if (indexObj->memObj && data_type != DATA_HWC)
+       return NULL;
+    }
+  return dbev->get_filtered_events (exp_index, data_type);
+}
+
+PtreePhaseStatus
+PathTree::add_experiment (int exp_index)
+{
+  StringBuilder sb;
+  char *expt_name;
+  char *base_name;
+  Emsg *m;
+  Experiment *experiment = dbeSession->get_exp (exp_index);
+  if (experiment->broken != 0)
+    return NORMAL;
+  status = 0;
+  expt_name = experiment->get_expt_name ();
+  base_name = get_basename (expt_name);
+
+  hrtime_t starttime = gethrtime ();
+  hrtime_t startvtime = gethrvtime ();
+
+  // Experiment::getEndTime was initially implemented as
+  // returning exp->last_event. To preserve the semantics
+  // new Experiment::getLastEvent() is used here.
+  hrtime_t tot_time = experiment->getLastEvent () - experiment->getStartTime ();
+
+  if (!dbev->isShowAll () && (dbev->isShowHideChanged ()
+                             || dbev->isNewViewMode ()))
+    experiment->resetShowHideStack ();
+
+  // To report experiment index to the user,
+  // start numeration from 1, not 0
+  sb.sprintf (GTXT ("PathTree processing experiment %d (`%s'); duration %lld.%06lld"),
+             exp_index + 1, base_name,
+             tot_time / NANOSEC, (tot_time % NANOSEC / 1000));
+  m = new Emsg (CMSG_COMMENT, sb);
+  statsq->append (m);
+
+  DataView *prof_packet = get_filtered_events (exp_index, DATA_CLOCK);
+  if (prof_packet && prof_packet->getSize () > 0)
+    {
+      if (process_packets (experiment, prof_packet, DATA_CLOCK) == CANCELED)
+       return CANCELED;
+      long clock_cnt = prof_packet->getSize ();
+      double clock_rate;
+      if (tot_time != 0)
+       clock_rate = (double) clock_cnt / (double) tot_time * (double) NANOSEC;
+      else
+       clock_rate = (double) 0.;
+      if (experiment->timelineavail)
+       sb.sprintf (GTXT ("  Processed %ld clock-profile events (%3.2f/sec.)"),
+                   clock_cnt, clock_rate);
+      else
+       sb.sprintf (GTXT ("  Processed %ld clock-profile events"), clock_cnt);
+      m = new Emsg (CMSG_COMMENT, sb);
+      statsq->append (m);
+
+      // check for statistical validity
+      if ((experiment->timelineavail == true)
+          && !dbev->get_filter_active () && (clock_cnt < MIN_PROF_CNT))
+       {
+         sb.sprintf (GTXT ("WARNING: too few clock-profile events (%ld) in experiment %d (`%s') for statistical validity"),
+                     clock_cnt, exp_index + 1, base_name);
+         m = new Emsg (CMSG_COMMENT, sb);
+         statsq->append (m);
+       }
+    }
+
+  DataView *sync_packet = get_filtered_events (exp_index, DATA_SYNCH);
+  if (sync_packet && sync_packet->getSize () > 0)
+    {
+      if (process_packets (experiment, sync_packet, DATA_SYNCH) == CANCELED)
+       return CANCELED;
+      long sync_cnt = sync_packet->getSize ();
+      sb.sprintf (GTXT ("  Processed %ld synctrace events"), sync_cnt);
+      m = new Emsg (CMSG_COMMENT, sb);
+      statsq->append (m);
+    }
+
+  DataView *iotrace_packet = get_filtered_events (exp_index, DATA_IOTRACE);
+  if (iotrace_packet && iotrace_packet->getSize () > 0)
+    {
+      if (process_packets (experiment, iotrace_packet, DATA_IOTRACE) == CANCELED)
+       return CANCELED;
+      long iotrace_cnt = iotrace_packet->getSize ();
+      sb.sprintf (GTXT ("  Processed %ld IO trace events"), iotrace_cnt);
+      m = new Emsg (CMSG_COMMENT, sb);
+      statsq->append (m);
+    }
+
+  DataView *hwc_packet = get_filtered_events (exp_index, DATA_HWC);
+  if (hwc_packet && hwc_packet->getSize () > 0)
+    {
+      if (process_packets (experiment, hwc_packet, DATA_HWC) == CANCELED)
+       return CANCELED;
+      long hwc_cnt = hwc_packet->getSize ();
+      double hwc_rate = (double) hwc_cnt / (double) tot_time * (double) NANOSEC;
+      if (experiment->timelineavail)
+       sb.sprintf (GTXT ("  Processed %ld hwc-profile events (%3.2f/sec.)"),
+                   hwc_cnt, hwc_rate);
+      else
+       sb.sprintf (GTXT ("  Processed %ld hwc-profile events"), hwc_cnt);
+      m = new Emsg (CMSG_COMMENT, sb);
+      statsq->append (m);
+
+      // check for statistical validity
+      if (experiment->timelineavail && !dbev->get_filter_active () && (hwc_cnt < MIN_PROF_CNT))
+       {
+         sb.sprintf (GTXT ("WARNING: too few HW counter profile events (%ld) in experiment %d (`%s') for statistical validity"),
+                     hwc_cnt, exp_index + 1, base_name);
+         m = new Emsg (CMSG_COMMENT, sb);
+         statsq->append (m);
+       }
+    }
+
+  DataView *heap_packet = get_filtered_events (exp_index, DATA_HEAP);
+  if (heap_packet && heap_packet->getSize () > 0)
+    {
+      if (process_packets (experiment, heap_packet, DATA_HEAP) == CANCELED)
+       return CANCELED;
+      long heap_cnt = heap_packet->getSize ();
+      sb.sprintf (GTXT ("  Processed %ld heaptrace events"), heap_cnt);
+      m = new Emsg (CMSG_COMMENT, sb);
+      statsq->append (m);
+    }
+
+  DataView *race_packet = get_filtered_events (exp_index, DATA_RACE);
+  if (race_packet && race_packet->getSize () > 0)
+    {
+      if (process_packets (experiment, race_packet, DATA_RACE) == CANCELED)
+       return CANCELED;
+      long race_cnt = race_packet->getSize ();
+      sb.sprintf (GTXT ("  Processed %ld race access events"), race_cnt);
+      m = new Emsg (CMSG_COMMENT, sb);
+      statsq->append (m);
+    }
+
+  DataView *deadlock_packet = get_filtered_events (exp_index, DATA_DLCK);
+  if (deadlock_packet && deadlock_packet->getSize () > 0)
+    {
+      if (process_packets (experiment, deadlock_packet, DATA_DLCK) == CANCELED)
+       return CANCELED;
+      long race_cnt = deadlock_packet->getSize ();
+      sb.sprintf (GTXT ("  Processed %ld race access events"), race_cnt);
+      m = new Emsg (CMSG_COMMENT, sb);
+      statsq->append (m);
+    }
+
+  hrtime_t pathtime = gethrtime () - starttime;
+  hrtime_t pathvtime = gethrvtime () - startvtime;
+  sb.sprintf (GTXT ("PathTree time = %lld.%06lld CPU-time %lld.%06lld\n"),
+             pathtime / NANOSEC, (pathtime % NANOSEC) / 1000,
+             pathvtime / NANOSEC, (pathvtime % NANOSEC) / 1000);
+  m = new Emsg (CMSG_COMMENT, sb);
+  statsq->append (m);
+  return NORMAL;
+}
+
+Hist_data *
+PathTree::compute_metrics (MetricList *mlist, Histable::Type type,
+                          Hist_data::Mode mode, Vector<Histable*> *objs,
+                          Histable *context, Vector<Histable*> *sel_objs,
+                          PtreeComputeOption computeOpt)
+{
+  VMode view_mode = dbev->get_view_mode ();
+
+  // For displaying disassembly correctly in user mode with openmp
+  if (ptree_internal != NULL &&
+      (view_mode == VMODE_EXPERT ||
+       (view_mode == VMODE_USER && (type == Histable::INSTR
+                                   || (dbev->isOmpDisMode ()
+                                       && type == Histable::FUNCTION
+                                       && mode == Hist_data::CALLEES
+                                       && computeOpt == COMPUTEOPT_OMP_CALLEE))
+                                   )))
+    return ptree_internal->compute_metrics (mlist, type, mode, objs, context,
+                                           sel_objs);
+
+  PtreePhaseStatus resetStatus = reset ();
+
+  hist_data = new Hist_data (mlist, type, mode);
+  int nmetrics = mlist->get_items ()->size ();
+  int sort_ind = -1;
+  Hist_data::HistItem *hi;
+  int index;
+
+  if (status != 0 || resetStatus == CANCELED)
+    return hist_data;
+
+  hist_data->set_status (Hist_data::SUCCESS);
+  if (dbeSession->is_interactive () && mode != Hist_data::CALLEES)
+    theApplication->set_progress (0, GTXT ("Constructing Metrics"));
+
+  xlate = new int[nmetrics];
+  for (int mind = 0; mind < nmetrics; mind++)
+    {
+      Metric *mtr = mlist->get (mind);
+      xlate[mind] = find_slot (mtr->get_id ());
+    }
+
+  // Compute dynamic metrics
+  obj_list = new Histable*[depth];
+  if ((type == Histable::LINE || type == Histable::INSTR)
+      && mode == Hist_data::CALLERS)
+    node_list = new Node*[depth];
+  percent = 0;
+  ndone = 0;
+  if (mode == Hist_data::MODL)
+    {
+      Histable *obj = objs && objs->size () > 0 ? objs->fetch (0) : NULL;
+      if (obj != NULL)
+       {
+         switch (obj->get_type ())
+           {
+           case Histable::FUNCTION:
+             {
+               Vector<Function*> *funclist = new Vector<Function*>;
+               funclist->append ((Function*) obj);
+               get_metrics (funclist, context);
+               delete funclist;
+               break;
+             }
+           case Histable::MODULE:
+             {
+               Vector<Histable*> *comparableModules = obj->get_comparable_objs ();
+               if (comparableModules != NULL)
+                 {
+                   Vector<Function*> *functions = new Vector<Function*>;
+                   for (int i = 0; i < comparableModules->size (); i++)
+                     {
+                       Module *mod = (Module*) comparableModules->fetch (i);
+                       if (mod)
+                         {
+                           bool found = false;
+                           for (int i1 = 0; i1 < i; i1++)
+                             {
+                               if (mod == comparableModules->fetch (i1))
+                                 {
+                                   found = true;
+                                   break;
+                                 }
+                             }
+                           if (!found)
+                             functions->addAll (mod->functions);
+                         }
+                     }
+                   get_metrics (functions, context);
+                   delete functions;
+                 }
+               else
+                 get_metrics (((Module*) obj)->functions, context);
+               break;
+             }
+           case Histable::SOURCEFILE:
+             get_metrics (((SourceFile *) obj)->get_functions (), context);
+             break;
+           default:
+             DBG (assert (0));
+           }
+       }
+    }
+  else if (mode == Hist_data::CALLERS)
+    {
+      if (objs && objs->size () > 0)
+       get_clr_metrics (objs);
+    }
+  else if (mode == Hist_data::CALLEES)
+    {
+      if (objs && objs->size () > 0)
+       get_cle_metrics (objs);
+      else   // Special case: get root
+       get_cle_metrics (NULL);
+    }
+  else if (mode == Hist_data::SELF)
+    {
+      if (objs->size () == 1)
+       {
+         Histable *obj = objs->fetch (0);
+         if (obj != NULL)
+           {
+             if (obj->get_type () == Histable::LINE)
+               {
+                 Vector<Function*> *funclist = new Vector<Function*>;
+                 for (DbeLine *dl = (DbeLine*) obj->convertto (Histable::LINE);
+                         dl; dl = dl->dbeline_func_next)
+                   if (dl->func)
+                     funclist->append (dl->func);
+
+                 get_self_metrics (obj, funclist, sel_objs);
+                 delete funclist;
+               }
+             else if (obj->get_type () == Histable::FUNCTION
+                      || obj->get_type () == Histable::INSTR)
+               {
+                 // Use shortcut for functions and oth.
+                 if (context)
+                   {
+                     Vector<Function*> *funclist = NULL;
+                     if (context->get_type () == Histable::MODULE)
+                       funclist = ((Module*) context)->functions->copy ();
+                     else
+                       {
+                         funclist = new Vector<Function*>;
+                         funclist->append ((Function*) context);
+                       }
+                     get_self_metrics (obj, funclist, sel_objs);
+                     delete funclist;
+                   }
+                 else
+                   get_self_metrics (objs);
+               }
+             else
+               get_self_metrics (objs);
+           }
+       }
+      else
+       get_self_metrics (objs);
+    }
+  else   // Hist_data::ALL
+    get_metrics (root_idx, 0);
+
+  delete[] obj_list;
+  if ((type == Histable::LINE || type == Histable::INSTR)
+      && mode == Hist_data::CALLERS)
+    delete[] node_list;
+
+  // Postprocess; find total
+  for (long mind = 0, sz = mlist->get_items ()->size (); mind < sz; mind++)
+    {
+      Metric *mtr = mlist->get_items ()->get (mind);
+      Metric::SubType subtype = mtr->get_subtype ();
+      ValueTag vtype = mtr->get_vtype ();
+      hist_data->total->value[mind].tag = vtype;
+
+      switch (vtype)
+       {
+         // ignoring the following cases (why?)
+       case VT_SHORT:
+       case VT_FLOAT:
+       case VT_HRTIME:
+       case VT_LABEL:
+       case VT_ADDRESS:
+       case VT_OFFSET:
+         break;
+
+       case VT_INT:
+         // Calculate total as the sum of all values in hist_data for
+         // ATTRIBUTED metrics only. For all others, use root node values.
+         //
+         if ((mode == Hist_data::CALLERS || mode == Hist_data::CALLEES)
+             && subtype == Metric::ATTRIBUTED)
+           {
+             hist_data->total->value[mind].i = 0;
+             Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+             {
+               hist_data->total->value[mind].i += hi->value[mind].i;
+             }
+             if (mode == Hist_data::CALLEES)
+               hist_data->total->value[mind].i += hist_data->gprof_item->value[mind].i;
+           }
+         else if (xlate[mind] != -1)
+           ASN_METRIC_VAL (hist_data->total->value[mind], slots[xlate[mind]],
+                           root_idx);
+         break;
+
+       case VT_LLONG:
+         Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+         {
+           hi->value[mind].tag = vtype;
+         }
+
+         if ((mode == Hist_data::CALLERS || mode == Hist_data::CALLEES)
+             && subtype == Metric::ATTRIBUTED)
+           {
+             hist_data->total->value[mind].ll = 0;
+             Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+             {
+               hist_data->total->value[mind].ll += hi->value[mind].ll;
+             }
+             if (mode == Hist_data::CALLEES)
+               hist_data->total->value[mind].ll += hist_data->gprof_item->value[mind].ll;
+           }
+         else if (xlate[mind] != -1)
+           ASN_METRIC_VAL (hist_data->total->value[mind], slots[xlate[mind]], root_idx);
+         break;
+
+       case VT_ULLONG:
+         Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+         {
+           hi->value[mind].tag = vtype;
+         }
+         if ((mode == Hist_data::CALLERS || mode == Hist_data::CALLEES)
+             && subtype == Metric::ATTRIBUTED)
+           {
+             hist_data->total->value[mind].ull = 0;
+             Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+             {
+               hist_data->total->value[mind].ull += hi->value[mind].ull;
+             }
+             if (mode == Hist_data::CALLEES)
+               hist_data->total->value[mind].ull += hist_data->gprof_item->value[mind].ull;
+           }
+         else if (xlate[mind] != -1)
+           ASN_METRIC_VAL (hist_data->total->value[mind], slots[xlate[mind]], root_idx);
+         break;
+
+       case VT_DOUBLE:
+         double prec = mtr->get_precision ();
+         ValueTag vt = (xlate[mind] != -1) ? slots[xlate[mind]].vtype : VT_INT;
+         Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+         {
+           double val = (vt == VT_LLONG ? hi->value[mind].ll :
+                         (vt == VT_ULLONG ? hi->value[mind].ull
+                          : hi->value[mind].i));
+           hi->value[mind].tag = vtype;
+           hi->value[mind].d = val / prec;
+         }
+
+         if ((mode == Hist_data::CALLERS || mode == Hist_data::CALLEES)
+              && subtype == Metric::ATTRIBUTED)
+           {
+             hist_data->total->value[mind].d = 0.0;
+             Vec_loop (Hist_data::HistItem*, hist_data->hist_items, index, hi)
+             {
+               hist_data->total->value[mind].d += hi->value[mind].d;
+             }
+             if (mode == Hist_data::CALLEES)
+               hist_data->total->value[mind].d +=
+                     (double) (vt == VT_LLONG ? hist_data->gprof_item->value[mind].ll :
+                               (vt == VT_ULLONG ? hist_data->gprof_item->value[mind].ull :
+                                hist_data->gprof_item->value[mind].i)) / prec;
+           }
+         else if (xlate[mind] != -1)
+           {
+             TValue& total = hist_data->total->value[mind];
+             ASN_METRIC_VAL (total, slots[xlate[mind]], root_idx);
+             double val = (vt == VT_LLONG ? total.ll :
+                           (vt == VT_ULLONG ? total.ll : total.i));
+             total.d = val / prec;
+           }
+         break;
+       }
+    }
+  delete[] xlate;
+
+  // Determine by which metric to sort if any
+  bool rev_sort = mlist->get_sort_rev ();
+  for (long mind = 0, sz = mlist->get_items ()->size (); mind < sz; mind++)
+    {
+      Metric *mtr = mlist->get_items ()->get (mind);
+      if (mlist->get_sort_ref_index () == mind)
+       sort_ind = mind;
+
+      switch (mtr->get_type ())
+       {
+       case BaseMetric::SIZES:
+         Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+         {
+           Histable *h = mtr->get_comparable_obj (hi->obj);
+           hi->value[mind].tag = VT_LLONG;
+           hi->value[mind].ll = h ? h->get_size () : 0;
+         }
+         break;
+       case BaseMetric::ADDRESS:
+         Vec_loop (Hist_data::HistItem *, hist_data->hist_items, index, hi)
+         {
+           Histable *h = mtr->get_comparable_obj (hi->obj);
+           hi->value[mind].tag = VT_ADDRESS;
+           hi->value[mind].ll = h ? h->get_addr () : 0;
+         }
+         break;
+       case BaseMetric::DERIVED:
+         {
+           Definition *def = mtr->get_definition ();
+           long *map = def->get_map ();
+           for (long i1 = 0, sz1 = hist_data->hist_items->size (); i1 < sz1; i1++)
+             {
+               /* Hist_data::HistItem * */hi = hist_data->hist_items->get (i1);
+               hi->value[mind].tag = VT_DOUBLE;
+               hi->value[mind].d = def->eval (map, hi->value);
+             }
+           hist_data->total->value[mind].tag = VT_DOUBLE;
+           hist_data->total->value[mind].d = def->eval (map, hist_data->total->value);
+         }
+         break;
+       default:
+         break;
+       }
+    }
+
+  hist_data->sort (sort_ind, rev_sort);
+  hist_data->compute_minmax ();
+  if (dbeSession->is_interactive () && mode != Hist_data::CALLERS)
+    theApplication->set_progress (0, GTXT (""));
+
+#if DEBUG_FTREE
+  if (ftree_hist_data)
+    {
+      bool matches = ftree_debug_match_hist_data (hist_data, ftree_hist_data);
+      if (!matches)
+       assert (false);
+      delete hist_data;
+      hist_data = ftree_hist_data; // return the debug version
+    }
+#endif
+  return hist_data;
+}
+
+#if DEBUG_FTREE
+bool
+PathTree::ftree_debug_match_hist_data (Hist_data *data /* ref */,
+                                      Hist_data *data_tmp)
+{
+  if (data->get_status () != Hist_data::SUCCESS)
+    {
+      DBG (assert (false));
+      return false;
+    }
+  if (data == NULL && data != data_tmp)
+    {
+      DBG (assert (false));
+      return false;
+    }
+
+  MetricList *mlist;
+  mlist = data->get_metric_list ();
+  MetricList *mlist_tmp;
+  mlist_tmp = data_tmp->get_metric_list ();
+  if (mlist->size () != mlist_tmp->size ())
+    {
+      DBG (assert (false));
+      return false;
+    }
+
+  // Get table size: count visible metrics
+  int nitems = data->size ();
+  if (data->size () != data_tmp->size ())
+    {
+      DBG (assert (false));
+      return false;
+    }
+
+  for (int i = 0; i < nitems; ++i)
+    {
+      Hist_data::HistItem *item = data->fetch (i);
+      Hist_data::HistItem *item_tmp = data_tmp->fetch (i);
+      if (item->obj->id != item_tmp->obj->id)
+       {
+         DBG (assert (false));
+         return false;
+       }
+    }
+
+  for (long i = 0, sz = mlist->size (); i < sz; i++)
+    {
+      long met_ind = i;
+      Metric *mitem = mlist->get (i);
+      Metric *mitem_tmp = mlist_tmp->get (i);
+
+      if (mitem->get_id () != mitem_tmp->get_id ())
+       {
+         DBG (assert (false));
+         return false;
+       }
+      if (mitem->get_visbits () != mitem_tmp->get_visbits ())
+       {
+         DBG (assert (false));
+         return false;
+       }
+      if (mitem->get_vtype () != mitem_tmp->get_vtype ())
+       {
+         DBG (assert (false));
+         return false;
+       }
+
+      if (!mitem->is_visible () && !mitem->is_tvisible ()
+         && !mitem->is_pvisible ())
+       continue;
+      // table->append(dbeGetTableDataOneColumn(data, i));
+      for (long row = 0, sz_row = data->size (); row < sz_row; row++)
+       {
+         Metric *m = mitem;
+         TValue res;
+         TValue res_tmp;
+         TValue *v = data->get_value (&res, met_ind, row);
+         TValue *v_tmp = data_tmp->get_value (&res_tmp, met_ind, row);
+         if ((m->get_visbits () & VAL_RATIO) != 0)
+           {
+             if (v->tag != VT_LABEL)
+               {
+                 if (v->to_double () != v_tmp->to_double ())
+                   {
+                     DBG (assert (false));
+                     return false;
+                   }
+               }
+             continue;
+           }
+         switch (m->get_vtype ())
+           {
+           case VT_DOUBLE:
+             {
+               double diff = v->d - v_tmp->d;
+               if (diff < 0) diff = -diff;
+               if (diff > 0.0001)
+                 {
+                   DBG (assert (false));
+                   return false;
+                 }
+               else
+                 DBG (assert (true));
+               break;
+             }
+           case VT_INT:
+             if (v->i != v_tmp->i)
+               {
+                 DBG (assert (false));
+                 return false;
+               }
+             break;
+           case VT_ULLONG:
+           case VT_LLONG:
+           case VT_ADDRESS:
+             if (v->ll != v_tmp->ll)
+               {
+                 DBG (assert (false));
+                 return false;
+               }
+             break;
+
+           case VT_LABEL:
+             if (dbe_strcmp (v->l, v_tmp->l))
+               {
+                 DBG (assert (false));
+                 return false;
+               }
+             break;
+           default:
+             DBG (assert (false));
+             return false;
+           }
+       }
+    }
+  return true;
+}
+#endif
+
+Histable *
+PathTree::get_hist_func_obj (Node *node)
+{
+  LoadObject *lo;
+  Function *func;
+  func = (Function*) (node->instr->convertto (Histable::FUNCTION));
+  // LIBRARY VISIBILITY
+  lo = func->module->loadobject;
+  if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE)
+    return lo->get_hide_function ();
+  return get_compare_obj (func);
+}
+
+Histable *
+PathTree::get_hist_obj (Node *node, Histable* context)
+{
+  LoadObject *lo;
+  Function *func;
+  switch (hist_data->type)
+    {
+    case Histable::INSTR:
+      if (hist_data->mode == Hist_data::MODL)
+       {
+         if (node->instr->get_type () != Histable::INSTR)
+           return NULL;
+       }
+      else
+       {
+         // LIBRARY VISIBILITY
+         func = (Function*) (node->instr->convertto (Histable::FUNCTION));
+         lo = func->module->loadobject;
+         if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE)
+           return lo->get_hide_function ();
+       }
+      return node->instr;
+
+    case Histable::LINE:
+      if (hist_data->mode != Hist_data::MODL)
+       {
+         func = (Function*) (node->instr->convertto (Histable::FUNCTION));
+         lo = func->module->loadobject;
+         // LIBRARY VISIBILITY
+         if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE)
+           return lo->get_hide_function ();
+       }
+      // For openmp user mode - the stack is already made with dbelines,
+      // no need to convert it
+      if (node->instr->get_type () == Histable::LINE)
+       return node->instr;
+      return node->instr->convertto (Histable::LINE, context);
+
+    case Histable::FUNCTION:
+      if (pathTreeType == PATHTREE_INTERNAL_FUNCTREE && node->ancestor != 0)
+       func = (Function*) node->instr;
+      else
+       func = (Function*) (node->instr->convertto (Histable::FUNCTION));
+      lo = func->module->loadobject;
+      // LIBRARY VISIBILITY
+      if (dbev->get_lo_expand (lo->seg_idx) == LIBEX_HIDE)
+       return lo->get_hide_function ();
+      return get_compare_obj (func);
+    case Histable::MODULE:
+      func = (Function*) (node->instr->convertto (Histable::FUNCTION));
+      return func->module;
+    case Histable::LOADOBJECT:
+      func = (Function*) (node->instr->convertto (Histable::FUNCTION));
+      return func->module->loadobject;
+    case Histable::INDEXOBJ:
+    case Histable::MEMOBJ:
+      return node->instr;
+    default:
+      DBG (assert (0));
+    }
+  return NULL;
+}
+
+Histable *
+PathTree::get_compare_obj (Histable *obj)
+{
+  if (obj && dbev->comparingExperiments ())
+    obj = dbev->get_compare_obj (obj);
+  return obj;
+}
+
+void
+PathTree::get_metrics (NodeIdx node_idx, int dpth)
+{
+  Node *node = NODE_IDX (node_idx);
+  Histable *cur_obj = get_hist_obj (node);
+  obj_list[dpth] = cur_obj;
+
+  // Check for recursion (inclusive metrics)
+  int incl_ok = 1;
+  for (int i = dpth - 1; i >= 0; i--)
+    if (cur_obj == obj_list[i])
+      {
+       incl_ok = 0;
+       break;
+      }
+
+  // Check for leaf nodes (exclusive metrics)
+  int excl_ok = 0;
+  if (IS_LEAF (node) || node == NODE_IDX (root_idx))
+    excl_ok = 1;
+
+  // We shouldn't eliminate empty subtrees here because
+  // we create the list of hist items dynamically and want
+  // one for each object in the tree.
+  cur_obj = get_compare_obj (cur_obj);
+  Hist_data::HistItem *hi = hist_data->append_hist_item (cur_obj);
+  DBG (assert (hi != NULL));
+
+  MetricList *mlist = hist_data->get_metric_list ();
+  for (long ind = 0, sz = mlist->size (); ind < sz; ind++)
+    {
+      if (xlate[ind] == -1)
+       continue;
+      Metric *mtr = mlist->get (ind);
+      Metric::SubType subtype = mtr->get_subtype ();
+      if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+       continue;
+
+      switch (subtype)
+       {
+       case Metric::INCLUSIVE:
+         if (incl_ok && hi)
+           ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+         break;
+       case Metric::EXCLUSIVE:
+         if (excl_ok && hi)
+           ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+         break;
+         // ignoring the following cases (why?)
+       case Metric::STATIC:
+       case Metric::ATTRIBUTED:
+         break;
+       case Metric::DATASPACE:
+         if (hi)
+           ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+         break;
+       }
+    }
+
+  if (dbeSession->is_interactive ())
+    {
+      ndone++;
+      int new_percent = 95 * ndone / nodes;
+      if (new_percent > percent)
+       {
+         percent = new_percent;
+         theApplication->set_progress (percent, NULL);
+       }
+    }
+
+  // Recursively process all descendants
+  int index;
+  int dsize = NUM_DESCENDANTS (node);
+  for (index = 0; index < dsize; index++)
+    get_metrics (node->descendants->fetch (index), dpth + 1);
+}
+
+void
+PathTree::get_clr_metrics (Vector<Histable*> *objs, NodeIdx node_idx,
+                          int pmatch, int dpth)
+{
+  Node *node = NODE_IDX (node_idx);
+  Histable *cur_obj;
+  if (hist_data->type == Histable::LINE || hist_data->type == Histable::INSTR)
+    {
+      cur_obj = get_hist_func_obj (node);
+      node_list[dpth] = node;
+    }
+  else
+    cur_obj = get_hist_obj (node);
+  obj_list[dpth] = cur_obj;
+
+  bool match = false;
+  int nobj = objs->size ();
+  if (dpth + 1 >= nobj)
+    {
+      match = true;
+      for (int i = 0; i < nobj; ++i)
+       {
+         if (objs->fetch (i) != obj_list[dpth - nobj + 1 + i])
+           {
+             match = false;
+             break;
+           }
+       }
+    }
+
+  Hist_data::HistItem *hi = NULL;
+  Hist_data::HistItem *hi_adj = NULL;
+  if (match && dpth >= nobj)
+    {
+      if (hist_data->type == Histable::LINE
+         || hist_data->type == Histable::INSTR)
+       hi = hist_data->append_hist_item (get_hist_obj (node_list[dpth - nobj]));
+      else
+       hi = hist_data->append_hist_item (obj_list[dpth - nobj]);
+
+      if (pmatch >= 0 && pmatch >= nobj)
+       {
+         if (hist_data->type == Histable::LINE
+             || hist_data->type == Histable::INSTR)
+           hi_adj = hist_data->append_hist_item (get_hist_obj (
+                                                   node_list[pmatch - nobj]));
+         else
+           hi_adj = hist_data->append_hist_item (obj_list[pmatch - nobj]);
+       }
+    }
+
+  if (hi != NULL)
+    {
+      MetricList *mlist = hist_data->get_metric_list ();
+      for (long ind = 0, sz = mlist->size (); ind < sz; ind++)
+       {
+         if (xlate[ind] == -1)
+           continue;
+         if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+           continue;
+         Metric *mtr = mlist->get (ind);
+         Metric::SubType subtype = mtr->get_subtype ();
+
+         switch (subtype)
+           {
+           case Metric::ATTRIBUTED:
+             if (hi)
+               ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+             if (hi_adj)
+               SUB_METRIC_VAL (hi_adj->value[ind], slots[xlate[ind]], node_idx);
+             break;
+           case Metric::STATIC:
+           case Metric::EXCLUSIVE:
+           case Metric::INCLUSIVE:
+           case Metric::DATASPACE:
+             break;
+           }
+       }
+    }
+
+  // Recursively process all descendants
+  int dsize = NUM_DESCENDANTS (node);
+  for (int index = 0; index < dsize; index++)
+    get_clr_metrics (objs, node->descendants->fetch (index),
+                    match ? dpth : pmatch, dpth + 1);
+}
+
+void
+PathTree::get_clr_metrics (Vector<Histable*> *objs)
+{
+  get_clr_metrics (objs, root_idx, -1, 0);
+}
+
+void
+PathTree::get_cle_metrics (Vector<Histable*> *objs, NodeIdx node_idx, int pcle,
+                          int pmatch, int dpth)
+{
+  Node *node = NODE_IDX (node_idx);
+  Histable *cur_obj = get_hist_obj (node);
+  obj_list[dpth] = cur_obj;
+
+  bool match = false;
+  int nobj = objs->size ();
+  if (dpth + 1 >= nobj)
+    {
+      match = true;
+      for (int i = 0; i < nobj; ++i)
+       if (objs->fetch (i) != obj_list[dpth - nobj + 1 + i])
+         {
+           match = false;
+           break;
+         }
+    }
+
+  Hist_data::HistItem *hi = NULL;
+  Hist_data::HistItem *hi_adj = NULL;
+  if (pmatch >= 0 && dpth == pmatch + 1)
+    hi = hist_data->append_hist_item (cur_obj);
+  if (match && IS_LEAF (node))
+    hi = hist_data->gprof_item;
+  if (pcle >= 0)
+    hi_adj = hist_data->append_hist_item (obj_list[pcle]);
+
+  if (hi != NULL)
+    {
+      MetricList *mlist = hist_data->get_metric_list ();
+      for (long ind = 0, sz = mlist->size (); ind < sz; ind++)
+       {
+         if (xlate[ind] == -1)
+           continue;
+         if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+           continue;
+         Metric *mtr = mlist->get (ind);
+         Metric::SubType subtype = mtr->get_subtype ();
+         if (subtype == Metric::ATTRIBUTED)
+           {
+             ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+             if (hi_adj)
+               SUB_METRIC_VAL (hi_adj->value[ind], slots[xlate[ind]], node_idx);
+           }
+       }
+    }
+
+  // Recursively process all descendants
+  int dsize = NUM_DESCENDANTS (node);
+  for (int index = 0; index < dsize; index++)
+    get_cle_metrics (objs, node->descendants->fetch (index),
+                    pmatch >= 0 && dpth == pmatch + 1 ? dpth : pcle,
+                    match ? dpth : pmatch, dpth + 1);
+}
+
+void
+PathTree::get_cle_metrics (Vector<Histable*> *objs, NodeIdx node_idx, int dpth)
+{
+  Node *node = NODE_IDX (node_idx);
+  Histable *cur_obj = get_hist_obj (node);
+  Hist_data::HistItem *hi = NULL;
+  if (NULL == objs)   // Special case: get root
+    hi = hist_data->append_hist_item (cur_obj);
+  else
+    {
+      if (dpth == objs->size ())
+       hi = hist_data->append_hist_item (cur_obj);
+      else if (cur_obj == objs->fetch (dpth))
+       {
+         // Recursively process all descendants
+         int dsize = NUM_DESCENDANTS (node);
+         for (int index = 0; index < dsize; index++)
+           get_cle_metrics (objs, node->descendants->fetch (index), dpth + 1);
+         if (dpth == objs->size () - 1 && dsize == 0)
+           hi = hist_data->gprof_item;
+       }
+    }
+
+  if (hi != NULL)
+    {
+      MetricList *mlist = hist_data->get_metric_list ();
+      for (long ind = 0, sz = mlist->size (); ind < sz; ind++)
+       {
+         if (xlate[ind] == -1)
+           continue;
+         if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+           continue;
+         Metric *mtr = mlist->get (ind);
+         Metric::SubType subtype = mtr->get_subtype ();
+         if (subtype == Metric::ATTRIBUTED)
+           ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+       }
+    }
+}
+
+void
+PathTree::ftree_reset ()
+{
+  if (pathTreeType == PATHTREE_MAIN && indxtype < 0)
+    {
+      reset ();
+      if (ftree_needs_update)
+       {
+         if (ftree_internal == NULL)
+           {
+             ftree_internal = new PathTree (dbev, indxtype,
+                                            PATHTREE_INTERNAL_FUNCTREE);
+             if (ftree_internal == NULL)
+               return;
+           }
+         ftree_internal->ftree_build (this);
+         ftree_needs_update = false;
+       }
+    }
+}
+
+void
+PathTree::ftree_build (PathTree * mstr)
+{
+  fini ();
+  init ();
+  allocate_slots (mstr->slots, mstr->nslots);
+  ftree_build (mstr, mstr->root_idx, root_idx);
+  depth = mstr->depth;
+  depth_map_build ();
+}
+
+#if DEBUG_FTREE // possibly TBR
+void
+PathTree::ftree_dump ()
+{
+  hrtime_t starttime, endtime;
+  int nmetrics = 1;
+  // int nmetrics = nslots;
+  for (int kk = 0; kk < nmetrics; kk++)
+    {
+      int id = slots[kk].id;
+      starttime = gethrtime ();
+      long nodecnt = 0;
+      for (int ii = 0; ii < depth; ii++)
+       {
+         Vector<Vector<void*>*> *tmp = (Vector<Vector<void*>*>*)get_ftree_level
+                 (id, ii);
+         if (tmp == NULL)
+           continue;
+         long sz = tmp->get (0)->size ();
+         nodecnt += sz;
+#if 1
+         //   fprintf(stderr, "... finished (%ld nodes)\n", sz);
+#else
+         Vector<NodeIdx> *nodeIdxList = (Vector<NodeIdx> *)tmp->get (0);
+         Vector<NodeIdx> *ancestorNodeIdxList = (Vector<NodeIdx> *)tmp->get (1);
+         Vector<uint64_t> *idList = (Vector<uint64_t> *)tmp->get (2);
+         Vector<uint64_t> *vals = (Vector<uint64_t> *)tmp->get (3);
+         for (int jj = 0; jj < sz; jj++)
+           fprintf (stderr, " ...%d:%d node=%ld, anc=%ld, id=%llu, val=%llu\n",
+                    sz, jj, nodeIdxList->get (jj),
+                    ancestorNodeIdxList->get (jj),
+                    idList->get (jj), vals->get (jj));
+#endif
+         destroy (tmp);
+       }
+      endtime = gethrtime ();
+      fprintf (stderr, "====================== %ld nodes time=%llu\n",
+              nodecnt, (endtime - starttime) / 1000 / 1000);
+    }
+}
+#endif
+
+// ftree: translate mstr Histable::INSTR to Histable::FUNCTION
+void
+PathTree::ftree_build (PathTree *mstr, NodeIdx mstr_node_idx,
+                      NodeIdx local_node_idx)
+{
+  // requires: slots, nslots
+  Node *mstr_node = mstr->NODE_IDX (mstr_node_idx);
+  int dsize = NUM_DESCENDANTS (mstr_node);
+
+  // Add metrics
+  for (int i = 0; i < nslots; i++)
+    {
+      if (i >= mstr->nslots)
+       continue; //weird
+      if (slots[i].vtype != mstr->slots[i].vtype)
+       continue; //weird
+      TValue val;
+      val.ll = 0;
+      mstr->ASN_METRIC_VAL (val, mstr->slots[i], mstr_node_idx);
+      int64_t mval;
+      switch (slots[i].vtype)
+       {
+       case VT_ULLONG:
+       case VT_LLONG:
+         mval = val.ll;
+         break;
+       case VT_INT:
+         mval = val.i;
+         break;
+       default:
+         mval = 0;
+         break;
+       }
+      if (mval)
+       {
+         Slot * mslot = SLOT_IDX (i);
+         if (mslot)
+           INCREMENT_METRIC (mslot, local_node_idx, mval);
+       }
+    }
+
+  // Recursively process all descendants
+  for (int index = 0; index < dsize; index++)
+    {
+      NodeIdx mstr_desc_node_idx = mstr_node->descendants->fetch (index);
+      Node *mstr_desc_node = mstr->NODE_IDX (mstr_desc_node_idx);
+      Function *func = (Function*) mstr_desc_node->instr->convertto (Histable::FUNCTION);
+      int mstr_desc_dsize = NUM_DESCENDANTS (mstr_desc_node);
+      bool leaf = (mstr_desc_dsize == 0);
+      NodeIdx local_desc_node_idx = find_desc_node (local_node_idx, func, leaf);
+      ftree_build (mstr, mstr_desc_node_idx, local_desc_node_idx);
+    }
+}
+
+void
+PathTree::depth_map_build ()
+{
+  destroy (depth_map);
+  depth_map = new Vector<Vector<NodeIdx>*>(depth);
+  if (depth)
+    {
+      depth_map->put (depth - 1, 0); // fill vector with nulls
+      depth_map_build (root_idx, 0);
+    }
+}
+
+void
+PathTree::depth_map_build (NodeIdx node_idx, int dpth)
+{
+  Node *node = NODE_IDX (node_idx);
+
+  Vector<NodeIdx> *node_idxs = depth_map->get (dpth);
+  if (node_idxs == NULL)
+    {
+      node_idxs = new Vector<NodeIdx>();
+      depth_map->store (dpth, node_idxs);
+    }
+  node_idxs->append (node_idx);
+
+  // Recursively process all descendants
+  int dsize = NUM_DESCENDANTS (node);
+  for (int index = 0; index < dsize; index++)
+    {
+      NodeIdx desc_node_idx = node->descendants->fetch (index);
+      depth_map_build (desc_node_idx, dpth + 1);
+    }
+}
+
+int
+PathTree::get_ftree_depth ()
+{ // external use only
+  ftree_reset ();
+  if (!ftree_internal)
+    return 0;
+  return ftree_internal->get_depth ();
+}
+
+Vector<Function*>*
+PathTree::get_ftree_funcs ()
+{ // external use only
+  ftree_reset ();
+  if (!ftree_internal)
+    return NULL;
+  return ftree_internal->get_funcs ();
+}
+
+Vector<Function*>*
+PathTree::get_funcs ()
+{
+  // get unique functions
+  if (fn_map == NULL)
+    return NULL;
+  return fn_map->keySet ();
+}
+
+Vector<void*>*
+PathTree::get_ftree_level (BaseMetric *bm, int dpth)
+{ // external use only
+  ftree_reset ();
+  if (!ftree_internal)
+    return NULL;
+  return ftree_internal->get_level (bm, dpth);
+}
+
+Vector<void*>*
+PathTree::get_level (BaseMetric *bm, int dpth)
+{
+  // Nodes at tree depth dpth
+  if (dpth < 0 || dpth >= depth)
+    return NULL;
+  if (depth_map == NULL)
+    return NULL;
+  Vector<NodeIdx> *node_idxs = depth_map->get (dpth);
+  return get_nodes (bm, node_idxs);
+}
+
+Vector<void*>*
+PathTree::get_ftree_node_children (BaseMetric *bm, NodeIdx node_idx)
+{ // external use only
+  ftree_reset ();
+  if (!ftree_internal)
+    return NULL;
+  return ftree_internal->get_node_children (bm, node_idx);
+}
+
+Vector<void*>*
+PathTree::get_node_children (BaseMetric *bm, NodeIdx node_idx)
+{
+  // Nodes that are children of node_idx
+  if (depth_map == NULL)
+    return NULL;
+  if (node_idx == 0)  // special case for root
+    return get_nodes (bm, depth_map->get (0));
+  if (node_idx < 0 || node_idx >= nodes)
+    return NULL;
+  Node *node = NODE_IDX (node_idx);
+  if (node == NULL)
+    return NULL;
+  Vector<NodeIdx> *node_idxs = node->descendants;
+  return get_nodes (bm, node_idxs);
+}
+
+Vector<void*>*
+PathTree::get_nodes (BaseMetric *bm, Vector<NodeIdx> *node_idxs)
+{ // used for ftree
+  // capture info for node_idxs:
+  //   node's idx
+  //   node->ancestor idx
+  //   node->instr->id
+  //   mind metric value // in the future, could instead accept vector of mind
+  if (node_idxs == NULL)
+    return NULL;
+  long sz = node_idxs->size ();
+  if (sz <= 0)
+    return NULL;
+
+  bool calculate_metric = false;
+  ValueTag vtype;
+  int slot_idx;
+  double prec;
+  if (bm != NULL)
+    {
+      int mind = bm->get_id ();
+      slot_idx = find_slot (mind); // may be -1 (CPI and IPC)
+      prec = bm->get_precision ();
+      vtype = bm->get_vtype ();
+    }
+  else
+    {
+      slot_idx = -1;
+      prec = 1.0;
+      vtype = VT_INT;
+    }
+
+  if (slot_idx >= 0)
+    {
+      switch (vtype)
+       {
+       case VT_ULLONG:
+       case VT_LLONG:
+       case VT_INT:
+         if (slots[slot_idx].vtype == vtype)
+           calculate_metric = true;
+         else
+           DBG (assert (false));
+         break;
+       case VT_DOUBLE:
+         calculate_metric = true;
+         break;
+       default:
+         break;
+       }
+    }
+
+  Vector<void*> *results = new Vector<void*>(4);
+  if (!calculate_metric)
+    results->store (3, NULL);
+  else
+    {
+      // Code below cribbed from Dbe.cc:dbeGetTableDataV2Data.
+      // TBD: possibly create an intermediate HistData and instead call that routine
+      switch (vtype)
+       {
+       case VT_ULLONG:
+       case VT_LLONG:
+         {
+           Vector<long long> *vals = new Vector<long long>(sz);
+           for (long i = 0; i < sz; i++)
+             {
+               NodeIdx node_idx = node_idxs->get (i);
+               TValue val;
+               val.ll = 0;
+               ASN_METRIC_VAL (val, slots[slot_idx], node_idx);
+               vals->append (val.ll);
+             }
+           results->store (3, vals);
+           break;
+         }
+       case VT_DOUBLE:
+         {
+           Vector<double> *vals = new Vector<double>(sz);
+           TValue val;
+           val.tag = slots[slot_idx].vtype; // required for to_double();
+           for (long i = 0; i < sz; i++)
+             {
+               NodeIdx node_idx = node_idxs->get (i);
+               val.ll = 0;
+               ASN_METRIC_VAL (val, slots[slot_idx], node_idx);
+               double dval = val.to_double ();
+               dval /= prec;
+               vals->append (dval);
+             }
+           results->store (3, vals);
+           break;
+         }
+       case VT_INT:
+         {
+           Vector<int> *vals = new Vector<int>(sz);
+           for (long i = 0; i < sz; i++)
+             {
+               NodeIdx node_idx = node_idxs->get (i);
+               TValue val;
+               val.i = 0;
+               ASN_METRIC_VAL (val, slots[slot_idx], node_idx);
+               vals->append (val.i);
+             }
+           results->store (3, vals);
+           break;
+         }
+       default:
+         results->store (3, NULL);
+         break;
+       }
+    }
+
+  Vector<int> *nodeIdxList = new Vector<int>(sz);
+  Vector<int> *ancestorNodeIdxList = new Vector<int>(sz);
+  Vector<uint64_t> *idList = new Vector<uint64_t>(sz);
+  for (long i = 0; i < sz; i++)
+    {
+      NodeIdx node_idx = node_idxs->get (i);
+      Node *node = NODE_IDX (node_idx);
+      NodeIdx ancestor_idx = node->ancestor;
+      Histable *func = node->instr;
+      nodeIdxList->append (node_idx);
+      ancestorNodeIdxList->append (ancestor_idx);
+      idList->append (func->id);
+    }
+
+  results->store (0, nodeIdxList);
+  results->store (1, ancestorNodeIdxList);
+  results->store (2, idList);
+  return results;
+}
+
+void
+PathTree::get_cle_metrics (Vector<Histable*> *objs)
+{
+  if (NULL == objs || objs->fetch (0) == get_hist_obj (NODE_IDX (root_idx)))
+    // Call Tree optimization
+    get_cle_metrics (objs, root_idx, 0);
+  else
+    // General case
+    get_cle_metrics (objs, root_idx, -1, -1, 0);
+}
+
+void
+PathTree::get_metrics (Vector<Function*> *functions, Histable *context)
+{
+  Function *fitem;
+  int excl_ok, incl_ok;
+  NodeIdx node_idx;
+  Node *node, *anc;
+  int index;
+
+  Vec_loop (Function*, functions, index, fitem)
+  {
+    node_idx = fn_map->get (fitem);
+    for (; node_idx; node_idx = node->funclist)
+      {
+       node = NODE_IDX (node_idx);
+       Histable *h_obj = get_hist_obj (node, context);
+       if (h_obj == NULL)
+         continue;
+
+       // Check for recursion (inclusive metrics)
+       incl_ok = 1;
+       for (anc = NODE_IDX (node->ancestor); anc;
+               anc = NODE_IDX (anc->ancestor))
+         {
+           if (h_obj == get_hist_obj (anc, context))
+             {
+               incl_ok = 0;
+               break;
+             }
+         }
+
+       // Check for leaf nodes (exclusive metrics)
+       excl_ok = 0;
+       if (IS_LEAF (node))
+         excl_ok = 1;
+
+       h_obj = get_compare_obj (h_obj);
+       Hist_data::HistItem *hi = hist_data->append_hist_item (h_obj);
+
+       if (!excl_ok)
+         hist_data->get_callsite_mark ()->put (h_obj, 1);
+       MetricList *mlist = hist_data->get_metric_list ();
+       for (long ind = 0, sz = mlist->size (); ind < sz; ind++)
+         {
+           if (xlate[ind] == -1)
+             continue;
+           Metric *mtr = mlist->get (ind);
+           Metric::SubType subtype = mtr->get_subtype ();
+           if (subtype == Metric::INCLUSIVE && !incl_ok)
+             continue;
+           if (subtype == Metric::EXCLUSIVE && !excl_ok)
+             continue;
+           if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+             continue;
+           ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+         }
+      }
+  }
+}
+
+void
+PathTree::get_self_metrics (Vector<Histable*> *objs, NodeIdx node_idx,
+                           bool seen, int dpth)
+{
+  Node *node = NODE_IDX (node_idx);
+  Histable *cur_obj = get_hist_obj (node);
+  obj_list[dpth] = cur_obj;
+
+  bool match = false;
+  int nobj = objs->size ();
+  if (dpth + 1 >= nobj)
+    {
+      match = true;
+      for (int i = 0; i < nobj; ++i)
+       {
+         if (objs->fetch (i) != obj_list[dpth - nobj + 1 + i])
+           {
+             match = false;
+             break;
+           }
+       }
+    }
+
+  if (match)
+    {
+      Hist_data::HistItem *hi = hist_data->append_hist_item (cur_obj);
+      int incl_ok = !seen;
+      int excl_ok = 0;
+      if (IS_LEAF (node) || node == NODE_IDX (root_idx))
+       excl_ok = 1;
+      MetricList *mlist = hist_data->get_metric_list ();
+      for (long ind = 0, sz = mlist->size (); ind < sz; ind++)
+       {
+         if (xlate[ind] == -1)
+           continue;
+         if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+           continue;
+         Metric *mtr = mlist->get (ind);
+         Metric::SubType subtype = mtr->get_subtype ();
+         switch (subtype)
+           {
+           case Metric::INCLUSIVE:
+             if (incl_ok && hi)
+               ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+             break;
+           case Metric::EXCLUSIVE:
+           case Metric::ATTRIBUTED:
+             if (excl_ok && hi)
+               ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+             break;
+           case Metric::DATASPACE:
+             if (hi)
+               ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+             break;
+             // ignoring the following cases (why?)
+           case Metric::STATIC:
+             break;
+           }
+       }
+    }
+
+  if (dbeSession->is_interactive ())
+    {
+      ndone++;
+      int new_percent = 95 * ndone / nodes;
+      if (new_percent > percent)
+       {
+         percent = new_percent;
+         theApplication->set_progress (percent, NULL);
+       }
+    }
+
+  // Recursively process all descendants
+  int index;
+  int dsize = NUM_DESCENDANTS (node);
+  for (index = 0; index < dsize; index++)
+    get_self_metrics (objs, node->descendants->fetch (index),
+                     seen || match, dpth + 1);
+}
+
+void
+PathTree::get_self_metrics (Vector<Histable*> *objs)
+{
+  get_self_metrics (objs, root_idx, false, 0);
+}
+
+void
+PathTree::get_self_metrics (Histable *obj, Vector<Function*> *funclist,
+                           Vector<Histable*>* sel_objs)
+{
+  int excl_ok, incl_ok;
+  NodeIdx node_idx;
+  Node *node, *anc;
+
+  if (obj == NULL)
+    return;
+
+  SourceFile *src = NULL;
+  if (obj && obj->get_type () == Histable::LINE)
+    {
+      DbeLine *dbeline = (DbeLine*) obj;
+      src = dbeline->sourceFile;
+    }
+
+  Hist_data::HistItem *hi = hist_data->append_hist_item (obj);
+  for (int i = 0, sz = funclist ? funclist->size () : 0; i < sz; i++)
+    {
+      Function *fitem = (Function*) get_compare_obj (funclist->fetch (i));
+      node_idx = fn_map->get (fitem);
+      for (; node_idx; node_idx = node->funclist)
+       {
+         node = NODE_IDX (node_idx);
+         if (obj && obj->get_type () == Histable::LINE)
+           {
+             Histable *h = get_hist_obj (node, src);
+             if (h == NULL)
+               continue;
+             if (h->convertto (Histable::LINE) != obj->convertto (Histable::LINE))
+               continue;
+           }
+         else if (get_hist_obj (node, src) != obj)
+           continue;
+
+         // Check for recursion (inclusive metrics)
+         incl_ok = 1;
+         for (anc = NODE_IDX (node->ancestor); anc;
+                 anc = NODE_IDX (anc->ancestor))
+           {
+             if (get_hist_obj (anc, src) == obj)
+               {
+                 incl_ok = 0;
+                 break;
+               }
+             if (sel_objs != NULL)
+               for (int k = 0; k < sel_objs->size (); k++)
+                 if (sel_objs->fetch (k) == get_hist_obj (anc, src))
+                   {
+                     incl_ok = 0;
+                     break;
+                   }
+           }
+
+         // Check for leaf nodes (exclusive metrics)
+         excl_ok = 0;
+         if (IS_LEAF (node) || node == NODE_IDX (root_idx))
+           excl_ok = 1;
+
+         MetricList *mlist = hist_data->get_metric_list ();
+         for (long ind = 0, ind_sz = mlist->size (); ind < ind_sz; ind++)
+           {
+             if (xlate[ind] == -1)
+               continue;
+             Metric *mtr = mlist->get (ind);
+             Metric::SubType subtype = mtr->get_subtype ();
+             if (subtype == Metric::INCLUSIVE && !incl_ok)
+               continue;
+             if (subtype == Metric::EXCLUSIVE && !excl_ok)
+               continue;
+             if (subtype == Metric::ATTRIBUTED && !excl_ok)
+               continue;
+             if (IS_MVAL_ZERO (slots[xlate[ind]], node_idx))
+               continue;
+             ADD_METRIC_VAL (hi->value[ind], slots[xlate[ind]], node_idx);
+           }
+       }
+    }
+}
+
+Vector<Histable*> *
+PathTree::get_clr_instr (Histable * func)
+{
+  Vector<Histable*> * instrs = NULL;
+  if (func->get_type () != Histable::FUNCTION)
+    return NULL;
+  NodeIdx node_idx = fn_map->get ((Function*) func);
+  Node *node = NODE_IDX (node_idx);
+  if (node == NULL)
+    return new Vector<Histable*>();
+  int instr_num = 0;
+  for (; node; node = NODE_IDX (node->funclist))
+    instr_num++;
+  instrs = new Vector<Histable*>(instr_num);
+  node = NODE_IDX (node_idx);
+  Histable *instr = NODE_IDX (node->ancestor)->instr;
+  instr_num = 0;
+  instrs->store (instr_num, instr);
+  node = NODE_IDX (node->funclist);
+  for (; node; node = NODE_IDX (node->funclist))
+    {
+      instr = NODE_IDX (node->ancestor)->instr;
+      instr_num++;
+      instrs->store (instr_num, instr);
+    }
+  return instrs;
+}
+
+Vector<void*> *
+PathTree::get_cle_instr (Histable * func, Vector<Histable*>*&instrs)
+{
+  if (func->get_type () != Histable::FUNCTION)
+    return NULL;
+  NodeIdx node_idx = fn_map->get ((Function*) func);
+  Node *node = NODE_IDX (node_idx);
+  if (node == NULL)
+    {
+      instrs = new Vector<Histable*>();
+      return new Vector<void*>();
+    }
+  int instr_num = 0;
+  for (; node; node = NODE_IDX (node->funclist))
+    instr_num++;
+  instrs = new Vector<Histable*>(instr_num);
+  Vector<void*> *callee_info = new Vector<void*>(instr_num);
+  node = NODE_IDX (node_idx);
+  Histable *instr = node->instr;
+  instr_num = 0;
+  instrs->store (instr_num, instr);
+  int dec_num = 0;
+  NodeIdx dec_idx = 0;
+  if (NUM_DESCENDANTS (node) > 0)
+    {
+      Vector<Histable*> * callee_instrs = new Vector<Histable*>(node->descendants->size ());
+      Vec_loop (NodeIdx, node->descendants, dec_num, dec_idx)
+      {
+       Node * dec_node = NODE_IDX (dec_idx);
+       //XXXX Note: there can be more than one instrs in one leaf function
+       callee_instrs->store (dec_num, dec_node->instr);
+      }
+      callee_info->store (instr_num, callee_instrs);
+    }
+  else
+    callee_info->store (instr_num, NULL);
+  node = NODE_IDX (node->funclist);
+  for (; node; node = NODE_IDX (node->funclist))
+    {
+      instr = node->instr;
+      instr_num++;
+      instrs->store (instr_num, instr);
+      if (NUM_DESCENDANTS (node) > 0)
+       {
+         Vector<Histable*> * callee_instrs = new Vector<Histable*>(node->descendants->size ());
+         Vec_loop (NodeIdx, node->descendants, dec_num, dec_idx)
+         {
+           Node * dec_node = NODE_IDX (dec_idx);
+           //XXXX Note: there can be more than one instrs in one leaf function
+           callee_instrs->store (dec_num, dec_node->instr);
+         }
+         callee_info->store (instr_num, callee_instrs);
+       }
+      else
+       callee_info->store (instr_num, NULL);
+    }
+  return callee_info;
+}
+
+//
+//
+// The following methods are used for debugging purpose only.
+//
+//
+static int maxdepth;
+static int maxwidth;
+
+void
+PathTree::print (FILE *fd)
+{
+  (void) reset ();
+  fprintf (fd, NTXT ("n = %lld, dn = %lld, MD = %lld\n\n"),
+          (long long) nodes, (long long) dnodes, (long long) depth);
+  maxdepth = 0;
+  maxwidth = 0;
+  print (fd, root, 0);
+  fprintf (fd, NTXT ("md = %lld, mw = %lld\n"),
+          (long long) maxdepth, (long long) maxwidth);
+}
+
+void
+PathTree::print (FILE *fd, PathTree::Node *node, int lvl)
+{
+  const char *t;
+  char *n;
+  if (lvl + 1 > maxdepth)
+    maxdepth = lvl + 1;
+  for (int i = 0; i < lvl; i++)
+    fprintf (fd, NTXT ("-"));
+  Histable *instr = node->instr;
+  if (instr->get_type () == Histable::LINE)
+    {
+      t = "L";
+      n = ((DbeLine *) instr)->func->get_name ();
+    }
+  else if (instr->get_type () == Histable::INSTR)
+    {
+      t = "I";
+      n = ((DbeInstr *) instr)->func->get_name ();
+    }
+  else
+    {
+      t = "O";
+      n = instr->get_name ();
+    }
+  long long addr = (long long) instr->get_addr ();
+  fprintf (fd, NTXT ("%s %s (0x%08llx) -- ndesc = %lld\n"),
+          t, n, addr, (long long) (NUM_DESCENDANTS (node)));
+
+  // Recursively process all descendants
+  int dsize = NUM_DESCENDANTS (node);
+  if (dsize > maxwidth)
+    maxwidth = dsize;
+  for (int index = 0; index < dsize; index++)
+    print (fd, NODE_IDX (node->descendants->fetch (index)), lvl + 1);
+}
+
+void
+PathTree::printn (FILE *fd)
+{
+  int n = dbg_nodes (root);
+  fprintf (fd, GTXT ("Number of nodes: %d, total size: %d\n"), n, (int) (n * sizeof (Node)));
+}
+
+void
+PathTree::dumpNodes (FILE *fd, Histable *obj)
+{
+  const char *t;
+  char *n;
+  NodeIdx node_idx = fn_map->get ((Function*) obj);
+  Node *node = NODE_IDX (node_idx);
+  if (node == NULL)
+    {
+      fprintf (fd, GTXT ("No nodes associated with %s\n"), obj->get_name ());
+      return;
+    }
+  Histable *instr = node->instr;
+  for (; node; node = NODE_IDX (node->funclist))
+    {
+      instr = node->instr;
+      if (instr->get_type () == Histable::LINE)
+       {
+         t = "L";
+         n = ((DbeLine *) instr)->func->get_name ();
+       }
+      else if (instr->get_type () == Histable::INSTR)
+       {
+         t = "I";
+         n = ((DbeInstr *) instr)->func->get_name ();
+       }
+      else
+       {
+         t = "O";
+         n = instr->get_name ();
+       }
+      long long addr = (long long) instr->get_addr ();
+      if (addr <= 0xFFFFFFFFU)
+       fprintf (fd, NTXT ("0x%08x -- %s %s\n"), (uint32_t) addr, t, n);
+      else
+       fprintf (fd, NTXT ("0x%016llX -- %s %s\n"), addr, t, n);
+    }
+}
+
+int
+PathTree::dbg_nodes (PathTree::Node *node)
+{
+  int res = 1;
+  int dsize = NUM_DESCENDANTS (node);
+  for (int index = 0; index < dsize; index++)
+    res += dbg_nodes (NODE_IDX (node->descendants->fetch (index)));
+  return res;
+}
+
+static int mind_g;
+
+int
+leak_alloc_comp (const void *s1, const void *s2)
+{
+  // See Hist_data::sort_compare() for duplicate code
+  int result = 0;
+  CStack_data::CStack_item *t1, *t2;
+  t1 = *(CStack_data::CStack_item **)s1;
+  t2 = *(CStack_data::CStack_item **)s2;
+
+  switch (t1->value[mind_g].tag)
+    {
+    case VT_INT:
+      if (t1->value[mind_g].i < t2->value[mind_g].i)
+       result = -1;
+      else if (t1->value[mind_g].i > t2->value[mind_g].i)
+       result = 1;
+      else
+       result = 0;
+      break;
+    case VT_LLONG:
+      if (t1->value[mind_g].ll < t2->value[mind_g].ll)
+       result = -1;
+      else if (t1->value[mind_g].ll > t2->value[mind_g].ll)
+       result = 1;
+      else
+       result = 0;
+      break;
+    case VT_ULLONG:
+      if (t1->value[mind_g].ull < t2->value[mind_g].ull)
+       result = -1;
+      else if (t1->value[mind_g].ull > t2->value[mind_g].ull)
+       result = 1;
+      else
+       result = 0;
+      break;
+      // ignoring the following cases (why?)
+    case VT_SHORT:
+    case VT_FLOAT:
+    case VT_DOUBLE:
+    case VT_HRTIME:
+    case VT_LABEL:
+    case VT_ADDRESS:
+    case VT_OFFSET:
+      break;
+    }
+  // Sort in descending order
+  return -result;
+}
+
+CStack_data *
+PathTree::get_cstack_data (MetricList *mlist)
+{
+  (void) reset ();
+  CStack_data *lam = new CStack_data (mlist);
+  int nmetrics = mlist->get_items ()->size ();
+  mind_g = -1;
+  xlate = new int[nmetrics];
+  for (int mind = 0; mind < nmetrics; mind++)
+    {
+      xlate[mind] = -1;
+      Metric *mtr = mlist->get_items ()->fetch (mind);
+      if (mlist->get_sort_ref_index () == mind)
+       mind_g = mind;
+      xlate[mind] = find_slot (mtr->get_id ());
+    }
+
+  // now fill in the actual data
+  obj_list = new Histable*[depth];
+  get_cstack_list (lam, root_idx, 0);
+  delete[] obj_list;
+
+  if (mind_g >= 0)
+    lam->cstack_items->sort (leak_alloc_comp);
+  delete[] xlate;
+  return lam;
+}
+
+void
+PathTree::get_cstack_list (CStack_data *lam, NodeIdx node_idx, int dpth)
+{
+
+  Node *node = NODE_IDX (node_idx);
+  obj_list[dpth] = node->instr;
+
+  CStack_data::CStack_item *item = NULL;
+  if (IS_LEAF (node))
+    item = lam->new_cstack_item ();
+  int nmetrics = lam->metrics->get_items ()->size ();
+  bool subtree_empty = true;
+
+  for (int mind = 0; mind < nmetrics; mind++)
+    {
+      if (xlate[mind] == -1)
+       continue;
+      if (IS_MVAL_ZERO (slots[xlate[mind]], node_idx))
+       continue;
+      else
+       subtree_empty = false;
+      if (item)
+       {
+         ADD_METRIC_VAL (item->value[mind], slots[xlate[mind]], node_idx);
+         ADD_METRIC_VAL (lam->total->value[mind], slots[xlate[mind]], node_idx);
+       }
+    }
+
+  if (subtree_empty)
+    {
+      delete item;
+      return;
+    }
+
+  if (item)
+    {
+      // Finish processing a leaf node
+      item->stack = new Vector<DbeInstr*>(dpth);
+      for (int i = 1; i <= dpth; i++)
+       item->stack->append ((DbeInstr*) obj_list[i]);
+      lam->cstack_items->append (item);
+    }
+  else
+    {
+      // Recursively process all descendants
+      int dsize = NUM_DESCENDANTS (node);
+      for (int index = 0; index < dsize; index++)
+       get_cstack_list (lam, node->descendants->fetch (index), dpth + 1);
+    }
+}
+
+Emsg *
+PathTree::fetch_stats ()
+{
+  if (statsq == NULL)
+    return NULL;
+  return statsq->fetch ();
+}
+
+void
+PathTree::delete_stats ()
+{
+  if (statsq != NULL)
+    {
+      delete statsq;
+      statsq = new Emsgqueue (NTXT ("statsq"));
+    }
+}
+
+Emsg *
+PathTree::fetch_warnings ()
+{
+  if (warningq == NULL)
+    return NULL;
+  return warningq->fetch ();
+}
+
+void
+PathTree::delete_warnings ()
+{
+  if (warningq != NULL)
+    {
+      delete warningq;
+      warningq = new Emsgqueue (NTXT ("warningq"));
+    }
+}
diff --git a/gprofng/src/PathTree.h b/gprofng/src/PathTree.h
new file mode 100644 (file)
index 0000000..dc3ad1f
--- /dev/null
@@ -0,0 +1,405 @@
+/* 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 _PATH_TREE_H
+#define _PATH_TREE_H
+
+#include <vec.h>
+#include <Map.h>
+
+#include "dbe_structs.h"
+#include "Hist_data.h"
+#include "Histable.h"
+#include "Metric.h"
+
+typedef enum
+{
+  NORMAL = 0, CANCELED
+} PtreePhaseStatus;
+
+class PathTree
+{
+public:
+
+  PathTree (DbeView *_dbev, int _indxtype = -1)
+  {
+    construct (_dbev, _indxtype, PATHTREE_MAIN);
+  }
+
+  ~PathTree ();
+
+  static void make_deltas (int vtype, TValue *v1, TValue *v2);
+  static void make_ratios (int vtype, TValue *v1, TValue *v2);
+
+  typedef enum
+  {
+    COMPUTEOPT_NONE = 0,
+    COMPUTEOPT_OMP_CALLEE
+  } PtreeComputeOption;
+
+  Hist_data *compute_metrics (MetricList *, Histable::Type,
+                             Hist_data::Mode, Vector<Histable*>*,
+                             Histable*, Vector<Histable*>* sel_objs = NULL,
+                             PtreeComputeOption flag = COMPUTEOPT_NONE);
+  // Get aggregated callstack data
+  CStack_data *get_cstack_data (MetricList *);
+
+  Vector<Histable*> *get_clr_instr (Histable *);
+  Vector<void*> *get_cle_instr (Histable *, Vector<Histable*>*&);
+
+  int
+  get_status ()
+  {
+    return status;
+  }
+
+  int
+  get_depth ()
+  {
+    return depth;
+  }
+
+  int
+  getStackProp ()
+  {
+    return stack_prop;
+  }
+
+  typedef long NodeIdx;
+
+  struct Node
+  {
+    inline void
+    reset ()
+    {
+      ancestor = 0;
+      descendants = NULL;
+      instr = NULL;
+      funclist = 0;
+    }
+
+    NodeIdx ancestor;
+    Vector<NodeIdx> *descendants;
+    Histable *instr;
+    NodeIdx funclist;
+  };
+
+  static const int CHUNKSZ = 16384;
+
+  inline Node *
+  NODE_IDX (NodeIdx idx)
+  {
+    return idx ? &chunks[idx / CHUNKSZ][idx % CHUNKSZ] : NULL;
+  }
+
+  // queue for messages (statistics for pathtree processing)
+  Emsg *fetch_stats (void);     // fetch the queue of comment messages
+  void delete_stats (void);     // delete the queue of stats messages
+  Emsg *fetch_warnings (void);  // fetch the queue of warnings messages
+  void delete_warnings (void);  // delete the queue of warnings messages
+
+  NodeIdx
+  get_func_nodeidx (Function * func)
+  {
+    return fn_map == NULL ? (NodeIdx) 0 : fn_map->get (func);
+  }
+
+  void print (FILE *);
+  void dumpNodes (FILE *, Histable *);
+
+  // flame charts functions - get values from ftree_internal
+  int get_ftree_depth ();   // Depth of tree
+  Vector<void*>* get_ftree_level (BaseMetric *bm, int dpth);
+  Vector<void*>* get_ftree_node_children (BaseMetric *bm, NodeIdx node_idx);
+  Vector<Function*>* get_ftree_funcs ();
+  Vector<Function*>* get_funcs ();      // Unique functions in tree
+
+private:
+
+  enum
+  {
+    MAX_DESC_HTABLE_SZ = 65535
+  };
+
+  typedef struct hash_node
+  {
+    NodeIdx nd;
+    struct hash_node *next;
+  } hash_node_t;
+
+  int desc_htable_size;
+  int desc_htable_nelem;
+  hash_node_t **descHT;
+
+  struct Slot
+  {
+    int id;
+    ValueTag vtype;
+    union
+    {
+      int **mvals;
+      int64_t **mvals64;
+    };
+  };
+
+  typedef enum
+  {
+    PATHTREE_MAIN = 0,
+    PATHTREE_INTERNAL_OMP,
+    PATHTREE_INTERNAL_FUNCTREE
+  } PathTreeType;
+
+  DbeView *dbev;
+  int indxtype;
+  int stack_prop;
+  Expression *indx_expr;
+  Histable *total_obj;
+  Map<Function*, NodeIdx> *fn_map;
+  Map<uint64_t, NodeIdx> *pathMap;
+  Map<uint64_t, uint64_t> *hideMap;
+  int status;
+  NodeIdx root_idx;
+  Node *root;
+  int depth;
+  long nodes;
+  long dnodes;
+  long nchunks;
+  Node **chunks;
+  int nslots;
+  Slot *slots;
+  int phaseIdx;
+  int nexps;
+  Emsgqueue *statsq;
+  Emsgqueue *warningq;
+  Hist_data *hist_data;
+  int percent;
+  int ndone;
+  Histable **obj_list;
+  Node **node_list;
+  int *xlate;
+  bool cancel_ok;
+  PathTreeType pathTreeType;
+  PathTree *ptree_internal;
+  PathTree *ftree_internal;             // function-based pathtree
+  bool ftree_needs_update;
+  Vector<Vector<NodeIdx>*> *depth_map; // for each depth level, list of nodes
+
+  void init ();
+  void fini ();
+  PtreePhaseStatus reset ();
+  PtreePhaseStatus add_experiment (int);
+  PtreePhaseStatus process_packets (Experiment*, DataView*, int);
+  DataView *get_filtered_events (int exp_index, int data_type);
+  void construct (DbeView *_dbev, int _indxtype, PathTreeType _pathTreeType);
+
+  PathTree (DbeView *_dbev, int _indxtype, PathTreeType _pathTreeType)
+  {
+    construct (_dbev, _indxtype, _pathTreeType);
+  }
+
+  inline int *
+  allocate_chunk (int **p, NodeIdx idx)
+  {
+    int *res = new int[CHUNKSZ];
+    for (int i = 0; i < CHUNKSZ; i++)
+      res[i] = 0;
+    p[idx] = res;
+    return res;
+  };
+
+  inline int64_t *
+  allocate_chunk (int64_t **p, NodeIdx idx)
+  {
+    int64_t *res = new int64_t[CHUNKSZ];
+    for (int i = 0; i < CHUNKSZ; i++)
+      res[i] = 0;
+    p[idx] = res;
+    return res;
+  };
+
+  inline Node *
+  allocate_chunk (Node **p, NodeIdx idx)
+  {
+    Node *res = new Node[CHUNKSZ];
+    for (int i = 0; i < CHUNKSZ; i++)
+      res[i].reset ();
+    p[idx] = res;
+    return res;
+  };
+
+  inline bool
+  IS_MVAL_ZERO (Slot& slot, NodeIdx idx)
+  {
+    if (slot.vtype == VT_LLONG || slot.vtype == VT_ULLONG)
+      {
+       int64_t *tmp = slot.mvals64[idx / CHUNKSZ];
+       return tmp ? tmp[idx % CHUNKSZ] == 0 : true;
+      }
+    else
+      {
+       int *tmp = slot.mvals[idx / CHUNKSZ];
+       return tmp ? tmp[idx % CHUNKSZ] == 0 : true;
+      }
+  }
+
+  inline void
+  ASN_METRIC_VAL (TValue& v, Slot& slot, NodeIdx idx)
+  {
+    if (slot.vtype == VT_LLONG)
+      {
+       int64_t *tmp = slot.mvals64[idx / CHUNKSZ];
+       if (tmp)
+         v.ll = tmp[idx % CHUNKSZ];
+      }
+    else if (slot.vtype == VT_ULLONG)
+      {
+       uint64_t *tmp = (uint64_t *) slot.mvals64[idx / CHUNKSZ];
+       if (tmp)
+         v.ull = tmp[idx % CHUNKSZ];
+      }
+    else
+      {
+       int *tmp = slot.mvals[idx / CHUNKSZ];
+       if (tmp)
+         v.i = tmp[idx % CHUNKSZ];
+      }
+  }
+
+  inline void
+  ADD_METRIC_VAL (TValue& v, Slot& slot, NodeIdx idx)
+  {
+    if (slot.vtype == VT_LLONG)
+      {
+       int64_t *tmp = slot.mvals64[idx / CHUNKSZ];
+       if (tmp)
+         v.ll += tmp[idx % CHUNKSZ];
+      }
+    else if (slot.vtype == VT_ULLONG)
+      {
+       uint64_t *tmp = (uint64_t *) slot.mvals64[idx / CHUNKSZ];
+       if (tmp)
+         v.ull += tmp[idx % CHUNKSZ];
+      }
+    else
+      {
+       int *tmp = slot.mvals[idx / CHUNKSZ];
+       if (tmp) v.i += tmp[idx % CHUNKSZ];
+      }
+  }
+
+  inline void
+  SUB_METRIC_VAL (TValue& v, Slot& slot, NodeIdx idx)
+  {
+    if (slot.vtype == VT_LLONG)
+      {
+       int64_t *tmp = slot.mvals64[idx / CHUNKSZ];
+       if (tmp)
+         v.ll -= tmp[idx % CHUNKSZ];
+      }
+    else if (slot.vtype == VT_ULLONG)
+      {
+       uint64_t *tmp = (uint64_t *) slot.mvals64[idx / CHUNKSZ];
+       if (tmp)
+         v.ull -= tmp[idx % CHUNKSZ];
+      }
+    else
+      {
+       int *tmp = slot.mvals[idx / CHUNKSZ];
+       if (tmp)
+         v.i -= tmp[idx % CHUNKSZ];
+      }
+  }
+
+  inline void
+  INCREMENT_METRIC (Slot *slot, NodeIdx idx, int64_t val)
+  {
+    if (slot->vtype == VT_LLONG)
+      {
+       int64_t *tmp = slot->mvals64[idx / CHUNKSZ];
+       if (tmp == NULL)
+         tmp = allocate_chunk (slot->mvals64, idx / CHUNKSZ);
+       tmp[idx % CHUNKSZ] += val;
+      }
+    else if (slot->vtype == VT_ULLONG)
+      {
+       uint64_t *tmp = (uint64_t *) slot->mvals64[idx / CHUNKSZ];
+       if (tmp == NULL)
+         tmp = (uint64_t *) allocate_chunk (slot->mvals64, idx / CHUNKSZ);
+       tmp[idx % CHUNKSZ] += val;
+      }
+    else
+      {
+       int *tmp = slot->mvals[idx / CHUNKSZ];
+       if (tmp == NULL)
+         tmp = allocate_chunk (slot->mvals, idx / CHUNKSZ);
+       tmp[idx % CHUNKSZ] += (int) val;
+      }
+  }
+
+  inline Slot *
+  SLOT_IDX (int idx)
+  {
+    if (idx < 0 || idx >= nslots)
+      return NULL;
+    return &slots[idx];
+  }
+
+  int allocate_slot (int id, ValueTag vtype);
+  void allocate_slots (Slot *slots, int nslots);
+  int find_slot (int);
+  NodeIdx new_Node (NodeIdx, Histable*, bool);
+  NodeIdx find_path (Experiment*, DataView*, long);
+  NodeIdx find_desc_node (NodeIdx, Histable*, bool);
+  NodeIdx find_in_desc_htable (NodeIdx, Histable*, bool);
+  Histable *get_hist_obj (Node *, Histable* = NULL);
+  Histable *get_hist_func_obj (Node *);
+  Histable *get_compare_obj (Histable *obj);
+  void get_metrics (NodeIdx, int);
+  void get_metrics (Vector<Function*> *, Histable *);
+  void get_clr_metrics (Vector<Histable*>*, NodeIdx, int, int);
+  void get_clr_metrics (Vector<Histable*>*);
+  void get_cle_metrics (Vector<Histable*>*, NodeIdx, int, int, int);
+  void get_cle_metrics (Vector<Histable*>*, NodeIdx, int);
+  void get_cle_metrics (Vector<Histable*>*);
+  void get_self_metrics (Vector<Histable*>*, NodeIdx, bool, int);
+  void get_self_metrics (Vector<Histable*>*);
+  void get_self_metrics (Histable *, Vector<Function*> *funclist,
+                        Vector<Histable*>* sel_objs = NULL);
+  void get_cstack_list (CStack_data *, NodeIdx, int);
+
+  // Generate PathTree based on Functions instead of Instructions // Used for flame chart
+  void ftree_reset ();
+  void ftree_build (PathTree *mstr);
+  void ftree_build (PathTree *mstr, NodeIdx mstr_node_idx, NodeIdx local_node_idx);
+  void depth_map_build ();
+  void depth_map_build (NodeIdx node_idx, int depth);
+  Vector<void*>* get_level (BaseMetric *bm, int dpth);
+  Vector<void*>* get_nodes (BaseMetric *bm, Vector<NodeIdx> *node_idxs);
+  Vector<void*>* get_node_children (BaseMetric *bm, NodeIdx node_idx);
+  bool ftree_debug_match_hist_data (Hist_data *data, Hist_data *data_tmp);
+  void ftree_dump ();
+
+  // Debugging functions
+  void print (FILE *, PathTree::Node*, int);
+  void printn (FILE *);
+  int dbg_nodes (PathTree::Node*);
+};
+
+#endif /* _PATH_TREE_H */
diff --git a/gprofng/src/PreviewExp.cc b/gprofng/src/PreviewExp.cc
new file mode 100644 (file)
index 0000000..553afd3
--- /dev/null
@@ -0,0 +1,113 @@
+/* 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 <stdio.h>
+
+#include "PreviewExp.h"
+#include "Data_window.h"
+#include "DbeSession.h"
+#include "Emsg.h"
+#include "Print.h"
+#include "i18n.h"
+
+PreviewExp::PreviewExp (): Experiment () { }
+
+PreviewExp::~PreviewExp () { }//~PreviewExp
+
+Experiment::Exp_status
+PreviewExp::experiment_open (char *path)
+{
+  // Find experiment directory
+  if ((status = find_expdir (path)) != SUCCESS)
+    {
+      size_t len = strlen (path);
+      is_group = ((len > 4) && !strcmp (&path[len - 4], NTXT (".erg")));
+      return status;
+    }
+  else
+    is_group = 0;
+
+  read_log_file ();
+  if (status == FAILURE)
+    return status;
+
+  if (status == INCOMPLETE && resume_ts != MAX_TIME)
+    // experiment is incomplete and "resumed" (non-paused)
+    // PreviewExp does not process all the packets, therefore...
+    //    ... last_event does not reflect reality
+    //    ... we don't know the duration or the end.
+    last_event = ZERO_TIME; // mark last_event as uninitialized
+
+  read_notes_file ();
+  return status;
+}
+
+Vector<char*> *
+PreviewExp::preview_info ()
+{
+  Vector<char*> *info = new Vector<char*>;
+  if (is_group)
+    info->append (GTXT ("Experiment Group"));
+  else
+    info->append (GTXT ("Experiment"));
+  info->append (expt_name);
+
+  if (status == FAILURE /* != SUCCESS */)
+    {
+      if (is_group)
+       {
+         Vector<char*> *grp_list = dbeSession->get_group_or_expt (expt_name);
+         for (int i = 0, grp_sz = grp_list->size (); i < grp_sz; i++)
+           {
+             char *nm = grp_list->fetch (i);
+             char *str = dbe_sprintf (GTXT ("Exp.#%d"), i + 1);
+             info->append (str);
+             info->append (nm);
+           }
+         delete grp_list;
+       }
+      else
+       {
+         info->append (GTXT ("Error message"));
+         info->append (mqueue_str (errorq, GTXT ("No errors\n")));
+       }
+      return info;
+    }
+  info->append (GTXT ("Experiment header"));
+  info->append (mqueue_str (commentq, GTXT ("Empty header\n")));
+  info->append (GTXT ("Error message"));
+  info->append (mqueue_str (errorq, GTXT ("No errors\n")));
+  info->append (GTXT ("Warning message"));
+  info->append (mqueue_str (warnq, GTXT ("No warnings\n")));
+  info->append (GTXT ("Notes"));
+  info->append (mqueue_str (notesq, GTXT ("\n")));
+  return info;
+}
+
+char *
+PreviewExp::mqueue_str (Emsgqueue *msgqueue, char *null_str)
+{
+  char *mesgs = pr_mesgs (msgqueue->fetch (), null_str, "");
+  char *last = mesgs + strlen (mesgs) - 1;
+  if (*last == '\n')
+    *last = '\0';
+  return mesgs;
+}
diff --git a/gprofng/src/PreviewExp.h b/gprofng/src/PreviewExp.h
new file mode 100644 (file)
index 0000000..8b7834a
--- /dev/null
@@ -0,0 +1,49 @@
+/* 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 _PREVIEW_EXP_H
+#define _PREVIEW_EXP_H
+
+#include "Experiment.h"
+#include "vec.h"
+
+class PreviewExp : public Experiment
+{
+public:
+  PreviewExp ();
+  ~PreviewExp ();
+
+  virtual Exp_status experiment_open (char *path);
+
+  Vector<char*> *preview_info ();
+
+  char *
+  getArgList ()
+  {
+    return uarglist;
+  }
+
+private:
+  char *mqueue_str (Emsgqueue *msgqueue, char *null_str);
+
+  int is_group;
+};
+
+#endif /* ! _PREVIEW_EXP_H */
diff --git a/gprofng/src/Print.cc b/gprofng/src/Print.cc
new file mode 100644 (file)
index 0000000..d6662df
--- /dev/null
@@ -0,0 +1,3485 @@
+/* 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 <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <libintl.h>
+//#include <libgen.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "util.h"
+#include "Dbe.h"
+#include "StringBuilder.h"
+#include "DbeSession.h"
+#include "DbeView.h"
+#include "Settings.h"
+#include "Print.h"
+#include "DbeView.h"
+#include "Experiment.h"
+#include "MetricList.h"
+#include "Module.h"
+#include "Function.h"
+#include "DataSpace.h"
+#include "DataObject.h"
+#include "FilterExp.h"
+#include "LoadObject.h"
+#include "Emsg.h"
+#include "Table.h"
+#include "DbeFile.h"
+#include "CallStack.h"
+
+int
+er_print_common_display::open (Print_params *params)
+{
+  pr_params = *params;
+  pr_params.name = dbe_strdup (params->name);
+  if (params->dest == DEST_PRINTER)
+    {
+      tmp_file = dbeSession->get_tmp_file_name (NTXT ("print"), false);
+      dbeSession->tmp_files->append (strdup (tmp_file));
+      out_file = fopen (tmp_file, NTXT ("w"));
+    }
+  else if (params->dest == DEST_OPEN_FILE)
+    out_file = pr_params.openfile;
+  else
+    out_file = fopen (pr_params.name, NTXT ("w"));
+
+  if (out_file == NULL)
+    // Failure
+    return 1;
+  return 0;
+}
+
+bool
+er_print_common_display::print_output ()
+{
+  char *sys_call;
+  bool ret = true;
+  if (pr_params.dest != DEST_OPEN_FILE)
+    fclose (out_file);
+
+  if (pr_params.dest == DEST_PRINTER)
+    {
+      if (streq ((char *) pr_params.name, NTXT ("")))
+       sys_call = dbe_sprintf ("(/usr/bin/lp -c -n%d %s) 2>/dev/null 1>&2",
+                               pr_params.ncopies, tmp_file);
+      else
+       sys_call = dbe_sprintf ("(/usr/bin/lp -c -d%s -n%d %s) 2>/dev/null 1>&2",
+                               pr_params.name, pr_params.ncopies, tmp_file);
+      if (system (sys_call) != 0)
+       ret = false;
+      unlink (tmp_file);
+      free (sys_call);
+    }
+
+  return ret;
+}
+
+// Return the report. If the report size is greater than max, return truncated report
+// Allocates memory, so the caller should free this memory.
+
+char *
+er_print_common_display::get_output (int maxsize)
+{
+  off_t max = (off_t) maxsize;
+  if (out_file != (FILE *) NULL)
+    {
+      fclose (out_file); // close tmp_file
+      out_file = (FILE *) NULL;
+    }
+  struct stat sbuf;
+  int st = stat (tmp_file, &sbuf);
+  if (st == 0)
+    {
+      off_t sz = sbuf.st_size;
+      if (sz > max)
+       return dbe_sprintf (GTXT ("Error: report is too long.\n"));
+      if (sz <= 0)
+       return dbe_sprintf (GTXT ("Error: empty temporary file: %s\n"),
+                           tmp_file);
+      max = sz;
+    }
+
+  FILE *f = fopen (tmp_file, "r");
+  if (f == NULL)
+    return dbe_sprintf (GTXT ("Error: cannot open temporary file: %s\n"),
+                       tmp_file);
+  char *report = (char *) malloc (max);
+  if (report)
+    {
+      if (1 != fread (report, max - 1, 1, f))
+       {
+         fclose (f);
+         free (report);
+         return dbe_sprintf (GTXT ("Error: cannot read temporary file: %s\n"),
+                             tmp_file);
+       }
+      report[max - 1] = 0;
+    }
+  fclose (f);
+  return report;
+}
+
+void
+er_print_common_display::header_dump (int exp_idx)
+{
+  if (load && (exp_idx == exp_idx1))
+    {
+      load = false;
+      print_load_object (out_file);
+    }
+  print_header (dbeSession->get_exp (exp_idx), out_file);
+}
+
+char *
+pr_load_objects (Vector<LoadObject*> *loadobjects, char *lead)
+{
+  int size, i;
+  LoadObject *lo;
+  Emsg *m;
+  char *msg;
+  StringBuilder sb;
+  char *lo_name;
+  size = loadobjects->size ();
+  for (i = 0; i < size; i++)
+    {
+      lo = loadobjects->fetch (i);
+      lo_name = lo->get_name ();
+      if (lo_name != NULL)
+       {
+         size_t len = strlen (lo_name);
+         if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
+           continue;
+       }
+
+      // print the segment name
+      sb.append (lead);
+      sb.append (NTXT (" "));
+      sb.append (lo->get_name ());
+      sb.append (NTXT (" ("));
+      sb.append (lo->get_pathname ());
+      sb.append (NTXT (")\n"));
+
+      // and any warnings
+      m = lo->fetch_warnings ();
+      if (m != NULL)
+       {
+         msg = pr_mesgs (m, NULL, NTXT ("       "));
+         sb.append (msg);
+         free (msg);
+       }
+    }
+  return sb.toString ();
+}
+
+char *
+pr_mesgs (Emsg *msg, const char *null_str, const char *lead)
+{
+  Emsg *m;
+  StringBuilder sb;
+  if (msg == NULL)
+    return dbe_strdup (null_str);
+  for (m = msg; m; m = m->next)
+    {
+      sb.append (lead);
+      sb.append (m->get_msg ());
+      sb.append (NTXT ("\n"));
+    }
+  return sb.toString ();
+}
+
+void
+print_load_object (FILE *out_file)
+{
+  Vector<LoadObject*> *loadobjects = dbeSession->get_text_segments ();
+  char *msg = pr_load_objects (loadobjects, NTXT ("\t"));
+  fprintf (out_file, GTXT ("Load Object Coverage:\n"));
+  fprintf (out_file, NTXT ("%s"), msg);
+  fprintf (out_file,
+          "----------------------------------------------------------------\n");
+  free (msg);
+  delete loadobjects;
+}
+
+void
+print_header (Experiment *exp, FILE *out_file)
+{
+  fprintf (out_file, GTXT ("Experiment: %s\n"), exp->get_expt_name ());
+  char *msg = pr_mesgs (exp->fetch_notes (), NTXT (""), NTXT (""));
+  fprintf (out_file, NTXT ("%s"), msg);
+  free (msg);
+
+  msg = pr_mesgs (exp->fetch_errors (), GTXT ("No errors\n"), NTXT (""));
+  fprintf (out_file, NTXT ("%s"), msg);
+  free (msg);
+
+  msg = pr_mesgs (exp->fetch_warnings (), GTXT ("No warnings\n"), NTXT (""));
+  fprintf (out_file, NTXT ("%s"), msg);
+  free (msg);
+
+  msg = pr_mesgs (exp->fetch_comments (), NTXT (""), NTXT (""));
+  fprintf (out_file, NTXT ("%s"), msg);
+  free (msg);
+
+  msg = pr_mesgs (exp->fetch_pprocq (), NTXT (""), NTXT (""));
+  fprintf (out_file, NTXT ("%s"), msg);
+  free (msg);
+}
+
+void
+get_width (Hist_data *data,
+          MetricList *metrics_list, Metric::HistMetric *hist_metric)
+{
+  Metric *mitem;
+  Metric::HistMetric *hitem;
+  int last_column;
+  int index;
+
+  // find the last visible column.
+  last_column = 0;
+  Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+  {
+    if (mitem->is_visible () || mitem->is_tvisible () || mitem->is_pvisible ())
+      last_column = index;
+  }
+
+  // find the width for each column.
+
+  Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+  {
+    hitem = &hist_metric[index];
+
+    if (mitem->is_visible ())
+      {
+       if (mitem->get_vtype () == VT_LABEL)
+         {
+           if (index == last_column)
+             hitem->maxvalue_width = 0;
+           else
+             hitem->maxvalue_width = data->name_maxlen ();
+           // truncate names which will be too long
+           if (hitem->maxvalue_width > MAX_LEN - 3)
+             hitem->maxvalue_width = MAX_LEN - 3;
+         }
+       else if (mitem->get_vtype () == VT_ADDRESS)
+         {
+           hitem->maxvalue_width = data->value_maxlen (index);
+           if (hitem->maxvalue_width < 13)
+             hitem->maxvalue_width = 13;
+         }
+       else
+         hitem->maxvalue_width = data->value_maxlen (index);
+      }
+    else
+      hitem->maxvalue_width = 0;
+
+    if (mitem->is_tvisible ())
+      {
+       if (mitem->get_visbits () & VAL_RATIO)
+         hitem->maxtime_width = data->value_maxlen (index);
+       else
+         hitem->maxtime_width = data->time_maxlen (index,
+                                                   dbeSession->get_clock (-1));
+      }
+    else
+      {
+       hitem->maxtime_width = 0;
+      }
+  }
+}
+
+void
+get_format (char **fmt_int, char **fmt_real0, char **fmt_real1,
+           MetricList *metrics_list, Metric::HistMetric *hist_metric,
+           int nspace)
+{
+  Metric *mitem;
+  Metric::HistMetric *hitem;
+  int index;
+  int visible, tvisible, pvisible;
+  size_t maxlen;
+  bool prev;
+  char numstr[MAX_LEN], pstr_int[MAX_LEN],
+         pstr_real0[MAX_LEN], pstr_real1[MAX_LEN];
+
+  // find the width for each column.
+  Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+  {
+    hitem = &hist_metric[index];
+    visible = mitem->is_visible ();
+    tvisible = mitem->is_tvisible ();
+    pvisible = mitem->is_pvisible ();
+    *pstr_int = *pstr_real0 = *pstr_real1 = '\0';
+
+    // Get 'Show Value' format
+    const char *sign = (mitem->get_visbits () & VAL_DELTA) ? "+" : "";
+    if (visible)
+      {
+       maxlen = hitem->maxvalue_width;
+       switch (mitem->get_vtype2 ())
+         {
+         case VT_DOUBLE:
+           if (mitem->get_visbits () & VAL_RATIO)
+             {
+               snprintf (numstr, sizeof (numstr), "x %%#%d.0lf    ",
+                         (int) (maxlen - 3));
+               snprintf (pstr_real0, sizeof (pstr_real0), numstr, 0.0);
+               snprintf (pstr_real1, sizeof (pstr_real1), "x%%s%%%d.3lf ",
+                         (int) maxlen);
+             }
+           else
+             {
+               snprintf (numstr, sizeof (numstr), "%%#%s%d.0lf    ", sign,
+                         (int) (maxlen - 3));
+               snprintf (pstr_real0, sizeof (pstr_real0), numstr, 0.0);
+               snprintf (pstr_real1, sizeof (pstr_real1), "%%s%%%s%d.3lf ",
+                         sign, (int) maxlen);
+             }
+           break;
+         case VT_INT:
+           snprintf (pstr_int, sizeof (pstr_int), "%%%s%dd ", sign,
+                     (int) maxlen);
+           break;
+         case VT_LLONG:
+           snprintf (pstr_int, sizeof (pstr_int), "%%%s%dlld ", sign,
+                     (int) maxlen);
+           break;
+         case VT_ULLONG:
+           snprintf (pstr_int, sizeof (pstr_int), "%%%s%dllu ", sign,
+                     (int) maxlen);
+           break;
+         case VT_ADDRESS:
+           if (maxlen <= 13)
+             {
+               snprintf (pstr_int, sizeof (pstr_int), "%%%dd:0x%%08x", 2);
+             }
+           else
+             {
+               snprintf (pstr_int, sizeof (pstr_int), "%%%dd:0x%%08x",
+                         (int) (maxlen - 13));
+             }
+           break;
+         case VT_FLOAT:
+           snprintf (numstr, sizeof (numstr), "%%#%d.0f    ",
+                     (int) (maxlen - 3));
+           snprintf (pstr_real0, sizeof (pstr_real0), numstr, 0.0);
+           snprintf (pstr_real1, sizeof (pstr_real1), "%%%d.3f ",
+                     (int) maxlen);
+           break;
+         case VT_SHORT:
+           snprintf (pstr_int, sizeof (pstr_int), "%%%dhu ", (int) maxlen);
+           break;
+         case VT_LABEL:
+           if (maxlen == 0) // last column
+             snprintf (pstr_int, sizeof (pstr_int), NTXT ("%%s%%s"));
+           else if (maxlen + nspace >= MAX_LEN - 3)
+             snprintf (pstr_int, sizeof (pstr_int), NTXT ("%%s%%-%d.%ds "),
+                       MAX_LEN - 7, MAX_LEN - 7);
+           else
+             snprintf (pstr_int, sizeof (pstr_int), NTXT ("%%s%%-%ds "),
+                       (int) (maxlen + nspace));
+           break;
+         default:
+           break;
+         }
+      }
+
+    // Get 'Show Time' format
+    if (tvisible)
+      {
+       maxlen = hitem->maxtime_width;
+       if (mitem->get_visbits () & VAL_RATIO)
+         {
+           snprintf (numstr, sizeof (numstr), " %%%s#%d.0lf    ",
+                     sign, (int) (maxlen - 3));
+           snprintf (pstr_real0, sizeof (pstr_real0), numstr, 0.0);
+           snprintf (pstr_real1, sizeof (pstr_real1), "%%s%%%s%d.3lf ",
+                     sign, (int) maxlen);
+         }
+       else
+         {
+           snprintf (numstr, sizeof (numstr), "%%%s#%d.0lf    ",
+                     sign, (int) (maxlen - 3));
+           snprintf (pstr_real0, sizeof (pstr_real0), numstr, 0.0);
+           snprintf (pstr_real1, sizeof (pstr_real1), "%%s%%%s%d.3lf ",
+                     sign, (int) maxlen);
+         }
+      }
+
+    // Copy format
+    if (*pstr_int)
+      fmt_int[index] = dbe_strdup (pstr_int);
+    else
+      fmt_int[index] = NULL;
+
+    if (*pstr_real0)
+      fmt_real0[index] = dbe_strdup (pstr_real0);
+    else
+      fmt_real0[index] = NULL;
+
+    if (*pstr_real1)
+      fmt_real1[index] = dbe_strdup (pstr_real1);
+    else
+      fmt_real1[index] = NULL;
+
+    // Set total width
+    hitem->width = 0;
+    if (hitem->maxvalue_width > 0)
+      {
+       hitem->width += hitem->maxvalue_width;
+       prev = true;
+      }
+    else
+      prev = false;
+
+    if (hitem->maxtime_width > 0)
+      {
+       if (prev)
+         hitem->width++;
+       hitem->width += hitem->maxtime_width;
+       prev = true;
+      }
+
+    if (pvisible)
+      {
+       if (prev)
+         hitem->width++;
+       hitem->width += 6; // adjust to change format from xx.yy%
+      }
+    if (visible || tvisible || pvisible)
+      mitem->legend_width (hitem, 2);
+  }
+}
+
+static char *
+delTrailingBlanks (char *s)
+{
+  for (int i = (int) strlen (s) - 1; i >= 0 && s[i] == ' '; i--)
+    s[i] = 0;
+  return s;
+}
+
+/**
+ * Print the 3-line header with column heads for the metrics
+ * Return offset of "Name" column (this is needed to print Callers-Callees)
+ */
+int
+print_label (FILE *out_file, MetricList *metrics_list,
+            Metric::HistMetric *hist_metric, int space)
+{
+  char line0[2 * MAX_LEN], line1[2 * MAX_LEN];
+  char line2[2 * MAX_LEN], line3[2 * MAX_LEN];
+  int name_offset = 0;
+  *line0 = *line1 = *line2 = *line3 = '\0';
+  Vector<Metric*> *mlist = metrics_list->get_items ();
+  for (int index = 0, mlist_sz = mlist->size (); index < mlist_sz; index++)
+    {
+      Metric *mitem = mlist->fetch (index);
+      if (mitem->is_visible () || mitem->is_tvisible () || mitem->is_pvisible ())
+       {
+         Metric::HistMetric *hitem = hist_metric + index;
+         char *fmt;
+         if (index > 0 && mitem->get_type () == Metric::ONAME)
+           {
+             fmt = NTXT (" %-*s");
+             name_offset = strlen (line1);
+           }
+         else
+           fmt = NTXT ("%-*s");
+         int width = (int) hitem->width;
+         size_t len = strlen (line1);
+         snprintf (line1 + len, sizeof (line1) - len, fmt, width,
+                   hitem->legend1);
+         len = strlen (line2);
+         snprintf (line2 + len, sizeof (line2) - len, fmt, width,
+                   hitem->legend2);
+         len = strlen (line3);
+         snprintf (line3 + len, sizeof (line3) - len, fmt, width,
+                   hitem->legend3);
+         len = strlen (line0);
+         snprintf (line0 + len, sizeof (line0) - len, fmt, width,
+                   mitem->legend ? mitem->legend : NTXT (""));
+       }
+    }
+  char *s = delTrailingBlanks (line0);
+  if (*s)
+    fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), s);
+  fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line1));
+  fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line2));
+  fprintf (out_file, NTXT ("%*s%s\n"), space, NTXT (""), delTrailingBlanks (line3));
+  return name_offset;
+}
+
+static int
+print_one_visible (FILE *out_file, char *fmt_int, char *fmt_real0, char *fmt_real1,
+                  TValue *value, int visbits)
+{
+  int nc = 0;
+  switch (value->tag)
+    {
+    case VT_DOUBLE:
+      if (value->d == 0.0)
+       nc = fprintf (out_file, fmt_real0);
+      else
+       {
+         if (visbits & VAL_RATIO)
+           {
+             if (value->d > 99.999)
+               nc = fprintf (out_file, fmt_real1, NTXT (">"), 99.999);
+             else
+               nc = fprintf (out_file, fmt_real1, NTXT (" "), value->d);
+           }
+         else
+           nc = fprintf (out_file, fmt_real1, NTXT (""), value->d);
+       }
+      break;
+    case VT_INT:
+      nc = fprintf (out_file, fmt_int, value->i);
+      break;
+    case VT_LLONG:
+    case VT_ULLONG:
+      nc = fprintf (out_file, fmt_int, value->ll);
+      break;
+    case VT_ADDRESS:
+      nc = fprintf (out_file, fmt_int, ADDRESS_SEG (value->ll),
+                   ADDRESS_OFF (value->ll));
+      break;
+    case VT_FLOAT:
+      if (value->f == 0.0)
+       nc = fprintf (out_file, fmt_real0);
+      else
+       nc = fprintf (out_file, fmt_real1, value->f);
+      break;
+    case VT_SHORT:
+      nc = fprintf (out_file, fmt_int, value->s);
+      break;
+      // ignoring the following cases (why?)
+    case VT_HRTIME:
+    case VT_LABEL:
+    case VT_OFFSET:
+      break;
+    }
+  return nc;
+}
+
+static int
+print_one_tvisible (FILE *out_file, char *fmt_real0, char *fmt_real1,
+                   TValue *value, int visbits, int clock)
+{
+  int nc;
+  if (value->ll == 0LL)
+    nc = fprintf (out_file, fmt_real0);
+  else
+    {
+      if (visbits & VAL_RATIO)
+       {
+         if (value->d > 99.999)
+           nc = fprintf (out_file, fmt_real1, NTXT (">"), 99.999);
+         else
+           nc = fprintf (out_file, fmt_real1, NTXT (" "), value->d);
+       }
+      else
+       nc = fprintf (out_file, fmt_real1, "", 1.e-6 * value->ll / clock);
+    }
+  return nc;
+}
+
+static void
+print_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item,
+          char **fmt_int, char **fmt_real0, char **fmt_real1,
+          MetricList *metrics_list, Metric::HistMetric *hist_metric,
+          char *mark, Histable::NameFormat nfmt)
+{
+  Metric *mitem;
+  Metric::HistMetric *hitem;
+  int index, nc, np, i;
+  int visible, tvisible, pvisible;
+  TValue *value;
+  double percent;
+
+  if (item->type == Module::AT_EMPTY)
+    {
+      fprintf (out_file, nl);
+      return;
+    }
+
+  // set name_is_Total
+  int name_is_Total = 0;
+
+  Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+  {
+    if (mitem->get_type () != Metric::ONAME)
+      continue;
+    name_is_Total = strcmp (item->obj->get_name (), GTXT ("<Total>")) == 0;
+    break;
+  }
+
+  np = 0;
+  Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+  {
+    visible = mitem->is_visible ();
+    tvisible = mitem->is_tvisible ();
+    pvisible = mitem->is_pvisible ();
+
+    // alignment
+    for (i = 0; i < np; i++)
+      fputc (' ', out_file);
+
+    hitem = &hist_metric[index];
+    nc = 0;
+    if (tvisible)
+      {
+       value = &(item->value[index]);
+       nc = print_one_tvisible (out_file, fmt_real0[index], fmt_real1[index],
+                                value, mitem->get_visbits (),
+                                dbeSession->get_clock (-1));
+      }
+    else
+      nc = 0;
+
+    if (visible)
+      {
+       if (mitem->get_vtype () == VT_LABEL)
+         {
+           value = &(item->value[index]);
+           if (value->tag == VT_OFFSET)
+             nc += fprintf (out_file, fmt_int[index], mark,
+                            ((DataObject*) (item->obj))->get_offset_name ());
+           else
+             nc += fprintf (out_file, fmt_int[index], mark,
+                            item->obj->get_name (nfmt));
+         }
+       else if (name_is_Total &&
+                (strcmp (mitem->get_username (), "Block Covered %") == 0
+                 || strcmp (mitem->get_username (), "Instr Covered %") == 0))
+         {
+           char stmp[128];
+           snprintf (stmp, sizeof (stmp), fmt_int[index], 0);
+
+           /* and now blank that '0' out */
+           for (int ii = 0; ii < 128; ii++)
+             {
+               if (stmp[ii] != '0')
+                 continue;
+               stmp[ii] = ' ';
+               break;
+             }
+           nc += fprintf (out_file, stmp);
+         }
+       else
+         nc += print_one_visible (out_file, fmt_int[index], fmt_real0[index],
+                                  fmt_real1[index], &(item->value[index]),
+                                  mitem->get_visbits ());
+      }
+
+    if (pvisible)
+      {
+       percent = data->get_percentage (item->value[index].to_double (), index);
+       if (percent == 0.0)
+         // adjust to change format from xx.yy%
+         nc += fprintf (out_file, NTXT ("%#4.0f   "), 0.);
+       else
+         // adjust format below to change format from xx.yy%
+         nc += fprintf (out_file, NTXT ("%6.2f "), (100.0 * percent));
+      }
+    np = (int) (hitem->width - nc);
+  }
+  fprintf (out_file, nl);
+}
+
+void
+print_content (FILE *out_file, Hist_data *data,
+              char **fmt_int, char **fmt_real0, char **fmt_real1,
+              MetricList *metrics_list, Metric::HistMetric *hist_metric,
+              int limit, Histable::NameFormat nfmt)
+{
+  // printing contents.
+  for (int i = 0; i < limit; i++)
+    {
+      Hist_data::HistItem *item = data->fetch (i);
+      print_one (out_file, data, item, fmt_int, fmt_real0, fmt_real1,
+                metrics_list, hist_metric, NTXT (" "), nfmt);
+    }
+}
+
+er_print_histogram::er_print_histogram (DbeView *_dbev, Hist_data *data,
+                                       MetricList *metrics_list,
+                                       Print_mode disp_type, int limit,
+                                       char *sort_name, Histable *sobj,
+                                       bool show_load, bool show_header)
+{
+  hist_data = data;
+  mlist = metrics_list;
+  type = disp_type;
+  number_entries = limit;
+  sort_metric = sort_name;
+  sel_obj = sobj;
+  dbev = _dbev;
+  exp_idx1 = 0;
+  exp_idx2 = dbeSession->nexps () - 1;
+  load = show_load;
+  header = show_header;
+}
+
+void
+er_print_histogram::dump_list (int limit)
+{
+  Histable::NameFormat nfmt = dbev->get_name_format ();
+  StringBuilder sb;
+  char *title = NULL; // No title for some formats
+  enum PrintMode pm = dbev->get_printmode ();
+
+  // create a header line, except for delimiter-separated list output
+  if (pm != PM_DELIM_SEP_LIST)
+    {
+      if (hist_data->type == Histable::FUNCTION)
+       sb.append (GTXT ("Functions sorted by metric: "));
+      else if (hist_data->type == Histable::INSTR)
+       sb.append (GTXT ("PCs sorted by metric: "));
+      else if (hist_data->type == Histable::LINE)
+       sb.append (GTXT ("Lines sorted by metric: "));
+      else if (hist_data->type == Histable::DOBJECT)
+       sb.append (GTXT ("Dataobjects sorted by metric: "));
+      else
+       sb.append (GTXT ("Objects sorted by metric: "));
+      sb.append (sort_metric);
+      title = sb.toString ();
+    }
+
+  switch (pm)
+    {
+    case PM_TEXT:
+      {
+       Metric::HistMetric *hist_metric = hist_data->get_histmetrics ();
+       fprintf (out_file, NTXT ("%s\n\n"), title); //print title
+       hist_data->print_label (out_file, hist_metric, 0);
+       hist_data->print_content (out_file, hist_metric, limit);
+       fprintf (out_file, nl);
+       break;
+      }
+    case PM_HTML:
+      {
+       print_html_title (out_file, title);
+       print_html_label (out_file, mlist);
+       print_html_content (out_file, hist_data, mlist, limit, nfmt);
+       print_html_trailer (out_file);
+       break;
+      }
+    case PM_DELIM_SEP_LIST:
+      {
+       char delim = dbev->get_printdelimiter ();
+       print_delim_label (out_file, mlist, delim);
+       print_delim_content (out_file, hist_data, mlist, limit, nfmt, delim);
+       print_delim_trailer (out_file, delim);
+       break;
+      }
+    }
+  free (title);
+}
+
+void
+er_print_histogram::dump_annotated_dataobjects (Vector<int> *marks,
+                                               int ithreshold)
+{
+  Metric::HistMetric *hist_metric;
+  char **fmt_int, **fmt_real0, **fmt_real1;
+  int no_metrics = mlist->get_items ()->size ();
+  int name_index = -1;
+  Histable::NameFormat nfmt = dbev->get_name_format ();
+  if (!dbeSession->is_datamode_available ())
+    fprintf (out_file,
+            GTXT ("No dataspace information recorded in experiments\n\n"));
+
+  Hist_data *layout_data = dbev->get_data_space ()->get_layout_data (hist_data, marks, ithreshold);
+
+  for (int mind = 0; mind < no_metrics; mind++)
+    if (mlist->get_items ()->fetch (mind)->get_type () == Metric::ONAME)
+      name_index = mind;
+
+  fmt_int = new char*[no_metrics];
+  fmt_real0 = new char*[no_metrics];
+  fmt_real1 = new char*[no_metrics];
+  hist_metric = new Metric::HistMetric[no_metrics];
+
+  // use new layout_data to set metric format
+  get_width (hist_data, mlist, hist_metric);
+  get_format (fmt_int, fmt_real0, fmt_real1, mlist, hist_metric, 0);
+  snprintf (hist_metric[name_index].legend2, MAX_LEN, GTXT ("* +offset .element"));
+  print_label (out_file, mlist, hist_metric, 3);
+  fprintf (out_file, nl);
+  for (long i = 0; i < layout_data->size (); i++)
+    {
+      Hist_data::HistItem* item = layout_data->fetch (i);
+      if (marks->find (i) != -1)
+       fprintf (out_file, NTXT ("## "));
+      else
+       fprintf (out_file, NTXT ("   "));
+      print_one (out_file, layout_data, item, fmt_int, fmt_real0, fmt_real1,
+                mlist, hist_metric, NTXT (" "), nfmt);
+    }
+  fprintf (out_file, nl);
+
+  // free format strings.
+  for (int i = 0; i < no_metrics; i++)
+    {
+      free (fmt_int[i]);
+      free (fmt_real0[i]);
+      free (fmt_real1[i]);
+    }
+  delete[] fmt_int;
+  delete[] fmt_real0;
+  delete[] fmt_real1;
+  delete[] hist_metric;
+  delete layout_data;
+}
+
+void
+er_print_histogram::dump_detail (int limit)
+{
+  Histable *obj;
+  Hist_data *current_data;
+  Histable::Type htype;
+  TValue *values;
+  double dvalue, percent;
+  MetricList *prop_mlist = new MetricList (mlist);
+  Metric *mitem;
+  int index, i;
+  size_t max_len, len, smax_len, slen;
+  Vaddr pc;
+  Module *module;
+  LoadObject *loadobject;
+  char *sname, *oname, *lname, *alias, *mangle;
+  char fmt_name[MAX_LEN];
+  char fmt_elem[MAX_LEN];
+  char fmt_real1[MAX_LEN], fmt_real2[MAX_LEN];
+  char fmt_int1[MAX_LEN], fmt_int2[MAX_LEN];
+  char fmt_long1[MAX_LEN], fmt_long2[MAX_LEN], fmt_long3[MAX_LEN];
+  char fmt_int0[MAX_LEN], fmt_long0[MAX_LEN];
+  char numstr[MAX_LEN];
+
+  Histable::NameFormat nfmt = dbev->get_name_format ();
+
+  // Check max. length of metrics names
+  max_len = smax_len = 0;
+
+  Vec_loop (Metric*, prop_mlist->get_items (), index, mitem)
+  {
+    mitem->set_vvisible (true);
+    if (mitem->get_vtype () == VT_LABEL)
+      continue;
+
+    if (mitem->get_subtype () != Metric::STATIC)
+      {
+       mitem->set_pvisible (true);
+       len = hist_data->value_maxlen (index);
+       if (max_len < len)
+         max_len = len;
+       slen = strlen (mitem->get_name ());
+       if (smax_len < slen)
+         smax_len = slen;
+      }
+  }
+
+  // now get the length of the other (non-performance-data) messages
+  if (hist_data->type == Histable::FUNCTION)
+    {
+      slen = strlen (GTXT ("Source File"));
+      if (smax_len < slen)
+       smax_len = slen;
+      slen = strlen (GTXT ("Object File"));
+      if (smax_len < slen)
+       smax_len = slen;
+      slen = strlen (GTXT ("Load Object"));
+      if (smax_len < slen)
+       smax_len = slen;
+      slen = strlen (GTXT ("Mangled Name"));
+      if (smax_len < slen)
+       smax_len = slen;
+      slen = strlen (GTXT ("Aliases"));
+      if (smax_len < slen)
+       smax_len = slen;
+    }
+  else if (hist_data->type == Histable::DOBJECT)
+    {
+      slen = strlen (GTXT ("Scope"));
+      if (smax_len < slen)
+       smax_len = slen;
+      slen = strlen (GTXT ("Type"));
+      if (smax_len < slen)
+       smax_len = slen;
+      slen = strlen (GTXT ("Member of"));
+      if (smax_len < slen)
+       smax_len = slen;
+      slen = strlen (GTXT ("Offset (bytes)"));
+      if (smax_len < slen)
+       smax_len = slen;
+      slen = strlen (GTXT ("Size (bytes)"));
+      if (smax_len < slen)
+       smax_len = slen;
+      slen = strlen (GTXT ("Elements"));
+      if (smax_len < slen)
+       smax_len = slen;
+    }
+  snprintf (fmt_name, sizeof (fmt_name), NTXT ("\t%%%ds: "), (int) smax_len);
+  snprintf (fmt_elem, sizeof (fmt_elem), NTXT ("\t%%%ds  "), (int) smax_len);
+  snprintf (numstr, sizeof (numstr), "%%#%d.0lf    (  %#1.0f %%%%%%%%)\n",
+           (int) (max_len - 3), 0.);
+  snprintf (fmt_real1, sizeof (fmt_real1), numstr, 0.0);
+  snprintf (fmt_real2, sizeof (fmt_real2), NTXT ("%%%d.3lf (%%5.1f%%%%)\n"),
+           (int) max_len);
+  snprintf (fmt_int0, sizeof (fmt_int0), NTXT ("%%%dd\n"), (int) max_len);
+  snprintf (numstr, sizeof (numstr), NTXT ("%%%dd (  %#1.0f %%%%%%%%)\n"),
+           (int) max_len, 0.);
+  snprintf (fmt_int1, sizeof (fmt_int1), numstr, 0);
+  snprintf (fmt_int2, sizeof (fmt_int2), NTXT ("%%%dd (%%5.1f%%%%)\n"),
+           (int) max_len);
+  snprintf (fmt_long0, sizeof (fmt_long0), NTXT ("%%%dllu\n"), (int) max_len);
+  snprintf (numstr, sizeof (numstr), NTXT ("%%%dd (  %#1.0f %%%%%%%%)\n"),
+           (int) max_len, 0.);
+  snprintf (fmt_long1, sizeof (fmt_long1), numstr, 0);
+  snprintf (fmt_long2, sizeof (fmt_long2), "%%%dllu (%%5.1f%%%%)\n",
+           (int) max_len);
+  snprintf (numstr, sizeof (numstr), NTXT ("\t%%%ds %%%%%dllu\n"),
+           (int) (smax_len + 1), (int) max_len);
+  snprintf (fmt_long3, sizeof (fmt_long3), numstr, GTXT ("Count:"));
+  snprintf (numstr, sizeof (numstr), "%%%dd (  %#1.0f %%%%%%%%) %%#%d.0lf\n",
+           (int) max_len, 0., (int) (max_len - 6));
+
+  // now loop over the objects
+  int num_printed_items = 0;
+  for (i = 0; i < hist_data->size (); i++)
+    {
+      if (hist_data->type == Histable::FUNCTION)
+       {
+         if (num_printed_items >= limit)
+           break;
+         obj = sel_obj ? sel_obj : hist_data->fetch (i)->obj;
+         htype = obj->get_type ();
+
+         // ask the view for all the data for the object
+         // xxxxx may be expensive to rescan all packets via get_hist_data()
+         current_data = dbev->get_hist_data (prop_mlist,
+                                             htype, 0, Hist_data::SELF, obj);
+         if (current_data->size () == 0)
+           continue;
+         values = current_data->fetch (0)->value;
+       }
+      else
+       {
+         obj = hist_data->fetch (i)->obj;
+         DataObject *dobj = (DataObject*) obj;
+         if (sel_obj)
+           {
+             // print selected item and its members
+             if (sel_obj != obj
+                 && (DataObject*) sel_obj != dobj->get_parent ())
+               // not a match, advance to next item
+               continue;
+           }
+         else if (num_printed_items >= limit)
+           break;
+         htype = obj->get_type ();
+         values = hist_data->fetch (i)->value;
+         current_data = hist_data;
+       }
+
+      if (num_printed_items)
+       // if this isn't the first one, add a blank line
+       fprintf (out_file, NTXT ("\n"));
+      num_printed_items++;
+
+      // Print full object name
+      if (htype != Histable::DOBJECT)
+       fprintf (out_file, NTXT ("%s\n"), obj->get_name (nfmt));
+      else
+       {
+         DataObject *dobj = (DataObject*) obj;
+         if (!dobj->get_parent ())
+           fprintf (out_file, NTXT ("%s\n"), obj->get_name (nfmt));
+         else
+           fprintf (out_file, NTXT ("    %s\n"), obj->get_name (nfmt));
+       }
+
+      Vec_loop (Metric*, prop_mlist->get_items (), index, mitem)
+      {
+       if (mitem->get_vtype () == VT_LABEL)
+         continue;
+       if (mitem->get_subtype () == Metric::STATIC
+           && htype == Histable::DOBJECT)
+         continue;
+       fprintf (out_file, fmt_name, mitem->get_name ());
+
+       if (mitem->get_value_styles () & VAL_PERCENT)
+         {
+           dvalue = values[index].to_double ();
+           switch (mitem->get_vtype ())
+             {
+             case VT_DOUBLE:
+               if (dvalue == 0.0)
+                 fprintf (out_file, fmt_real1);
+               else
+                 fprintf (out_file, fmt_real2, dvalue, 100.0
+                         * current_data->get_percentage (dvalue, index));
+               break;
+             case VT_INT:
+               if (dvalue == 0.0)
+                 fprintf (out_file, fmt_int1);
+               else
+                 fprintf (out_file, fmt_int2, (int) dvalue, 100.0
+                         * current_data->get_percentage (dvalue, index));
+               break;
+             case VT_LLONG:
+             case VT_ULLONG:
+               if (values[index].ll == 0LL)
+                 {
+                   if (mitem->is_time_val ())
+                     {
+                       fprintf (out_file, fmt_real1);
+                       fprintf (out_file, fmt_long3, 0LL);
+                     }
+                   else
+                     fprintf (out_file, fmt_long1);
+                 }
+               else
+                 {
+                   percent = 100.0 *
+                           current_data->get_percentage (dvalue, index);
+                   if (mitem->is_time_val ())
+                     {
+                       dvalue /= 1.e+6 * dbeSession->get_clock (-1);
+                       fprintf (out_file, fmt_real2, dvalue, percent);
+                       fprintf (out_file, fmt_long3, values[index].ll);
+                     }
+                   else
+                     fprintf (out_file, fmt_long2, values[index].ll,
+                              percent);
+                 }
+               break;
+             default:
+               break;
+             }
+         }
+       else
+         {
+           switch (mitem->get_vtype ())
+             {
+             case VT_INT:
+               fprintf (out_file, fmt_int0, values[index].i);
+               break;
+             case VT_LLONG:
+             case VT_ULLONG:
+               fprintf (out_file, fmt_long0, values[index].ll);
+               break;
+             case VT_ADDRESS:
+               pc = values[index].ll;
+               fprintf (out_file, NTXT ("%u:0x%08x\n"), ADDRESS_SEG (pc),
+                        ADDRESS_OFF (pc));
+               break;
+             case VT_DOUBLE:
+               if (values[index].d == 0.0)
+                 fprintf (out_file, fmt_real1);
+               else
+                 fprintf (out_file, "\t%*.3lf\n", (int) (max_len - 5), values[index].d);
+               break;
+             default:
+               break;
+             }
+         }
+      }
+
+      // now add the descriptive information about the object
+      if (htype != Histable::DOBJECT)
+       {
+         Function *func = (Function*) obj->convertto (Histable::FUNCTION);
+         if (func && func->get_type () == Histable::FUNCTION)
+           {
+             // Print the source/object/load-object files & aliases
+             oname = lname = alias = NULL;
+             sname = func->getDefSrcName ();
+             mangle = func->get_mangled_name ();
+             if (mangle && streq (func->get_name (), mangle))
+               mangle = NULL;
+             module = func->module;
+             if (module)
+               {
+                 oname = module->get_name ();
+                 loadobject = module->loadobject;
+                 if (loadobject)
+                   {
+                     lname = loadobject->get_pathname ();
+                     alias = loadobject->get_alias (func);
+                   }
+               }
+
+             if (htype == Histable::INSTR && dbeSession->is_datamode_available ())
+               alias = ((DbeInstr*) obj)->get_descriptor ();
+
+             fprintf (out_file, fmt_name, GTXT ("Source File"));
+             if (sname)
+               fprintf (out_file, NTXT ("%s"), sname);
+             fprintf (out_file, NTXT ("\n"));
+
+             fprintf (out_file, fmt_name, GTXT ("Object File"));
+             if (oname)
+               fprintf (out_file, NTXT ("%s"), oname);
+             fprintf (out_file, NTXT ("\n"));
+
+             fprintf (out_file, fmt_name, GTXT ("Load Object"));
+             if (lname)
+               fprintf (out_file, NTXT ("%s"), lname);
+             fprintf (out_file, NTXT ("\n"));
+
+             fprintf (out_file, fmt_name, GTXT ("Mangled Name"));
+             if (mangle)
+               fprintf (out_file, NTXT ("%s"), mangle);
+             fprintf (out_file, NTXT ("\n"));
+             fprintf (out_file, fmt_name, GTXT ("Aliases"));
+             if (alias)
+               fprintf (out_file, NTXT ("%s"), alias);
+             fprintf (out_file, NTXT ("\n"));
+           }
+       }
+      else
+       {
+         // Print the dataobject information
+         DataObject *dobj = (DataObject*) obj;
+         Histable *scope = dobj->get_scope ();
+
+         // print the scope
+         fprintf (out_file, fmt_name, GTXT ("Scope"));
+         if (!scope)
+           fprintf (out_file, GTXT ("(Global)\n"));
+         else switch (scope->get_type ())
+             {
+             case Histable::FUNCTION:
+               fprintf (out_file, NTXT ("%s(%s)\n"),
+                        ((Function*) scope)->module->get_name (),
+                        scope->get_name ());
+               break;
+             case Histable::LOADOBJECT:
+             case Histable::MODULE:
+             default:
+               fprintf (out_file, NTXT ("%s\n"), scope->get_name ());
+             }
+
+         // print the type name
+         fprintf (out_file, fmt_name, GTXT ("Type"));
+         if (dobj->get_typename ())
+           fprintf (out_file, NTXT ("%s\n"), dobj->get_typename ());
+         else
+           fprintf (out_file, GTXT ("(Synthetic)\n"));
+
+         // print the offset
+         if (dobj->get_offset () != -1)
+           {
+             if (dobj->get_parent ())
+               {
+                 fprintf (out_file, fmt_name, GTXT ("Member of"));
+                 fprintf (out_file, NTXT ("%s\n"), dobj->get_parent ()->get_name ());
+               }
+             fprintf (out_file, fmt_name, GTXT ("Offset (bytes)"));
+             fprintf (out_file, NTXT ("%lld\n"), (long long) dobj->get_offset ());
+           }
+         // print the size
+         if (dobj->get_size ())
+           {
+             fprintf (out_file, fmt_name, GTXT ("Size (bytes)"));
+             fprintf (out_file, NTXT ("%lld\n"), (long long) dobj->get_size ());
+           }
+       }
+      if (hist_data->type == Histable::FUNCTION)
+       delete current_data;
+    }
+  if (num_printed_items == 0 && sel_obj)
+    fprintf (stderr,
+            GTXT ("Error: Specified item `%s' had no recorded metrics.\n"),
+            sel_obj->get_name ());
+  delete prop_mlist;
+}
+
+static Metric::HistMetric *
+allocateHistMetric (int no_metrics)
+{
+  Metric::HistMetric *hist_metric = new Metric::HistMetric[no_metrics];
+  for (int i = 0; i < no_metrics; i++)
+    {
+      Metric::HistMetric *hm = &hist_metric[i];
+      hm->init ();
+    }
+  return hist_metric;
+}
+
+void
+er_print_histogram::dump_gprof (int limit)
+{
+  StringBuilder sb;
+  Histable *obj;
+  Hist_data *callers;
+  Hist_data *callees;
+  Hist_data *center;
+
+  int no_metrics = mlist->get_items ()->size ();
+  Metric::HistMetric *hist_metric = allocateHistMetric (no_metrics);
+  for (int i = 0; i < limit; i++)
+    {
+      obj = sel_obj ? sel_obj : hist_data->fetch (i)->obj;
+      callers = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+                                    Hist_data::CALLERS, obj);
+      callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+                                    Hist_data::CALLEES, obj);
+      center = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+                                   Hist_data::SELF, obj);
+      callers->update_max (hist_metric);
+      callees->update_max (hist_metric);
+      center->update_max (hist_metric);
+      callers->update_legend_width (hist_metric);
+      callers->print_label (out_file, hist_metric, 0);
+      callers->print_content (out_file, hist_metric, callers->size ());
+
+      if (center->size () > 0)
+       {
+         center->update_total (callers->get_totals ());
+         sb.setLength (0);
+         center->print_row (&sb, 0, hist_metric, NTXT ("*"));
+         sb.toFileLn (out_file);
+       }
+      callees->print_content (out_file, hist_metric, callees->size ());
+      fprintf (out_file, nl);
+      delete callers;
+      delete callees;
+      delete center;
+    }
+  delete[] hist_metric;
+}
+
+// dump an annotated file
+void
+dump_anno_file (FILE *fp, Histable::Type type, Module *module, DbeView *dbev,
+               MetricList *mlist, TValue *ftotal, const char *srcFile,
+               Function *func, Vector<int> *marks, int threshold, int vis_bits,
+               int src_visible, bool hex_visible, bool src_only)
+{
+  int no_metrics, lspace, mspace, tspace,
+         remain, mindex, next_mark, hidx,
+         index;
+  Metric *mitem;
+  char **fmt_int, **fmt_real0, **fmt_real1, buf[MAX_LEN];
+  Hist_data::HistItem *item;
+
+  SourceFile *srcContext = NULL;
+  bool func_scope = dbev == NULL ? false : dbev->get_func_scope ();
+  if (srcFile)
+    {
+      srcContext = module->findSource (srcFile, false);
+      if (srcContext == NULL)
+       {
+         Vector<SourceFile*> *includes = module->includes;
+         char *bname = get_basename (srcFile);
+         for (int i = 0, sz = includes ? includes->size () : 0; i < sz; i++)
+           {
+             SourceFile *sf = includes->fetch (i);
+             if (streq (get_basename (sf->get_name ()), bname))
+               {
+                 srcContext = sf;
+                 break;
+               }
+           }
+       }
+      if (func)
+       func_scope = true;
+    }
+  else if (func)
+    srcContext = func->getDefSrc ();
+
+  Hist_data *hdata = module->get_data (dbev, mlist, type, ftotal, srcContext,
+                                      func, marks, threshold, vis_bits,
+                                      src_visible, hex_visible,
+                                      func_scope, src_only);
+
+  if (hdata == NULL)
+    return;
+
+  // force the name metric to be invisible
+  MetricList *nmlist = hdata->get_metric_list ();
+  nmlist->find_metric (GTXT ("name"), Metric::STATIC)->clear_all_visbits ();
+  no_metrics = nmlist->get_items ()->size ();
+  fmt_int = new char*[no_metrics];
+  fmt_real0 = new char*[no_metrics];
+  fmt_real1 = new char*[no_metrics];
+  Metric::HistMetric *hist_metric = hdata->get_histmetrics ();
+
+  // lspace is for max line number that's inserted; use to set width
+  int max_lineno = 0;
+  Vec_loop (Hist_data::HistItem*, hdata, hidx, item)
+  {
+    if (!item->obj)
+      continue;
+    if (item->obj->get_type () == Histable::LINE
+       && ((DbeLine*) item->obj)->lineno > max_lineno)
+      max_lineno = ((DbeLine*) item->obj)->lineno;
+    else if (item->obj->get_type () == Histable::INSTR
+            && ((DbeInstr*) item->obj)->lineno > max_lineno)
+      max_lineno = ((DbeInstr*) item->obj)->lineno;
+  }
+
+  lspace = snprintf (buf, sizeof (buf), NTXT ("%d"), max_lineno);
+
+  // mspace is the space needed for all metrics, and the mark, if any
+  mspace = 0;
+  if (nmlist->get_items ()->size () > 0)
+    {
+      mspace = 3; // mark "## "
+      Vec_loop (Metric*, nmlist->get_items (), index, mitem)
+      {
+       if (mitem->is_visible () || mitem->is_tvisible ()
+           || mitem->is_pvisible ())
+         mspace += (int) hist_metric[index].width;
+      }
+    }
+  tspace = 0;
+  remain = (mspace + lspace + 3) % 8; // " " before, ". " after line#
+  if (remain)
+    { // tab alignment
+      tspace = 8 - remain;
+      mspace += tspace;
+    }
+  mindex = 0;
+  next_mark = (mindex < marks->size ()) ? marks->fetch (mindex) : -1;
+
+  // Print the header for this list
+  SourceFile *sf = srcContext ? srcContext : module->getMainSrc ();
+  char *src_name = sf->dbeFile->get_location_info ();
+  DbeFile *df = module->dbeFile;
+  if (df == NULL || (df->filetype & DbeFile::F_JAVACLASS) == 0)
+    df = module->loadobject->dbeFile;
+  char *lo_name = df->get_location_info ();
+  char *dot_o_name = lo_name;
+  if (module->dot_o_file)
+    dot_o_name = module->dot_o_file->dbeFile->get_location_info ();
+  fprintf (fp, GTXT ("Source file: %s\nObject file: %s\nLoad Object: %s\n\n"),
+          src_name, dot_o_name, lo_name);
+
+  // Print metric labels
+  if (nmlist->get_items ()->size () != 0)
+    print_label (fp, nmlist, hist_metric, 3);
+
+  // determine the name metric (not printed as a metric, though)
+  int lind = nmlist->get_listorder (GTXT ("name"), Metric::STATIC);
+
+  // now loop over the data rows -- the lines in the annotated source/disasm,
+  //   including index lines, compiler commentary, etc.
+  StringBuilder sb;
+  Vec_loop (Hist_data::HistItem*, hdata, hidx, item)
+  {
+    sb.setLength (0);
+    if (item->type == Module::AT_DIS || item->type == Module::AT_QUOTE
+       || item->type == Module::AT_SRC)
+      {
+       // does this line get a high-metric mark?
+       if (hidx == next_mark)
+         {
+           sb.append (NTXT ("## "));
+           mindex++;
+           next_mark = (mindex < marks->size ()) ? marks->fetch (mindex) : -1;
+         }
+       else
+         sb.append (NTXT ("   "));
+
+       hdata->print_row (&sb, hidx, hist_metric, NTXT (" "));
+       sb.toFile (fp);
+       for (int i = sb.length (); i < mspace; i++)
+         {
+           fputc (' ', fp);
+         }
+      }
+    else
+      // this line does not get any metrics; insert blanks in lieu of them
+      for (int i = 0; i < mspace; i++)
+       fputc (' ', fp);
+
+    switch (item->type)
+      {
+      case Module::AT_SRC_ONLY:
+       if (item->obj == NULL)
+         fprintf (fp, NTXT ("%*s. "), lspace + 1, "?");
+       else
+         fprintf (fp, "%*d. ", lspace + 1, ((DbeLine*) item->obj)->lineno);
+       break;
+
+      case Module::AT_SRC:
+       fprintf (fp, "%*d. ", lspace + 1, ((DbeLine*) item->obj)->lineno);
+       break;
+      case Module::AT_FUNC:
+      case Module::AT_QUOTE:
+       fprintf (fp, NTXT ("%*c"), lspace + 3, ' ');
+       break;
+      case Module::AT_DIS:
+      case Module::AT_DIS_ONLY:
+       if (item->obj == NULL || ((DbeInstr*) item->obj)->lineno == -1)
+         fprintf (fp, "%*c[%*s] ", lspace + 3, ' ', lspace, "?");
+       else
+         fprintf (fp, "%*c[%*d] ", lspace + 3, ' ', lspace,
+                  ((DbeInstr*) item->obj)->lineno);
+       break;
+      case Module::AT_COM:
+      case Module::AT_EMPTY:
+       break;
+
+      }
+    if (item->value[lind].l == NULL)
+      item->value[lind].l = dbe_strdup (GTXT ("INTERNAL ERROR: missing line text"));
+    fprintf (fp, NTXT ("%s\n"), item->value[lind].l);
+  }
+  delete[] fmt_int;
+  delete[] fmt_real0;
+  delete[] fmt_real1;
+  delete hdata;
+}
+
+void
+er_print_histogram::dump_annotated ()
+{
+  Vector<int> *marks = new Vector<int>;
+  Function *anno_func = (Function *) sel_obj;
+  Module *module = anno_func ? anno_func->module : NULL;
+
+  if (hist_data->type == Histable::DOBJECT)
+    dump_annotated_dataobjects (marks, number_entries); // threshold
+  else if (number_entries == 0)
+      // Annotated source
+    dump_anno_file (out_file, Histable::LINE, module, dbev, mlist,
+                   hist_data->get_totals ()->value, NULL, anno_func, marks,
+                   dbev->get_thresh_src (), dbev->get_src_compcom (),
+                   dbev->get_src_visible (), dbev->get_hex_visible (), true);
+  else
+    // Annotated disassembly
+    dump_anno_file (out_file, Histable::INSTR, module, dbev, mlist,
+                   hist_data->get_totals ()->value, NULL, anno_func, marks,
+                   dbev->get_thresh_dis (), dbev->get_dis_compcom (),
+                   dbev->get_src_visible (), dbev->get_hex_visible (), true);
+}
+
+void
+er_print_histogram::data_dump ()
+{
+  int limit;
+  if (hist_data->get_status () == Hist_data::SUCCESS)
+    {
+      if (sort_metric[0] == '\n')
+       { // csingle Callers-Callees entry
+         sort_metric++;
+         fprintf (out_file, NTXT ("%s\n\n"), sort_metric);
+       }
+      else if (!sel_obj && type != MODE_LIST)
+       {
+         if (hist_data->type == Histable::FUNCTION)
+           fprintf (out_file,
+                    GTXT ("Functions sorted by metric: %s\n\n"), sort_metric);
+         else if (hist_data->type == Histable::DOBJECT)
+           fprintf (out_file, GTXT ("Dataobjects sorted by metric: %s\n\n"),
+                    sort_metric);
+         else
+           fprintf (out_file,
+                    GTXT ("Objects sorted by metric: %s\n\n"), sort_metric);
+       }
+      limit = hist_data->size ();
+      if ((number_entries > 0) && (number_entries < limit))
+       limit = number_entries;
+
+      switch (type)
+       {
+       case MODE_LIST:
+         dump_list (limit);
+         break;
+       case MODE_DETAIL:
+         dump_detail (limit);
+         break;
+       case MODE_GPROF:
+         dump_gprof (limit);
+         break;
+       case MODE_ANNOTATED:
+         dump_annotated ();
+         break;
+       }
+    }
+  else
+    fprintf (out_file, GTXT ("Get_Hist_data call failed %d\n"),
+            (int) hist_data->get_status ());
+}
+
+/*
+ * Class er_print_ctree to print functions call tree
+ */
+er_print_ctree::er_print_ctree (DbeView *_dbev, Vector<Histable*> *_cstack,
+                               Histable *_sobj, int _limit)
+{
+  dbev = _dbev;
+  cstack = _cstack;
+  sobj = _sobj;
+  limit = _limit;
+  print_row = 0;
+  exp_idx1 = 0;
+  exp_idx2 = dbeSession->nexps () - 1;
+  load = false;
+  header = false;
+}
+
+void
+er_print_ctree::data_dump ()
+{
+  StringBuilder sb;
+  Hist_data::HistItem *total;
+  sb.append (GTXT ("Functions Call Tree. Metric: "));
+  char *s = dbev->getSort (MET_CALL_AGR);
+  sb.append (s);
+  free (s);
+  sb.toFileLn (out_file);
+  fprintf (out_file, NTXT ("\n"));
+  mlist = dbev->get_metric_list (MET_CALL_AGR);
+
+  // Change cstack: add sobj to the end of cstack
+  cstack->append (sobj);
+  Hist_data *center = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+                                          Hist_data::SELF, cstack);
+  Hist_data *callers = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+                                           Hist_data::CALLERS, cstack);
+  Hist_data *callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+                                           Hist_data::CALLEES, cstack);
+
+  // Restore cstack
+  int last = cstack->size () - 1;
+  cstack->remove (last);
+
+  // Prepare formats
+  int no_metrics = mlist->size ();
+
+  // calculate max. width using data from callers, callees, center
+  hist_metric = allocateHistMetric (no_metrics);
+  callers->update_max (hist_metric);
+  callees->update_max (hist_metric);
+  center->update_max (hist_metric);
+  callers->update_legend_width (hist_metric);
+  callers->print_label (out_file, hist_metric, 0); // returns Name column offset
+
+  print_row = 0;
+  // Pass real total to print_children()
+  total = center->get_totals ();
+  print_children (center, 0, sobj, NTXT (" "), total);
+
+  // Free memory
+  cstack->reset ();
+  delete callers;
+  delete callees;
+  delete center;
+  delete[] hist_metric;
+}
+
+/*
+ * Recursive method print_children prints Call Tree elements.
+ */
+void
+er_print_ctree::print_children (Hist_data *data, int index, Histable *my_obj,
+                               char * prefix, Hist_data::HistItem *total)
+{
+  StringBuilder buf;
+  const char *P0 = "+-";
+  const char *P2 = "  |";
+  const char *P1 = "  ";
+
+  // If limit exceeded - return
+  ++print_row;
+  if (limit > 0 && print_row > limit)
+    return;
+
+  if (my_obj == NULL)
+    return; // should never happen
+
+  // Prepare prefix
+  buf.append (prefix);
+  if (buf.endsWith (P2))
+    {
+      int len = buf.length () - 1;
+      buf.setLength (len);
+    }
+  buf.append (P0);
+
+  // Change cstack: add my_obj to the end of cstack
+  cstack->append (my_obj);
+
+  // Print current node info
+  char * my_prefix = buf.toString ();
+
+  // Replace parent's total values with real total values
+  data->update_total (total); // Needed to to calculate percentage only
+  buf.setLength (0);
+  data->print_row (&buf, index, hist_metric, my_prefix);
+  buf.toFileLn (out_file);
+  free (my_prefix);
+
+  // Get children
+  Hist_data *callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+                                           Hist_data::CALLEES, cstack);
+  int nc = callees->size ();
+  if (nc > 0)
+    {
+      // Print children
+      Hist_data::HistItem *item;
+      Histable *ch_obj;
+      char *ch_prefix;
+      buf.setLength (0);
+      buf.append (prefix);
+      buf.append (P2);
+      ch_prefix = buf.toString ();
+      for (int i = 0; i < nc - 1; i++)
+       {
+         item = callees->fetch (i);
+         ch_obj = item->obj;
+         print_children (callees, i, ch_obj, ch_prefix, total);
+       }
+      free (ch_prefix);
+      buf.setLength (0);
+      buf.append (prefix);
+      buf.append (P1);
+      ch_prefix = buf.toString ();
+      item = callees->fetch (nc - 1);
+      ch_obj = item->obj;
+      print_children (callees, nc - 1, ch_obj, ch_prefix, total);
+      free (ch_prefix);
+    }
+
+  // Restore cstack
+  int last = cstack->size () - 1;
+  cstack->remove (last);
+  delete callees;
+  return;
+}
+
+er_print_gprof::er_print_gprof (DbeView *_dbev, Vector<Histable*> *_cstack)
+{
+  dbev = _dbev;
+  cstack = _cstack;
+  exp_idx1 = 0;
+  exp_idx2 = dbeSession->nexps () - 1;
+  load = false;
+  header = false;
+}
+
+void
+er_print_gprof::data_dump ()
+{
+  StringBuilder sb;
+  sb.append (GTXT ("Callers and callees sorted by metric: "));
+  char *s = dbev->getSort (MET_CALL);
+  sb.append (s);
+  free (s);
+  sb.toFileLn (out_file);
+  fprintf (out_file, NTXT ("\n"));
+
+  MetricList *mlist = dbev->get_metric_list (MET_CALL);
+  Hist_data *center = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+                                          Hist_data::SELF, cstack);
+  Hist_data *callers = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+                                           Hist_data::CALLERS, cstack);
+  Hist_data *callees = dbev->get_hist_data (mlist, Histable::FUNCTION, 0,
+                                           Hist_data::CALLEES, cstack);
+
+  mlist = center->get_metric_list ();
+  int no_metrics = mlist->get_items ()->size ();
+
+  // update max. width for callers/callees/center function item
+  Metric::HistMetric *hist_metric = allocateHistMetric (no_metrics);
+  callers->update_max (hist_metric);
+  callees->update_max (hist_metric);
+  center->update_max (hist_metric);
+
+  callers->update_legend_width (hist_metric);
+  int name_offset = callers->print_label (out_file, hist_metric, 0); // returns Name column offset
+  // Print Callers
+  sb.setLength (0);
+  for (int i = 0; i < name_offset; i++)
+    sb.append (NTXT ("="));
+  if (name_offset > 0)
+    sb.append (NTXT (" "));
+  char *line1 = sb.toString ();
+  char *line2;
+  if (callers->size () > 0)
+    line2 = GTXT ("Callers");
+  else
+    line2 = GTXT ("No Callers");
+  fprintf (out_file, NTXT ("%s%s\n"), line1, line2);
+  callers->print_content (out_file, hist_metric, callers->size ());
+
+  // Print Stack Fragment
+  line2 = GTXT ("Stack Fragment");
+  fprintf (out_file, NTXT ("\n%s%s\n"), line1, line2);
+
+  for (long i = 0, last = cstack->size () - 1; i <= last; ++i)
+    {
+      sb.setLength (0);
+      if (i == last && center->size () > 0)
+       {
+         center->update_total (callers->get_totals ()); // Needed to to calculate percentage only
+         center->print_row (&sb, center->size () - 1, hist_metric, NTXT (" "));
+       }
+      else
+       {
+         for (int n = name_offset; n > 0; n--)
+           sb.append (NTXT (" "));
+         if (name_offset > 0)
+           sb.append (NTXT (" "));
+         sb.append (cstack->get (i)->get_name ());
+       }
+      sb.toFileLn (out_file);
+    }
+
+  // Print Callees
+  if (callees->size () > 0)
+    line2 = GTXT ("Callees");
+  else
+    line2 = GTXT ("No Callees");
+  fprintf (out_file, NTXT ("\n%s%s\n"), line1, line2);
+  callees->print_content (out_file, hist_metric, callees->size ());
+  fprintf (out_file, nl);
+  free (line1);
+  delete callers;
+  delete callees;
+  delete center;
+  delete[] hist_metric;
+}
+
+er_print_leaklist::er_print_leaklist (DbeView *_dbev, bool show_leak,
+                                     bool show_alloca, int _limit)
+{
+  dbev = _dbev;
+  leak = show_leak;
+  alloca = show_alloca;
+  limit = _limit;
+}
+
+// Output routine for leak list only
+void
+er_print_leaklist::data_dump ()
+{
+  CStack_data *lam;
+  CStack_data::CStack_item *lae;
+  int index;
+  if (!dbeSession->is_leaklist_available ())
+    fprintf (out_file, GTXT ("No leak or allocation information recorded in experiments\n\n"));
+
+  MetricList *origmlist = dbev->get_metric_list (MET_NORMAL);
+  if (leak)
+    {
+      // make a copy of the metric list, and set metrics for leaks
+      MetricList *nmlist = new MetricList (origmlist);
+      nmlist->set_metrics ("e.heapleakbytes:e.heapleakcnt:name", true,
+                          dbev->get_derived_metrics ());
+
+      // now make a compacted version of it to get the right indices
+      MetricList *mlist = new MetricList (nmlist);
+      delete nmlist;
+
+      // fetch the callstack data
+      lam = dbev->get_cstack_data (mlist);
+
+      // now print it
+      if (lam && lam->size () != 0)
+       {
+         fprintf (out_file, GTXT ("Summary Results: Distinct Leaks = %d, Total Instances = %lld, Total Bytes Leaked = %lld\n\n"),
+                  (int) lam->size (), lam->total->value[1].ll,
+                  lam->total->value[0].ll);
+
+         Vec_loop (CStack_data::CStack_item*, lam->cstack_items, index, lae)
+         {
+           fprintf (out_file,
+                    GTXT ("Leak #%d, Instances = %lld, Bytes Leaked = %lld\n"),
+                    index + 1, lae->value[1].ll, lae->value[0].ll);
+           if (lae->stack != NULL)
+             for (int i = lae->stack->size () - 1; i >= 0; i--)
+               {
+                 DbeInstr *instr = lae->stack->fetch (i);
+                 fprintf (out_file, NTXT ("  %s\n"), instr->get_name ());
+               }
+           fprintf (out_file, NTXT ("\n"));
+           if (index + 1 == limit) break;
+         }
+       }
+      else
+       fprintf (out_file, GTXT ("No leak information\n\n"));
+      delete lam;
+      delete mlist;
+    }
+
+  if (alloca)
+    {
+      // make a copy of the metric list, and set metrics for leaks
+      MetricList *nmlist = new MetricList (origmlist);
+      nmlist->set_metrics ("e.heapallocbytes:e.heapalloccnt:name",
+                          true, dbev->get_derived_metrics ());
+
+      // now make a compacted version of it to get the right indices
+      MetricList *mlist = new MetricList (nmlist);
+      delete nmlist;
+
+      // fetch the callstack data
+      lam = dbev->get_cstack_data (mlist);
+
+      // now print it
+      if (lam && lam->size () != 0)
+       {
+         fprintf (out_file, GTXT ("Summary Results: Distinct Allocations = %d, Total Instances = %lld, Total Bytes Allocated = %lld\n\n"),
+                  (int) lam->size (), lam->total->value[1].ll,
+                  lam->total->value[0].ll);
+         Vec_loop (CStack_data::CStack_item*, lam->cstack_items, index, lae)
+         {
+           fprintf (out_file, GTXT ("Allocation #%d, Instances = %lld, Bytes Allocated = %lld\n"),
+                    index + 1, lae->value[1].ll, lae->value[0].ll);
+           if (lae->stack != NULL)
+             for (int i = lae->stack->size () - 1; i >= 0; i--)
+               {
+                 DbeInstr *instr = lae->stack->fetch (i);
+                 fprintf (out_file, NTXT ("  %s\n"), instr->get_name ());
+               }
+           fprintf (out_file, NTXT ("\n"));
+           if (index + 1 == limit) break;
+         }
+       }
+      else
+       fprintf (out_file, GTXT ("No allocation information\n\n"));
+      delete lam;
+      delete mlist;
+    }
+}
+
+er_print_heapactivity::er_print_heapactivity (DbeView *_dbev,
+                                             Histable::Type _type,
+                                             bool _printStat, int _limit)
+{
+  dbev = _dbev;
+  type = _type;
+  printStat = _printStat;
+  limit = _limit;
+}
+
+void
+er_print_heapactivity::printCallStacks (Hist_data *hist_data)
+{
+  Hist_data::HistItem *hi;
+  HeapData *hData;
+  long stackId;
+  int size = hist_data->size ();
+  if (limit > 0 && limit < size)
+    size = limit;
+
+  Histable::NameFormat fmt = dbev->get_name_format ();
+  for (int i = 0; i < size; i++)
+    {
+      hi = hist_data->fetch (i);
+      hData = (HeapData*) hi->obj;
+      stackId = hData->id;
+      if (i != 0)
+       fprintf (out_file, NTXT ("\n"));
+
+      fprintf (out_file, NTXT ("%s\n"), hData->get_name (fmt));
+      if (hData->getAllocCnt () > 0)
+       {
+         fprintf (out_file, GTXT ("Instances = %d  "),
+                  (int) (hData->getAllocCnt ()));
+         fprintf (out_file, GTXT ("Bytes Allocated = %lld\n"),
+                  (long long) hData->getAllocBytes ());
+       }
+
+      if (hData->getLeakCnt () > 0)
+       {
+         fprintf (out_file, GTXT ("Instances = %d  "),
+                  (int) (hData->getLeakCnt ()));
+         fprintf (out_file, GTXT ("Bytes Leaked = %lld\n"),
+                  (long long) hData->getLeakBytes ());
+       }
+
+      // There is no stack trace for <Total>
+      if (i == 0)
+       continue;
+
+      // LIBRARY VISIBILITY pass extra argument if necessary to get hide stack
+      Vector<Histable*> *instrs = CallStack::getStackPCs ((void *) stackId);
+      if (instrs != NULL)
+       {
+         int stSize = instrs->size ();
+         for (int j = 0; j < stSize; j++)
+           {
+             Histable *instr = instrs->fetch (j);
+             if (instr != NULL)
+               fprintf (out_file, NTXT ("  %s\n"), instr->get_name ());
+           }
+         delete instrs;
+       }
+    }
+}
+
+void
+er_print_heapactivity::printStatistics (Hist_data *hist_data)
+{
+  Hist_data::HistItem *hi;
+  HeapData *hDataTotal;
+  hi = hist_data->fetch (0);
+  hDataTotal = (HeapData*) hi->obj;
+  Vector<hrtime_t> *pTimestamps;
+  if (hDataTotal->getPeakMemUsage () > 0)
+    {
+      fprintf (out_file, GTXT ("\nProcess With Highest Peak Memory Usage\n"));
+      fprintf (out_file,
+              "-------------------------------------------------------\n");
+      fprintf (out_file, GTXT ("Heap size bytes                   %lld\n"),
+              (long long) hDataTotal->getPeakMemUsage ());
+      fprintf (out_file, GTXT ("Experiment Id                     %d\n"),
+              (int) (hDataTotal->getUserExpId ()));
+      fprintf (out_file, GTXT ("Process Id                        %d\n"),
+              (int) (hDataTotal->getPid ()));
+      pTimestamps = hDataTotal->getPeakTimestamps ();
+      if (pTimestamps != NULL)
+       for (int i = 0; i < pTimestamps->size (); i++)
+         fprintf (out_file,
+                  GTXT ("Time of peak                      %.3f (secs.)\n"),
+                  (double) (pTimestamps->fetch (i) / (double) NANOSEC));
+    }
+
+  if (hDataTotal->getAllocCnt () > 0)
+    {
+      fprintf (out_file, GTXT ("\nMemory Allocations Statistics\n"));
+      fprintf (out_file,
+              GTXT ("Allocation Size Range             Allocations          \n"));
+      fprintf (out_file,
+              "-------------------------------------------------------\n");
+      if (hDataTotal->getA0KB1KBCnt () > 0)
+       fprintf (out_file, NTXT ("  0KB - 1KB                       %d\n"),
+                hDataTotal->getA0KB1KBCnt ());
+      if (hDataTotal->getA1KB8KBCnt () > 0)
+       fprintf (out_file, NTXT ("  1KB - 8KB                       %d\n"),
+                hDataTotal->getA1KB8KBCnt ());
+      if (hDataTotal->getA8KB32KBCnt () > 0)
+       fprintf (out_file, NTXT ("  8KB - 32KB                      %d\n"),
+                hDataTotal->getA8KB32KBCnt ());
+      if (hDataTotal->getA32KB128KBCnt () > 0)
+       fprintf (out_file, NTXT ("  32KB - 128KB                    %d\n"),
+                hDataTotal->getA32KB128KBCnt ());
+      if (hDataTotal->getA128KB256KBCnt () > 0)
+       fprintf (out_file, NTXT ("  128KB - 256KB                   %d\n"),
+                hDataTotal->getA128KB256KBCnt ());
+      if (hDataTotal->getA256KB512KBCnt () > 0)
+       fprintf (out_file, NTXT ("  256KB - 512KB                   %d\n"),
+                hDataTotal->getA256KB512KBCnt ());
+      if (hDataTotal->getA512KB1000KBCnt () > 0)
+       fprintf (out_file, NTXT ("  512KB - 1000KB                  %d\n"),
+                hDataTotal->getA512KB1000KBCnt ());
+      if (hDataTotal->getA1000KB10MBCnt () > 0)
+       fprintf (out_file, NTXT ("  1000KB - 10MB                   %d\n"),
+                hDataTotal->getA1000KB10MBCnt ());
+      if (hDataTotal->getA10MB100MBCnt () > 0)
+       fprintf (out_file, NTXT ("  10MB - 100MB                    %d\n"),
+                hDataTotal->getA10MB100MBCnt ());
+      if (hDataTotal->getA100MB1GBCnt () > 0)
+       fprintf (out_file, NTXT ("  100MB - 1GB                     %d\n"),
+                hDataTotal->getA100MB1GBCnt ());
+      if (hDataTotal->getA1GB10GBCnt () > 0)
+       fprintf (out_file, NTXT ("  1GB - 10GB                      %d\n"),
+                hDataTotal->getA1GB10GBCnt ());
+      if (hDataTotal->getA10GB100GBCnt () > 0)
+       fprintf (out_file, NTXT ("  10GB - 100GB                    %d\n"),
+                hDataTotal->getA10GB100GBCnt ());
+      if (hDataTotal->getA100GB1TBCnt () > 0)
+       fprintf (out_file, NTXT ("  100GB - 1TB                     %d\n"),
+                hDataTotal->getA100GB1TBCnt ());
+      if (hDataTotal->getA1TB10TBCnt () > 0)
+       fprintf (out_file, NTXT ("  1TB - 10TB                      %d\n"),
+                hDataTotal->getA1TB10TBCnt ());
+      fprintf (out_file, GTXT ("\nSmallest allocation bytes         %lld\n"),
+              (long long) hDataTotal->getASmallestBytes ());
+      fprintf (out_file, GTXT ("Largest allocation bytes          %lld\n"),
+              (long long) hDataTotal->getALargestBytes ());
+      fprintf (out_file, GTXT ("Total allocations                 %d\n"),
+              hDataTotal->getAllocCnt ());
+      fprintf (out_file, GTXT ("Total bytes                       %lld\n"),
+              (long long) hDataTotal->getAllocBytes ());
+    }
+
+  if (hDataTotal->getLeakCnt () > 0)
+    {
+      fprintf (out_file, GTXT ("\nMemory Leaks Statistics\n"));
+      fprintf (out_file,
+              GTXT ("Leak Size Range                   Leaks              \n"));
+      fprintf (out_file,
+              "-------------------------------------------------------\n");
+      if (hDataTotal->getL0KB1KBCnt () > 0)
+       fprintf (out_file, NTXT ("  0KB - 1KB                       %d\n"),
+                hDataTotal->getL0KB1KBCnt ());
+      if (hDataTotal->getL1KB8KBCnt () > 0)
+       fprintf (out_file, NTXT ("  1KB - 8KB                       %d\n"),
+                hDataTotal->getL1KB8KBCnt ());
+      if (hDataTotal->getL8KB32KBCnt () > 0)
+       fprintf (out_file, NTXT ("  8KB - 32KB                      %d\n"),
+                hDataTotal->getL8KB32KBCnt ());
+      if (hDataTotal->getL32KB128KBCnt () > 0)
+       fprintf (out_file, NTXT ("  32KB - 128KB                    %d\n"),
+                hDataTotal->getL32KB128KBCnt ());
+      if (hDataTotal->getL128KB256KBCnt () > 0)
+       fprintf (out_file, NTXT ("  128KB - 256KB                   %d\n"),
+                hDataTotal->getL128KB256KBCnt ());
+      if (hDataTotal->getL256KB512KBCnt () > 0)
+       fprintf (out_file, NTXT ("  256KB - 512KB                   %d\n"),
+                hDataTotal->getL256KB512KBCnt ());
+      if (hDataTotal->getL512KB1000KBCnt () > 0)
+       fprintf (out_file, NTXT ("  512KB - 1000KB                  %d\n"),
+                hDataTotal->getL512KB1000KBCnt ());
+      if (hDataTotal->getL1000KB10MBCnt () > 0)
+       fprintf (out_file, NTXT ("  1000KB - 10MB                   %d\n"),
+                hDataTotal->getL1000KB10MBCnt ());
+      if (hDataTotal->getL10MB100MBCnt () > 0)
+       fprintf (out_file, NTXT ("  10MB - 100MB                    %d\n"),
+                hDataTotal->getL10MB100MBCnt ());
+      if (hDataTotal->getL100MB1GBCnt () > 0)
+       fprintf (out_file, NTXT ("  100MB - 1GB                     %d\n"),
+                hDataTotal->getL100MB1GBCnt ());
+      if (hDataTotal->getL1GB10GBCnt () > 0)
+       fprintf (out_file, NTXT ("  1GB - 10GB                      %d\n"),
+                hDataTotal->getL1GB10GBCnt ());
+      if (hDataTotal->getL10GB100GBCnt () > 0)
+       fprintf (out_file, NTXT ("  10GB - 100GB                    %d\n"),
+                hDataTotal->getL10GB100GBCnt ());
+      if (hDataTotal->getL100GB1TBCnt () > 0)
+       fprintf (out_file, NTXT ("  100GB - 1TB                     %d\n"),
+                hDataTotal->getL100GB1TBCnt ());
+      if (hDataTotal->getL1TB10TBCnt () > 0)
+       fprintf (out_file, NTXT ("  1TB - 10TB                      %d\n"),
+                hDataTotal->getL1TB10TBCnt ());
+      fprintf (out_file, GTXT ("\nSmallest leaked bytes             %lld\n"),
+              (long long) hDataTotal->getLSmallestBytes ());
+      fprintf (out_file, GTXT ("Largest leaked bytes              %lld\n"),
+              (long long) hDataTotal->getLLargestBytes ());
+      fprintf (out_file, GTXT ("Total leaked                      %d \n"),
+              hDataTotal->getLeakCnt ());
+      fprintf (out_file, GTXT ("Total bytes                       %lld\n"),
+              (long long) hDataTotal->getLeakBytes ());
+    }
+  fprintf (out_file, NTXT ("\n"));
+}
+
+void
+er_print_heapactivity::data_dump ()
+{
+  // get the list of heap events from DbeView
+  int numExps = dbeSession->nexps ();
+  if (!numExps)
+    {
+      fprintf (out_file,
+              GTXT ("There is no heap event information in the experiments\n"));
+      return;
+    }
+  MetricList *mlist = dbev->get_metric_list (MET_HEAP);
+  Hist_data *hist_data;
+  hist_data = dbev->get_hist_data (mlist, type, 0, Hist_data::ALL);
+  if (printStat)
+    printStatistics (hist_data);
+  else
+    printCallStacks (hist_data);
+}
+
+er_print_ioactivity::er_print_ioactivity (DbeView *_dbev, Histable::Type _type,
+                                         bool _printStat, int _limit)
+{
+  dbev = _dbev;
+  type = _type;
+  printStat = _printStat;
+  limit = _limit;
+}
+
+void
+er_print_ioactivity::printCallStacks (Hist_data *hist_data)
+{
+  Hist_data::HistItem *hi;
+  FileData *fData;
+  long stackId;
+  int size = hist_data->size ();
+  if (limit > 0 && limit < size)
+    size = limit;
+
+  for (int i = 0; i < size; i++)
+    {
+      hi = hist_data->fetch (i);
+      fData = (FileData*) hi->obj;
+      stackId = fData->id;
+      if (i != 0)
+       fprintf (out_file, NTXT ("\n"));
+      fprintf (out_file, NTXT ("%s\n"), fData->getFileName ());
+      if (fData->getWriteCnt () > 0)
+       {
+         fprintf (out_file, GTXT ("Write Time=%.6f (secs.)  "),
+                  (double) (fData->getWriteTime () / (double) NANOSEC));
+         fprintf (out_file, GTXT ("Write Bytes=%lld  "),
+                  (long long) fData->getWriteBytes ());
+         fprintf (out_file, GTXT ("Write Count=%d\n"),
+                  (int) (fData->getWriteCnt ()));
+       }
+      if (fData->getReadCnt () > 0)
+       {
+         fprintf (out_file, GTXT ("Read Time=%.6f (secs.)  "),
+                  (double) (fData->getReadTime () / (double) NANOSEC));
+         fprintf (out_file, GTXT ("Read Bytes=%lld  "),
+                  (long long) fData->getReadBytes ());
+         fprintf (out_file, GTXT ("Read Count=%d\n"),
+                  (int) fData->getReadCnt ());
+       }
+      if (fData->getOtherCnt () > 0)
+       {
+         fprintf (out_file, GTXT ("Other I/O Time=%.6f (secs.)  "),
+                  (double) (fData->getOtherTime () / (double) NANOSEC));
+         fprintf (out_file, GTXT ("Other I/O Count=%d\n"),
+                  (int) (fData->getOtherCnt ()));
+       }
+      if (fData->getErrorCnt () > 0)
+       {
+         fprintf (out_file, GTXT ("I/O Error Time=%.6f (secs.)  "),
+                  (double) (fData->getErrorTime () / (double) NANOSEC));
+         fprintf (out_file, GTXT ("I/O Error Count=%d\n"),
+                  (int) (fData->getErrorCnt ()));
+       }
+
+      // There is no stack trace for <Total>
+      if (i == 0)
+       continue;
+
+      // LIBRARY VISIBILITY pass extra argument if necessary to get hide stack
+      Vector<Histable*> *instrs = CallStack::getStackPCs ((void *) stackId);
+      if (instrs != NULL)
+       {
+         int stSize = instrs->size ();
+         for (int j = 0; j < stSize; j++)
+           {
+             Histable *instr = instrs->fetch (j);
+             if (instr != NULL)
+               fprintf (out_file, "  %s\n", instr->get_name ());
+           }
+         delete instrs;
+       }
+    }
+}
+
+void
+er_print_ioactivity::printStatistics (Hist_data *hist_data)
+{
+  Hist_data::HistItem *hi;
+  FileData *fDataTotal;
+
+  hi = hist_data->fetch (0);
+  fDataTotal = (FileData*) hi->obj;
+
+  if (fDataTotal->getWriteCnt () > 0)
+    {
+      fprintf (out_file,
+              GTXT ("\nWrite Statistics\n"));
+      fprintf (out_file,
+              GTXT ("I/O Size Range                    Write Calls          \n"));
+      fprintf (out_file,
+              "-------------------------------------------------------\n");
+      if (fDataTotal->getW0KB1KBCnt () > 0)
+       fprintf (out_file, NTXT ("  0KB - 1KB                       %d\n"),
+                fDataTotal->getW0KB1KBCnt ());
+      if (fDataTotal->getW1KB8KBCnt () > 0)
+       fprintf (out_file, NTXT ("  1KB - 8KB                       %d\n"),
+                fDataTotal->getW1KB8KBCnt ());
+      if (fDataTotal->getW8KB32KBCnt () > 0)
+       fprintf (out_file, NTXT ("  8KB - 32KB                      %d\n"),
+                fDataTotal->getW8KB32KBCnt ());
+      if (fDataTotal->getW32KB128KBCnt () > 0)
+       fprintf (out_file, NTXT ("  32KB - 128KB                    %d\n"),
+                fDataTotal->getW32KB128KBCnt ());
+      if (fDataTotal->getW128KB256KBCnt () > 0)
+       fprintf (out_file, NTXT ("  128KB - 256KB                   %d\n"),
+                fDataTotal->getW128KB256KBCnt ());
+      if (fDataTotal->getW256KB512KBCnt () > 0)
+       fprintf (out_file, NTXT ("  256KB - 512KB                   %d\n"),
+                fDataTotal->getW256KB512KBCnt ());
+      if (fDataTotal->getW512KB1000KBCnt () > 0)
+       fprintf (out_file, NTXT ("  512KB - 1000KB                  %d\n"),
+                fDataTotal->getW512KB1000KBCnt ());
+      if (fDataTotal->getW1000KB10MBCnt () > 0)
+       fprintf (out_file, NTXT ("  1000KB - 10MB                   %d\n"),
+                fDataTotal->getW1000KB10MBCnt ());
+      if (fDataTotal->getW10MB100MBCnt () > 0)
+       fprintf (out_file, NTXT ("  10MB - 100MB                    %d\n"),
+                fDataTotal->getW10MB100MBCnt ());
+      if (fDataTotal->getW100MB1GBCnt () > 0)
+       fprintf (out_file, NTXT ("  100MB - 1GB                     %d\n"),
+                fDataTotal->getW100MB1GBCnt ());
+      if (fDataTotal->getW1GB10GBCnt () > 0)
+       fprintf (out_file, NTXT ("  1GB - 10GB                     %d\n"),
+                fDataTotal->getW1GB10GBCnt ());
+      if (fDataTotal->getW10GB100GBCnt () > 0)
+       fprintf (out_file, NTXT ("  10GB - 100GB                   %d\n"),
+                fDataTotal->getW10GB100GBCnt ());
+      if (fDataTotal->getW100GB1TBCnt () > 0)
+       fprintf (out_file, NTXT ("  100GB - 1TB                    %d\n"),
+                fDataTotal->getW100GB1TBCnt ());
+      if (fDataTotal->getW1TB10TBCnt () > 0)
+       fprintf (out_file, NTXT ("  1TB - 10TB                     %d\n"),
+                fDataTotal->getW1TB10TBCnt ());
+      fprintf (out_file,
+              GTXT ("\nLongest write                     %.6f (secs.)\n"),
+              (double) (fDataTotal->getWSlowestBytes () / (double) NANOSEC));
+      fprintf (out_file, GTXT ("Smallest write bytes              %lld\n"),
+              (long long) fDataTotal->getWSmallestBytes ());
+      fprintf (out_file, GTXT ("Largest write bytes               %lld\n"),
+              (long long) fDataTotal->getWLargestBytes ());
+      fprintf (out_file,
+              GTXT ("Total time                        %.6f (secs.)\n"),
+              (double) (fDataTotal->getWriteTime () / (double) NANOSEC));
+      fprintf (out_file, GTXT ("Total calls                       %d\n"),
+              fDataTotal->getWriteCnt ());
+      fprintf (out_file, GTXT ("Total bytes                       %lld\n"),
+              (long long) fDataTotal->getWriteBytes ());
+    }
+
+  if (fDataTotal->getReadCnt () > 0)
+    {
+      fprintf (out_file,
+              GTXT ("\nRead Statistics\n"));
+      fprintf (out_file,
+              GTXT ("I/O Size Range                    Read Calls         \n"));
+      fprintf (out_file,
+              "------------------------------------------------------\n");
+      if (fDataTotal->getR0KB1KBCnt () > 0)
+       fprintf (out_file, NTXT ("  0KB - 1KB                       %d\n"),
+                fDataTotal->getR0KB1KBCnt ());
+      if (fDataTotal->getR1KB8KBCnt () > 0)
+       fprintf (out_file, NTXT ("  1KB - 8KB                       %d\n"),
+                fDataTotal->getR1KB8KBCnt ());
+      if (fDataTotal->getR8KB32KBCnt () > 0)
+       fprintf (out_file, NTXT ("  8KB - 32KB                      %d\n"),
+                fDataTotal->getR8KB32KBCnt ());
+      if (fDataTotal->getR32KB128KBCnt () > 0)
+       fprintf (out_file, NTXT ("  32KB - 128KB                    %d\n"),
+                fDataTotal->getR32KB128KBCnt ());
+      if (fDataTotal->getR128KB256KBCnt () > 0)
+       fprintf (out_file, NTXT ("  128KB - 256KB                   %d\n"),
+                fDataTotal->getR128KB256KBCnt ());
+      if (fDataTotal->getR256KB512KBCnt () > 0)
+       fprintf (out_file, NTXT ("  256KB - 512KB                   %d\n"),
+                fDataTotal->getR256KB512KBCnt ());
+      if (fDataTotal->getR512KB1000KBCnt () > 0)
+       fprintf (out_file, NTXT ("  512KB - 1000KB                  %d\n"),
+                fDataTotal->getR512KB1000KBCnt ());
+      if (fDataTotal->getR1000KB10MBCnt () > 0)
+       fprintf (out_file, NTXT ("  1000KB - 10MB                   %d\n"),
+                fDataTotal->getR1000KB10MBCnt ());
+      if (fDataTotal->getR10MB100MBCnt () > 0)
+       fprintf (out_file, NTXT ("  10MB - 100MB                    %d\n"),
+                fDataTotal->getR10MB100MBCnt ());
+      if (fDataTotal->getR100MB1GBCnt () > 0)
+       fprintf (out_file, NTXT ("  100MB - 1GB                     %d\n"),
+                fDataTotal->getR100MB1GBCnt ());
+      if (fDataTotal->getR1GB10GBCnt () > 0)
+       fprintf (out_file, NTXT ("  1GB - 10GB                      %d\n"),
+                fDataTotal->getR1GB10GBCnt ());
+      if (fDataTotal->getR10GB100GBCnt () > 0)
+       fprintf (out_file, NTXT ("  10GB - 100GB                    %d\n"),
+                fDataTotal->getR10GB100GBCnt ());
+      if (fDataTotal->getR100GB1TBCnt () > 0)
+       fprintf (out_file, NTXT ("  100GB - 1TB                     %d\n"),
+                fDataTotal->getR100GB1TBCnt ());
+      if (fDataTotal->getR1TB10TBCnt () > 0)
+       fprintf (out_file, NTXT ("  1TB - 10TB                      %d\n"),
+                fDataTotal->getR1TB10TBCnt ());
+      fprintf (out_file,
+              GTXT ("\nLongest time                      %.6f (secs.)\n"),
+              (double) (fDataTotal->getRSlowestBytes () / (double) NANOSEC));
+      fprintf (out_file, GTXT ("Smallest read bytes               %lld\n"),
+              (long long) fDataTotal->getRSmallestBytes ());
+      fprintf (out_file, GTXT ("Largest read bytes                %lld\n"),
+              (long long) fDataTotal->getRLargestBytes ());
+      fprintf (out_file,
+              GTXT ("Total time                        %.6f (secs.)\n"),
+              (double) (fDataTotal->getReadTime () / (double) NANOSEC));
+      fprintf (out_file, GTXT ("Total calls                       %d\n"),
+              fDataTotal->getReadCnt ());
+      fprintf (out_file, GTXT ("Total bytes                       %lld\n"),
+              (long long) fDataTotal->getReadBytes ());
+    }
+
+  if (fDataTotal->getOtherCnt () > 0)
+    {
+      fprintf (out_file, GTXT ("\nOther I/O Statistics\n"));
+      fprintf (out_file,
+              "-----------------------------------------------------\n");
+      fprintf (out_file,
+              GTXT ("Total time                        %.6f (secs.)\n"),
+              (double) (fDataTotal->getOtherTime () / (double) NANOSEC));
+      fprintf (out_file, GTXT ("Total calls                       %d \n"),
+              fDataTotal->getOtherCnt ());
+    }
+  if (fDataTotal->getErrorCnt () > 0)
+    {
+      fprintf (out_file, GTXT ("\nI/O Error Statistics\n"));
+      fprintf (out_file,
+              "-----------------------------------------------------\n");
+      fprintf (out_file,
+              GTXT ("Total time                        %.6f (secs.)\n"),
+              (double) (fDataTotal->getErrorTime () / (double) NANOSEC));
+      fprintf (out_file, GTXT ("Total calls                       %d \n"),
+              fDataTotal->getErrorCnt ());
+    }
+  fprintf (out_file, NTXT ("\n"));
+}
+
+void
+er_print_ioactivity::data_dump ()
+{
+  // get the list of io events from DbeView
+  int numExps = dbeSession->nexps ();
+  if (!numExps)
+    {
+      fprintf (out_file,
+              GTXT ("There is no IO event information in the experiments\n"));
+      return;
+    }
+
+  MetricList *mlist = dbev->get_metric_list (MET_IO);
+  Hist_data *hist_data = dbev->get_hist_data (mlist, type, 0, Hist_data::ALL);
+  if (type == Histable::IOCALLSTACK)
+    printCallStacks (hist_data);
+  else if (printStat)
+    printStatistics (hist_data);
+  else
+    {
+      Metric::HistMetric *hist_metric = hist_data->get_histmetrics ();
+      hist_data->print_label (out_file, hist_metric, 0);
+      hist_data->print_content (out_file, hist_metric, limit);
+      fprintf (out_file, nl);
+    }
+}
+
+er_print_experiment::er_print_experiment (DbeView *_dbev, int bgn_idx,
+                                         int end_idx, bool show_load,
+                                         bool show_header, bool show_stat,
+                                         bool show_over, bool show_odetail)
+{
+  dbev = _dbev;
+  exp_idx1 = bgn_idx;
+  exp_idx2 = end_idx;
+  load = show_load;
+  header = show_header;
+  stat = show_stat;
+  over = show_over;
+  odetail = show_odetail;
+}
+
+void
+er_print_experiment::data_dump ()
+{
+  int index, maxlen;
+
+  maxlen = 0;
+
+  if (stat)
+    {
+      snprintf (fmt1, sizeof (fmt1), NTXT ("%%50s"));
+      if (exp_idx2 > exp_idx1)
+       {
+         statistics_sum (maxlen);
+         fprintf (out_file, nl);
+       }
+
+      for (index = exp_idx1; index <= exp_idx2; index++)
+       statistics_dump (index, maxlen);
+    }
+  else if (over)
+    {
+      snprintf (fmt1, sizeof (fmt1), NTXT ("%%30s"));
+      if (exp_idx2 > exp_idx1)
+       {
+         overview_sum (maxlen);
+         fprintf (out_file, nl);
+       }
+
+      for (index = exp_idx1; index <= exp_idx2; index++)
+       overview_dump (index, maxlen);
+    }
+  else if (header)
+    for (index = exp_idx1; index <= exp_idx2; index++)
+      {
+       if (index != exp_idx1)
+         fprintf (out_file,
+                  "----------------------------------------------------------------\n");
+       header_dump (index);
+      }
+}
+
+void
+er_print_experiment::overview_sum (int &maxlen)
+{
+  int index;
+  Ovw_data *sum_data = new Ovw_data ();
+  for (index = exp_idx1; index <= exp_idx2; index++)
+    {
+      Ovw_data *ovw_data = dbev->get_ovw_data (index);
+      if (ovw_data == NULL)
+       continue;
+      sum_data->sum (ovw_data);
+      delete ovw_data;
+    }
+
+  fprintf (out_file, GTXT ("<Sum across selected experiments>"));
+  fprintf (out_file, nl);
+  overview_summary (sum_data, maxlen);
+  fprintf (out_file, nl);
+  delete sum_data;
+}
+
+void
+er_print_experiment::overview_dump (int exp_idx, int &maxlen)
+{
+  Ovw_data *ovw_data;
+  Ovw_data::Ovw_item ovw_item_labels;
+  Ovw_data::Ovw_item ovw_item;
+  int index;
+  int size;
+
+  ovw_data = dbev->get_ovw_data (exp_idx);
+  if (ovw_data == NULL)
+    return;
+  if (pr_params.header)
+    header_dump (exp_idx);
+  else if (odetail)
+    fprintf (out_file, GTXT ("Experiment: %s\n"),
+            dbeSession->get_exp (exp_idx)->get_expt_name ());
+
+  overview_summary (ovw_data, maxlen);
+  if (!odetail)
+    {
+      delete ovw_data;
+      return;
+    }
+
+  //Get the collection params for the sample selection and display them.
+  fprintf (out_file, NTXT ("\n\n"));
+  fprintf (out_file, fmt1, GTXT ("Individual samples"));
+  fprintf (out_file, NTXT ("\n\n"));
+
+  size = ovw_data->size ();
+  ovw_item_labels = ovw_data->get_labels ();
+
+  for (index = 0; index < size; index++)
+    {
+      ovw_item = ovw_data->fetch (index);
+      fprintf (out_file, fmt1, GTXT ("Sample Number"));
+      fprintf (out_file, NTXT (": %d\n\n"), ovw_item.number);
+      overview_item (&ovw_item, &ovw_item_labels);
+      fprintf (out_file, nl);
+    }
+
+  delete ovw_data;
+}
+
+void
+er_print_experiment::overview_summary (Ovw_data *ovw_data, int &maxlen)
+{
+  char buf[128];
+  int len;
+  Ovw_data::Ovw_item totals;
+  Ovw_data::Ovw_item ovw_item_labels;
+  totals = ovw_data->get_totals ();
+  len = snprintf (buf, sizeof (buf), "%.3lf", tstodouble (totals.total.t));
+  if (maxlen < len)
+    maxlen = len;
+  snprintf (buf, sizeof (buf), NTXT ("%%#%d.0lf    (  %#1.0f %%%%%%%%)"),
+           maxlen - 3, 0.);
+  snprintf (fmt2, sizeof (fmt2), NTXT ("%%%d.3lf"), maxlen);
+  snprintf (fmt3, sizeof (fmt3), buf, 0.0);
+  snprintf (fmt4, sizeof (fmt4), NTXT ("%%%d.3lf (%%5.1f%%%%)"), maxlen);
+  fprintf (out_file, fmt1, GTXT ("Aggregated statistics for selected samples"));
+  fprintf (out_file, NTXT ("\n\n"));
+
+  ovw_item_labels = ovw_data->get_labels ();
+  overview_item (&totals, &ovw_item_labels);
+}
+
+void
+er_print_experiment::overview_item (Ovw_data::Ovw_item *ovw_item,
+                                   Ovw_data::Ovw_item *ovw_item_labels)
+{
+  double start, end, total_value;
+  int index, size;
+  timestruc_t total_time = {0, 0};
+
+  start = tstodouble (ovw_item->start);
+  end = tstodouble (ovw_item->end);
+
+  fprintf (out_file, fmt1, GTXT ("Start Label"));
+  fprintf (out_file, NTXT (": "));
+  fprintf (out_file, NTXT ("%s"), ovw_item->start_label);
+  fprintf (out_file, nl);
+  fprintf (out_file, fmt1, GTXT ("End Label"));
+  fprintf (out_file, NTXT (": %s\n"), ovw_item->end_label);
+
+  fprintf (out_file, fmt1, GTXT ("Start Time (sec.)"));
+  fprintf (out_file, NTXT (": "));
+  if (start == -1.0)
+    fprintf (out_file, GTXT ("N/A"));
+  else
+    fprintf (out_file, fmt2, start);
+  fprintf (out_file, nl);
+  fprintf (out_file, fmt1, GTXT ("End Time (sec.)"));
+  fprintf (out_file, NTXT (": "));
+  if (end == -1.0)
+    fprintf (out_file, GTXT ("N/A"));
+  else
+    fprintf (out_file, fmt2, end);
+  fprintf (out_file, nl);
+  fprintf (out_file, fmt1, GTXT ("Duration (sec.)"));
+  fprintf (out_file, NTXT (": "));
+  fprintf (out_file, fmt2, tstodouble (ovw_item->duration));
+  fprintf (out_file, NTXT ("\n"));
+
+  size = ovw_item->size;
+  for (index = 0; index < size; index++)
+    tsadd (&total_time, &ovw_item->values[index].t);
+
+  total_value = tstodouble (total_time);
+  fprintf (out_file, fmt1, GTXT ("Total Thread Time (sec.)"));
+  fprintf (out_file, NTXT (": "));
+  fprintf (out_file, fmt2, tstodouble (ovw_item->tlwp));
+  fprintf (out_file, NTXT ("\n"));
+  fprintf (out_file, fmt1, GTXT ("Average number of Threads"));
+  fprintf (out_file, NTXT (": "));
+  if (tstodouble (ovw_item->duration) != 0)
+    fprintf (out_file, fmt2, ovw_item->nlwp);
+  else
+    fprintf (out_file, GTXT ("N/A"));
+  fprintf (out_file, NTXT ("\n\n"));
+  fprintf (out_file, fmt1, GTXT ("Process Times (sec.)"));
+  fprintf (out_file, NTXT (":\n"));
+  for (index = 1; index < size; index++)
+    {
+      overview_value (&ovw_item_labels->values[index], ovw_item_labels->type,
+                     total_value);
+      overview_value (&ovw_item->values[index], ovw_item->type,
+                     total_value);
+      fprintf (out_file, NTXT ("\n"));
+    }
+}
+
+void
+er_print_experiment::overview_value (Value *value, ValueTag value_tag,
+                                    double total_value)
+{
+  double dvalue;
+  switch (value_tag)
+    {
+    case VT_LABEL:
+      fprintf (out_file, fmt1, value->l);
+      fprintf (out_file, NTXT (": "));
+      break;
+    case VT_HRTIME:
+      dvalue = tstodouble (value->t);
+      if (dvalue == 0.0)
+       fprintf (out_file, fmt3, 0., 0.);
+      else
+       fprintf (out_file, fmt4, dvalue, 100.0 * dvalue / total_value);
+      break;
+    case VT_INT:
+      fprintf (out_file, NTXT ("%d"), value->i);
+      break;
+    default:
+      fprintf (out_file, fmt3);
+    }
+}
+
+void
+er_print_experiment::statistics_sum (int &maxlen)
+{
+  int index;
+  int size, len;
+  Stats_data *sum_data = new Stats_data ();
+  for (index = exp_idx1; index <= exp_idx2; index++)
+    {
+      Stats_data *stats_data = dbev->get_stats_data (index);
+      if (stats_data == NULL)
+       continue;
+      sum_data->sum (stats_data);
+      delete stats_data;
+    }
+
+  // get the maximum width of values
+  size = sum_data->size ();
+  for (index = 0; index < size; index++)
+    {
+      len = (int) sum_data->fetch (index).value.get_len ();
+      if (maxlen < len)
+       maxlen = len;
+    }
+
+  // print overview average
+  overview_sum (maxlen);
+
+  // print statistics data
+  snprintf (fmt2, sizeof (fmt2), NTXT (": %%%ds\n"), maxlen);
+  statistics_item (sum_data);
+  delete sum_data;
+}
+
+void
+er_print_experiment::statistics_dump (int exp_idx, int &maxlen)
+{
+  Stats_data *stats_data;
+  int index;
+  int size, len;
+  stats_data = dbev->get_stats_data (exp_idx);
+  if (stats_data == NULL)
+    return;
+  if (pr_params.header)
+    {
+      header_dump (exp_idx);
+      fprintf (out_file, nl);
+    }
+  else
+    fprintf (out_file, GTXT ("Experiment: %s\n"),
+            dbeSession->get_exp (exp_idx)->get_expt_name ());
+
+  // get the maximum width of values
+  size = stats_data->size ();
+  for (index = 0; index < size; index++)
+    {
+      len = (int) stats_data->fetch (index).value.get_len ();
+      if (maxlen < len)
+       maxlen = len;
+    }
+
+  // print overview average
+  overview_dump (exp_idx, maxlen);
+  fprintf (out_file, nl);
+
+  // print statistics data
+  snprintf (fmt2, sizeof (fmt2), NTXT (": %%%ds\n"), maxlen);
+  statistics_item (stats_data);
+  delete stats_data;
+}
+
+void
+er_print_experiment::statistics_item (Stats_data *stats_data)
+{
+  int size, index;
+  Stats_data::Stats_item stats_item;
+  char buf[256];
+  size = stats_data->size ();
+  for (index = 0; index < size; index++)
+    {
+      stats_item = stats_data->fetch (index);
+      fprintf (out_file, fmt1, stats_item.label);
+      fprintf (out_file, fmt2, stats_item.value.to_str (buf, sizeof (buf)));
+    }
+  fprintf (out_file, nl);
+}
+
+// Print annotated source or disassembly -- called by er_print only
+void
+print_anno_file (char *name, const char *sel, const char *srcFile,
+                bool isDisasm, FILE *dis_file, FILE *inp_file, FILE *out_file,
+                DbeView *dbev, bool xdefault)
+{
+  Histable *obj;
+  Function *func;
+  Module *module;
+  Vector<int> *marks;
+  Hist_data *hist_data;
+  char *errstr;
+  int index;
+  SourceFile *fitem;
+  int threshold;
+  int compcom_bits;
+  int src_visible;
+  bool hex_visible;
+  bool srcmetrics_visible;
+
+  if ((name == NULL) || (strlen (name) == 0))
+    {
+      fprintf (stderr, GTXT ("Error: No function or file has been specified.\n"));
+      return;
+    }
+
+  // find the function from the name
+  if (!dbeSession->find_obj (dis_file, inp_file, obj, name, sel,
+                            Histable::FUNCTION, xdefault))
+    return;
+
+  if (obj != NULL)
+    {
+      // source or disassembly for <Total>, <Unknown>, or @plt
+      if (obj->get_type () != Histable::FUNCTION)
+       {
+         fprintf (stderr,
+                  GTXT ("Error: %s is not a real function; no source or disassembly available.\n"),
+                  name);
+         return;
+       }
+
+      func = (Function *) obj;
+      if (func->flags & FUNC_FLAG_SIMULATED)
+       {
+         fprintf (stderr,
+                  GTXT ("Error: %s is not a real function; no source or disassembly available.\n"),
+                  name);
+         return;
+       }
+      else if (dbev != NULL && isDisasm)
+       dbev->set_func_scope (true);
+
+      // function found, set module
+      module = func->module;
+      int ix = module->loadobject->seg_idx;
+      if (dbev->get_lo_expand (ix) == LIBEX_HIDE)
+       {
+         char *lo_name = module->loadobject->get_name ();
+         fprintf (stderr,
+                  GTXT ("Error: No source or disassembly available for hidden object %s.\n"),
+                  lo_name);
+         return;
+       }
+
+      if (srcFile)
+       {
+         Vector<SourceFile*> *sources = func->get_sources ();
+         bool found = false;
+         if (sources == NULL)
+           {
+             fitem = func->getDefSrc ();
+             found = (func->line_first > 0)
+                     && strcmp (basename (srcFile),
+                                basename (fitem->get_name ())) == 0;
+           }
+         else
+           {
+             Vec_loop (SourceFile*, sources, index, fitem)
+             {
+               if (strcmp (basename (srcFile), basename (fitem->get_name ())) == 0)
+                 {
+                   found = true;
+                   break;
+                 }
+             }
+           }
+         if (!found)
+           {
+             fprintf (stderr, GTXT ("Error: Source file context %s does not contribute to function `%s'.\n"),
+                      srcFile, name);
+             return;
+           }
+       }
+    }
+  else
+    {
+      // function not found
+      if (sel && strrchr (sel, ':'))
+       {
+         // 'sel' was "@seg_num:address" or "file_name:address"
+         fprintf (stderr,
+                  GTXT ("Error: No function with given name `%s %s' found.\n"),
+                  name, sel);
+         return;
+       }
+      // search for a file of that name
+      if (!dbeSession->find_obj (dis_file, inp_file, obj, name, sel,
+                                Histable::MODULE, xdefault))
+       return;
+
+      if (obj == NULL)
+       { // neither function nor file found
+         fprintf (stderr, GTXT ("Error: No function or file with given name `%s' found.\n"),
+                  name);
+         return;
+       }
+
+      func = NULL;
+      module = (Module *) obj;
+      int ix = module->loadobject->seg_idx;
+      if (dbev->get_lo_expand (ix) == LIBEX_HIDE)
+       {
+         char *lo_name = module->loadobject->get_name ();
+         fprintf (stderr, GTXT ("Error: No source or disassembly available for hidden object %s.\n"),
+                  lo_name);
+         return;
+       }
+      if (name)
+       srcFile = name;
+    }
+
+  if (module == NULL || module->get_name () == NULL)
+    {
+      fprintf (stderr, GTXT ("Error: Object name not recorded in experiment\n"));
+      return;
+    }
+  module->read_stabs ();
+
+  if (!isDisasm && (module->file_name == NULL
+                   || (module->flags & MOD_FLAG_UNKNOWN) != 0
+                   || *module->file_name == 0))
+    {
+      fprintf (stderr, GTXT ("Error: Source location not recorded in experiment\n"));
+      return;
+    }
+
+  MetricList *metric_list = dbev->get_metric_list (MET_NORMAL);
+  int sort_ref_index = metric_list->get_sort_ref_index ();
+  if (isDisasm)
+    metric_list->set_sort_ref_index (-1);
+
+  // Ask DbeView to generate function-level data
+  //   MSI: I think this is used only to get totals to compute percentages
+  hist_data = dbev->get_hist_data (metric_list, Histable::FUNCTION, 0,
+                                  Hist_data::ALL);
+  MetricList *nmlist = hist_data->get_metric_list ();
+  metric_list->set_sort_ref_index (sort_ref_index);
+  if (nmlist->get_items ()->size () != 0
+      && hist_data->get_status () != Hist_data::SUCCESS)
+    {
+      errstr = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+      if (errstr)
+       {
+         fprintf (stderr, GTXT ("Error: %s\n"), errstr);
+         free (errstr);
+       }
+      return;
+    }
+
+  marks = new Vector<int>;
+  if (isDisasm)
+    {
+      threshold = dbev->get_thresh_dis ();
+      compcom_bits = dbev->get_dis_compcom ();
+      src_visible = dbev->get_src_visible ();
+      hex_visible = dbev->get_hex_visible ();
+      srcmetrics_visible = dbev->get_srcmetric_visible ();
+    }
+  else
+    {
+      threshold = dbev->get_thresh_src ();
+      compcom_bits = dbev->get_src_compcom ();
+      src_visible = SRC_NA;
+      hex_visible = false;
+      srcmetrics_visible = false;
+    }
+
+  dump_anno_file (out_file, isDisasm ? Histable::INSTR : Histable::LINE,
+                 module, dbev, nmlist, hist_data->get_totals ()->value,
+                 srcFile, func, marks, threshold, compcom_bits,
+                 src_visible, hex_visible, srcmetrics_visible);
+
+  delete marks;
+
+  errstr = module->anno_str ();
+  if (errstr)
+    {
+      fprintf (stderr, GTXT ("Error: %s\n"), errstr);
+      free (errstr);
+    }
+  delete hist_data;
+}
+
+void
+print_html_title (FILE *out_file, char *title)
+{
+  // This will print a header row for the report
+  fprintf (out_file, "<html><title>%s</title>\n", title);
+  fprintf (out_file, "<center><h3>%s</h3></center>\n", title);
+}
+
+void
+print_html_label (FILE *out_file, MetricList *metrics_list)
+{
+  int mlist_sz;
+
+  // This will print  a header row for the metrics
+  Vector<Metric*> *mlist = metrics_list->get_items ();
+  mlist_sz = mlist->size ();
+
+  fprintf (out_file, "<style type=\"text/css\">\n");
+  fprintf (out_file, "<!--\nBODY\n");
+  fprintf (out_file, ".th_C   { text-align:center; background-color:lightgoldenrodyellow; }\n");
+  fprintf (out_file, ".th_CG  { text-align:center; background-color:#ffff33; }\n");
+  fprintf (out_file, ".th_L   { text-align:left; background-color:lightgoldenrodyellow; }\n");
+  fprintf (out_file, ".th_LG  { text-align:left; background-color:#ffff33; }\n");
+  fprintf (out_file, ".td_R   { text-align:right;  }\n");
+  fprintf (out_file, ".td_RG  { text-align:right; background-color:#ffff33; }\n");
+  fprintf (out_file, ".td_L   { text-align:left; }\n");
+  fprintf (out_file, ".td_LG  { text-align:left;  background-color:#ffff33; }\n");
+  fprintf (out_file, "-->\n</style>");
+  fprintf (out_file, "<center><table border=1 cellspacing=2>\n<tr>");
+
+  for (int index = 0; index < mlist_sz; index++)
+    {
+      Metric *mitem = mlist->fetch (index);
+      int ncols = 0;
+      if (mitem->is_visible ())
+       ncols++;
+      if (mitem->is_tvisible ())
+       ncols++;
+      if (mitem->is_pvisible ())
+       ncols++;
+      if (ncols == 0)
+       continue;
+      char *name = strdup (mitem->get_name ());
+      char *name2 = split_metric_name (name);
+      const char *style = index == metrics_list->get_sort_ref_index () ? "G" : "";
+
+      // start the column, with colspan setting, legend, and sort metric indicator
+      if (ncols == 1)
+       {
+         if (mitem->get_vtype () == VT_LABEL)
+           // left-adjust the name metric
+           fprintf (out_file,
+                    "<th class=\"th_L%s\">%s&nbsp;<br>%s&nbsp;%s&nbsp;<br>%s&nbsp;</th>",
+                    style, mitem->legend == NULL ? "&nbsp;" : mitem->legend,
+                    (index == metrics_list->get_sort_ref_index ()) ? "&nabla;" : "&nbsp;",
+                    name, name2 == NULL ? "&nbsp;" : name2);
+         else
+           // but center the others
+           fprintf (out_file,
+                    "<th class=\"th_C%s\">%s&nbsp;<br>%s&nbsp;%s&nbsp;<br>%s&nbsp;</th>",
+                    style, mitem->legend == NULL ? "&nbsp;" : mitem->legend,
+                    (index == metrics_list->get_sort_ref_index ()) ?
+                        "&nabla;" : "&nbsp;",
+                    name, name2 == NULL ? NTXT ("&nbsp;") : name2);
+       }
+      else
+       // name metric can't span columns
+       fprintf (out_file,
+                "<th colspan=%d class=\"th_C%s\">%s&nbsp;<br>%s&nbsp;%s&nbsp;<br>%s&nbsp;</th>",
+                ncols, style,
+                mitem->legend == NULL ? "&nbsp;" : mitem->legend,
+                index == metrics_list->get_sort_ref_index () ?
+                    "&nabla;" : "&nbsp;",
+                name, name2 == NULL ? "&nbsp;" : name2);
+
+      free (name);
+    }
+
+  // end this row, start the units row
+  fprintf (out_file, NTXT ("</tr>\n<tr>"));
+
+  // now do the units row
+  for (int index = 0; index < mlist_sz; index++)
+    {
+      Metric *mitem = mlist->fetch (index);
+      const char *style = index == metrics_list->get_sort_ref_index () ? "G" : "";
+
+      if (mitem->is_tvisible ())
+       fprintf (out_file, "<th class=\"th_C%s\">&nbsp;(%s)</th>", style,
+                GTXT ("sec."));
+      if (mitem->is_visible ())
+       {
+         if (mitem->get_abbr_unit () == NULL)
+           fprintf (out_file, "<th class=\"th_C%s\">&nbsp;</th>", style);
+         else
+           fprintf (out_file, "<th class=\"th_C%s\">(%s)</th>", style,
+                    mitem->get_abbr_unit () == NULL ? "&nbsp;"
+                    : mitem->get_abbr_unit ());
+       }
+      if (mitem->is_pvisible ())
+       fprintf (out_file, "<th class=\"th_C%s\">&nbsp;(%%)</th>", style);
+    }
+  fprintf (out_file, NTXT ("</tr>\n"));
+}
+
+void
+print_html_content (FILE *out_file, Hist_data *data, MetricList *metrics_list,
+                   int limit, Histable::NameFormat nfmt)
+{
+  Hist_data::HistItem *item;
+
+  // printing contents.
+  for (int i = 0; i < limit; i++)
+    {
+      item = data->fetch (i);
+      print_html_one (out_file, data, item, metrics_list, nfmt);
+    }
+}
+
+void
+print_html_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item,
+               MetricList *metrics_list, Histable::NameFormat nfmt)
+{
+  Metric *mitem;
+  int index;
+  int visible, tvisible, pvisible;
+  TValue *value;
+  double percent;
+
+  fprintf (out_file, NTXT ("<tr>"));
+  Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+  {
+    visible = mitem->is_visible ();
+    tvisible = mitem->is_tvisible ();
+    pvisible = mitem->is_pvisible ();
+    const char *style = index == metrics_list->get_sort_ref_index () ? "G" : "";
+
+    if (tvisible)
+      {
+       value = &(item->value[index]);
+       if (value->ll == 0LL)
+         fprintf (out_file,
+                  "<td class=\"td_R%s\"><tt>0.&nbsp;&nbsp;&nbsp;</tt></td>",
+                  style);
+       else
+         fprintf (out_file, "<td class=\"td_R%s\"><tt>%4.3lf</tt></td>",
+                  style, 1.e-6 * value->ll / dbeSession->get_clock (-1));
+      }
+
+    if (visible)
+      {
+       if (mitem->get_vtype () == VT_LABEL)
+         {
+           value = &(item->value[index]);
+           char *r;
+           if (value->tag == VT_OFFSET)
+             r = ((DataObject*) (item->obj))->get_offset_name ();
+           else
+             r = item->obj->get_name (nfmt);
+           char *n = html_ize_name (r);
+           fprintf (out_file, NTXT ("<td class=\"td_L%s\">%s</td>"), style, n);
+           free (n);
+         }
+       else
+         {
+           value = &(item->value[index]);
+           switch (value->tag)
+             {
+             case VT_DOUBLE:
+               if (value->d == 0.0)
+                 fprintf (out_file,
+                     "<td class=\"td_R%s\"><tt>0.&nbsp;&nbsp;&nbsp;</tt></td>",
+                          style);
+               else
+                 fprintf (out_file,
+                          "<td  class=\"td_R%s\"><tt>%4.3lf</tt></td>", style,
+                          value->d);
+               break;
+             case VT_INT:
+               fprintf (out_file, "<td  class=\"td_R%s\"><tt>%d</tt></td>",
+                        style, value->i);
+               break;
+             case VT_LLONG:
+               fprintf (out_file, "<td  class=\"td_R%s\"><tt>%lld</td></tt>",
+                        style, value->ll);
+               break;
+             case VT_ULLONG:
+               fprintf (out_file, "<td  class=\"td_R%s\"><tt>%llu</td></tt>",
+                        style, value->ull);
+               break;
+             case VT_ADDRESS:
+               fprintf (out_file,
+                        "<td  class=\"td_R%s\"><tt>%u:0x%08x</tt></td>", style,
+                        ADDRESS_SEG (value->ll), ADDRESS_OFF (value->ll));
+               break;
+             case VT_FLOAT:
+               if (value->f == 0.0)
+                 fprintf (out_file,
+                          "<td  class=\"td_R%s\"><tt>0.&nbsp;&nbsp;&nbsp;</tt></td>",
+                          style);
+               else
+                 fprintf (out_file,
+                          "<td  class=\"td_R%s\"><tt>%4.3f</tt></td>",
+                          style, value->f);
+               break;
+             case VT_SHORT:
+               fprintf (out_file, "<td  class=\"td_R%s\"><tt>%d</tt></td>",
+                        style, value->s);
+               break;
+               // ignoring the following cases (why?)
+             case VT_HRTIME:
+             case VT_LABEL:
+             case VT_OFFSET:
+               break;
+             }
+         }
+      }
+
+    if (pvisible)
+      {
+       percent = data->get_percentage (item->value[index].to_double (), index);
+       if (percent == 0.0)
+         // adjust to change format from xx.yy%
+         fprintf (out_file, "<td class=\"td_R%s\">0.&nbsp;&nbsp;&nbsp;</td>",
+                  style);
+       else
+         // adjust format below to change format from xx.yy%
+         fprintf (out_file, "<td class=\"td_R%s\">%3.2f</td>", style,
+                  (100.0 * percent));
+      }
+  }
+  fprintf (out_file, NTXT ("</tr>\n"));
+}
+
+void
+print_html_trailer (FILE *out_file)
+{
+  fprintf (out_file, NTXT ("</table></center></html>\n"));
+}
+
+static char *
+del_delim (char *s)
+{
+  size_t len = strlen (s);
+  if (len > 0)
+    s[len - 1] = 0;
+  return s;
+}
+
+void
+print_delim_label (FILE *out_file, MetricList *metrics_list, char delim)
+{
+  char line0[2 * MAX_LEN], line1[2 * MAX_LEN];
+  char line2[2 * MAX_LEN], line3[2 * MAX_LEN];
+  size_t len;
+
+  // This will print four header rows for the metrics
+  line0[0] = 0;
+  line1[0] = 0;
+  line2[0] = 0;
+  line3[0] = 0;
+  Vector<Metric*> *mlist = metrics_list->get_items ();
+  for (int index = 0, mlist_sz = mlist->size (); index < mlist_sz; index++)
+    {
+      Metric *mitem = mlist->fetch (index);
+      if (!(mitem->is_visible () || mitem->is_tvisible ()
+           || mitem->is_pvisible ()))
+       continue;
+      char *name = strdup (mitem->get_name ());
+      char *name2 = split_metric_name (name);
+
+      if (mitem->is_tvisible ())
+       {
+         len = strlen (line0);
+         snprintf (line0 + len, sizeof (line0) - len, NTXT ("\"%s\"%c"),
+                   mitem->legend == NULL ? NTXT ("") : mitem->legend, delim);
+         len = strlen (line1);
+         snprintf (line1 + len, sizeof (line1) - len, NTXT ("\"%s\"%c"),
+                   name, delim);
+         len = strlen (line2);
+         snprintf (line2 + len, sizeof (line2) - len, NTXT ("\"%s\"%c"),
+                   name2 == NULL ? NTXT ("") : name2, delim);
+         len = strlen (line3);
+         if (index == metrics_list->get_sort_ref_index ())
+           snprintf (line3 + len, sizeof (line3) - len, NTXT ("\"V  %s\"%c"),
+                     GTXT ("(sec.)"), delim);
+         else
+           snprintf (line3 + len, sizeof (line3) - len, NTXT ("\"   %s\"%c"),
+                     GTXT ("(sec.)"), delim);
+       }
+      if (mitem->is_visible ())
+       {
+         len = strlen (line0);
+         snprintf (line0 + len, sizeof (line0) - len, "\"%s\"%c",
+                   mitem->legend == NULL ? "" : mitem->legend, delim);
+
+         len = strlen (line1);
+         snprintf (line1 + len, sizeof (line1) - len, "\"%s\"%c",
+                   name, delim);
+
+         len = strlen (line2);
+         snprintf (line2 + len, sizeof (line2) - len, "\"%s\"%c",
+                   name2 == NULL ? NTXT ("") : name2, delim);
+
+         len = strlen (line3);
+         char *au = mitem->get_abbr_unit ();
+
+         if (index == metrics_list->get_sort_ref_index ())
+           {
+             if (au == NULL)
+               snprintf (line3 + len, sizeof (line3) - len, "\"V  \"%c", delim);
+             else
+               snprintf (line3 + len, sizeof (line3) - len, "\"V  (%s)\"%c",
+                           au, delim);
+           }
+         else
+           {
+             if (au == NULL)
+               snprintf (line3 + len, sizeof (line3) - len, "\"   \"%c",
+                         delim);
+             else
+               snprintf (line3 + len, sizeof (line3) - len, "\"   (%s)\"%c",
+                         au, delim);
+           }
+       }
+      if (mitem->is_pvisible ())
+       {
+         len = strlen (line0);
+         snprintf (line0 + len, sizeof (line0) - len, NTXT ("\"%s\"%c"),
+                   mitem->legend == NULL ? NTXT ("") : mitem->legend, delim);
+
+         len = strlen (line1);
+         snprintf (line1 + len, sizeof (line1) - len, NTXT ("\"%s\"%c"),
+                   name, delim);
+
+         len = strlen (line2);
+         snprintf (line2 + len, sizeof (line2) - len, NTXT ("\"%s\"%c"),
+                   name2 == NULL ? NTXT ("") : name2, delim);
+
+         len = strlen (line3);
+         if (index == metrics_list->get_sort_ref_index ())
+           snprintf (line3 + len, sizeof (line3) - len, NTXT ("\"V  %s\"%c"),
+                     NTXT ("%%"), delim);
+         else
+           snprintf (line3 + len, sizeof (line3) - len, NTXT ("\"   %s\"%c"),
+                     NTXT ("%%"), delim);
+       }
+      free (name);
+    }
+  // now remove the trailing delimiter, and print the four lines
+  fprintf (out_file, NTXT ("%s\n"), del_delim (line0));
+  fprintf (out_file, NTXT ("%s\n"), del_delim (line1));
+  fprintf (out_file, NTXT ("%s\n"), del_delim (line2));
+  fprintf (out_file, NTXT ("%s\n"), del_delim (line3));
+}
+
+void
+print_delim_content (FILE *out_file, Hist_data *data, MetricList *metrics_list,
+                    int limit, Histable::NameFormat nfmt, char delim)
+{
+  Hist_data::HistItem *item;
+  int i;
+
+  // printing contents.
+  for (i = 0; i < limit; i++)
+    {
+      item = data->fetch (i);
+      print_delim_one (out_file, data, item, metrics_list, nfmt, delim);
+    }
+}
+
+void
+print_delim_trailer (FILE */*out_file*/, char /*delim*/) { }
+
+// EUGENE does this function work properly when "-compare ratio" is used?
+//   how about when the ratio is nonzero-divided-by-zero?
+// EUGENE actually, review this entire file
+
+void
+print_delim_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item,
+                MetricList *metrics_list, Histable::NameFormat nfmt,
+                char delim)
+{
+  Metric *mitem;
+  int index;
+  int visible, tvisible, pvisible;
+  TValue *value;
+  double percent;
+  size_t len;
+
+  char line1[2 * MAX_LEN];
+  *line1 = 0;
+  Vec_loop (Metric*, metrics_list->get_items (), index, mitem)
+  {
+    visible = mitem->is_visible ();
+    tvisible = mitem->is_tvisible ();
+    pvisible = mitem->is_pvisible ();
+    if (tvisible)
+      {
+       value = &(item->value[index]);
+       len = strlen (line1);
+       if (value->ll == 0LL)
+         snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c", delim);
+       else
+         snprintf (line1 + len, sizeof (line1) - len, "\"%4.3lf\"%c",
+                   1.e-6 * value->ll / dbeSession->get_clock (-1),
+                   delim);
+      }
+
+    if (visible)
+      {
+       len = strlen (line1);
+       if (mitem->get_vtype () == VT_LABEL)
+         {
+           value = &(item->value[index]);
+           char *r;
+           if (value->tag == VT_OFFSET)
+             r = ((DataObject*) (item->obj))->get_offset_name ();
+           else
+             r = item->obj->get_name (nfmt);
+           char *p = csv_ize_name (r, delim);
+           snprintf (line1 + len, sizeof (line1) - len, "\"%s\"%c", p, delim);
+           free (p);
+         }
+       else
+         {
+           value = &(item->value[index]);
+           switch (value->tag)
+             {
+             case VT_DOUBLE:
+               if (value->d == 0.0)
+                 snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c",
+                           delim);
+               else
+                 snprintf (line1 + len, sizeof (line1) - len, "\"%4.3lf\"%c",
+                           value->d, delim);
+               break;
+             case VT_INT:
+               snprintf (line1 + len, sizeof (line1) - len, "\"%d\"%c",
+                         value->i, delim);
+               break;
+             case VT_LLONG:
+               snprintf (line1 + len, sizeof (line1) - len, "\"%lld\"%c",
+                         value->ll, delim);
+               break;
+             case VT_ULLONG:
+               snprintf (line1 + len, sizeof (line1) - len, "\"%llu\"%c",
+                         value->ull, delim);
+               break;
+             case VT_ADDRESS:
+               snprintf (line1 + len, sizeof (line1) - len, "\"%u:0x%08x\"%c",
+                         ADDRESS_SEG (value->ll),
+                         ADDRESS_OFF (value->ll), delim);
+               break;
+             case VT_FLOAT:
+               if (value->f == 0.0)
+                 snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c",
+                           delim);
+               else
+                 snprintf (line1 + len, sizeof (line1) - len, "\"%4.3f\"%c",
+                           value->f, delim);
+               break;
+             case VT_SHORT:
+               snprintf (line1 + len, sizeof (line1) - len, "\"%d\"%c",
+                         value->s, delim);
+               break;
+               // ignoring the following cases (why?)
+             case VT_HRTIME:
+             case VT_LABEL:
+             case VT_OFFSET:
+               break;
+             }
+         }
+      }
+
+    if (pvisible)
+      {
+       len = strlen (line1);
+       percent = data->get_percentage (item->value[index].to_double (), index);
+       if (percent == 0.0)
+         // adjust to change format from xx.yy%
+         snprintf (line1 + len, sizeof (line1) - len, "\"0.\"%c", delim);
+       else
+         // adjust format below to change format from xx.yy%
+         snprintf (line1 + len, sizeof (line1) - len, "\"%3.2f\"%c",
+                   (100.0 * percent), delim);
+      }
+  }
+  fprintf (out_file, NTXT ("%s\n"), del_delim (line1));
+}
+
+char *
+html_ize_name (char *name)
+{
+  StringBuilder sb;
+  for (size_t i = 0; i < strlen (name); i++)
+    {
+      switch (name[i])
+       {
+       case ' ': sb.append (NTXT ("&nbsp;"));
+         break;
+       case '"': sb.append (NTXT ("&quot;"));
+         break;
+       case '&': sb.append (NTXT ("&amp;"));
+         break;
+       case '<': sb.append (NTXT ("&lt;"));
+         break;
+       case '>': sb.append (NTXT ("&gt;"));
+         break;
+       default: sb.append (name[i]);
+         break;
+       }
+    }
+  char *ret = sb.toString ();
+  return ret;
+}
+
+char *
+csv_ize_name (char *name, char /*delim*/)
+{
+  StringBuilder sb;
+  for (size_t i = 0; i < strlen (name); i++)
+    sb.append (name[i]);
+  char *ret = sb.toString ();
+  return ret;
+}
+
+// Split a metric name into two parts, replacing a blank with
+//     a zero and returning pointer to the rest of the string, or
+//     leaving the string unchanged, and returning NULL;
+
+char *
+split_metric_name (char *name)
+{
+  // figure out the most even split of the name
+  size_t len = strlen (name);
+  char *middle = &name[len / 2];
+
+  // find the first blank
+  char *first = strchr (name, (int) ' ');
+  if (first == NULL)  // no blanks
+    return NULL;
+  char *last = first;
+  char *p = first;
+  for (;;)
+    {
+      p = strchr (p + 1, (int) ' ');
+      if (p == NULL)
+       break;
+      if (p < middle)
+       {
+         first = p;
+         last = p;
+       }
+      else
+       {
+         last = p;
+         break;
+       }
+    }
+  // pick the better of the two
+  char *ret;
+  int f = (int) (middle - first);
+  int l = (int) (last - middle);
+  if ((first == last) || (f <= l))
+    {
+      *first = '\0';
+      ret = first + 1;
+    }
+  else
+    {
+      *last = '\0';
+      ret = last + 1;
+    }
+  return ret;
+}
diff --git a/gprofng/src/Print.h b/gprofng/src/Print.h
new file mode 100644 (file)
index 0000000..4bc6655
--- /dev/null
@@ -0,0 +1,283 @@
+/* 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 _PRINT_H
+#define _PRINT_H
+
+
+// Include files
+#include <stdio.h>
+#include <stdlib.h>
+#include "dbe_types.h"
+#include "Metric.h"
+#include "Hist_data.h"
+#include "Ovw_data.h"
+#include "Stats_data.h"
+#include "Emsg.h"
+#include "Exp_Layout.h"
+#include "DefaultMap.h"
+#include "FileData.h"
+#include "HeapData.h"
+#include "HashMap.h"
+
+const char nl[] = "\n";
+const char tab[] = "\t";
+
+// Printing options.
+enum Print_destination
+{
+  DEST_PRINTER      = 0,
+  DEST_FILE         = 1,
+  DEST_OPEN_FILE    = 2
+};
+
+enum Print_mode
+{
+  MODE_LIST,
+  MODE_DETAIL,
+  MODE_GPROF,
+  MODE_ANNOTATED
+};
+
+struct Print_params
+{
+  Print_destination dest;   // printer or file
+  char *name;               // of printer or file
+  int ncopies;              // # of copies
+  bool header;              // print header first
+  FILE *openfile;           // if destination is DEST_OPEN_FILE
+};
+
+class Experiment;
+class MetricList;
+class DbeView;
+class Stack_coverage;
+class Function;
+class LoadObject;
+
+//  Class Definitions
+class er_print_common_display
+{
+public:
+  er_print_common_display ()
+  {
+    out_file = NULL;
+    pr_params.header = false;
+  }
+
+  virtual ~er_print_common_display () { }
+
+  //  Open the file/printer to write to
+  int open (Print_params *);
+
+  void
+  set_out_file (FILE *o)
+  {
+    out_file = o;
+    pr_params.dest = DEST_FILE;
+  }
+
+  //  Print the final output data.  This function calls
+  //  data_dump() to actually do the dumping of data.
+  bool print_output ();
+
+  //  Print the output in the appropriate format.
+  virtual void data_dump () = 0;
+
+  void header_dump (int exp_idx);
+
+  // Return the report. If the report size is greater than max, return truncated report
+  // Allocates memory, so the caller should free this memory.
+  char *get_output (int max);
+
+protected:
+  DbeView *dbev;
+  FILE *out_file;
+  Print_params pr_params;
+  char *tmp_file;
+  int exp_idx1, exp_idx2;
+  bool load;
+  bool header;
+};
+
+class er_print_histogram : public er_print_common_display
+{
+public:
+  er_print_histogram (DbeView *dbv, Hist_data *data, MetricList *metrics_list,
+                     Print_mode disp_type, int limit, char *sort_name,
+                     Histable *sobj, bool show_load, bool show_header);
+  void data_dump ();
+
+private:
+  void dump_list (int limit);
+  void dump_detail (int limit);
+  void get_gprof_width (Metric::HistMetric *hist_metric, int limit);
+  void dump_gprof (int limit);
+  void dump_annotated_dataobjects (Vector<int> *marks, int threshold);
+  void dump_annotated ();
+
+  Stack_coverage *stack_cov;
+  Hist_data *hist_data;
+  MetricList *mlist;
+  Print_mode type;
+  int number_entries;
+  char *sort_metric;
+  Histable *sel_obj;
+};
+
+class er_print_ctree : public er_print_common_display
+{
+public:
+  er_print_ctree (DbeView *dbv, Vector<Histable*> *cstack, Histable *sobj,
+                 int limit);
+  void data_dump ();
+  void print_children (Hist_data *data, int index, Histable *obj, char *prefix,
+                      Hist_data::HistItem *total);
+
+private:
+  Vector<Histable*> *cstack;
+  Histable *sobj;
+  MetricList *mlist;
+  Metric::HistMetric *hist_metric;
+  char **fmt_int;
+  char **fmt_real0;
+  char **fmt_real1;
+  int limit;
+  int print_row;
+};
+
+class er_print_gprof : public er_print_common_display
+{
+public:
+  er_print_gprof (DbeView *dbv, Vector<Histable*> *cstack);
+  void data_dump ();
+private:
+  Vector<Histable*> *cstack;
+};
+
+class er_print_leaklist : public er_print_common_display
+{
+public:
+  er_print_leaklist (DbeView *dbv, bool show_leak,
+                    bool show_alloca, int limit);
+  void data_dump ();
+
+private:
+  bool leak;
+  bool alloca;
+  int limit;
+};
+
+class er_print_heapactivity : public er_print_common_display
+{
+public:
+  er_print_heapactivity (DbeView *_dbev, Histable::Type _type,
+                        bool _printStat, int _limit);
+  void data_dump ();
+
+private:
+  void printStatistics (Hist_data *hist_data);
+  void printCallStacks (Hist_data *hist_data);
+
+  Histable::Type type;
+  bool printStat;
+  int limit;
+};
+
+class er_print_ioactivity : public er_print_common_display
+{
+public:
+  er_print_ioactivity (DbeView *_dbev, Histable::Type _type,
+                      bool _printStat, int _limit);
+  void data_dump ();
+
+private:
+  void printStatistics (Hist_data *hist_data);
+  void printCallStacks (Hist_data *hist_data);
+
+  Histable::Type type;
+  bool printStat;
+  int limit;
+};
+
+class er_print_experiment : public er_print_common_display
+{
+public:
+  er_print_experiment (DbeView *me, int bgn_idx, int end_idx, bool show_load,
+          bool show_header, bool show_stat, bool show_over, bool show_odetail);
+  void data_dump ();
+
+private:
+  char fmt1[32], fmt2[32], fmt3[32], fmt4[32];
+  // buffers shared by the following functions
+  void overview_sum (int &maxlen);
+  void overview_dump (int exp_idx, int &maxlen);
+  void overview_summary (Ovw_data *ovw_data, int &maxlen);
+  void overview_item (Ovw_data::Ovw_item *ovw_item,
+                     Ovw_data::Ovw_item *ovw_item_labels);
+  void overview_value (Value *value, ValueTag value_tag,
+                      double total_value);
+  void statistics_sum (int &maxlen);
+  void statistics_dump (int exp_idx, int &maxlen);
+  void statistics_item (Stats_data *stats_data);
+
+  bool stat;
+  bool over;
+  bool odetail;
+};
+
+//  Print the header.  Experiment name and the sample
+//  selection, along with the percentage.
+char *pr_load_objects (Vector<LoadObject*> *loadobjects, char *lead);
+char *pr_samples (Experiment *exp);
+char *pr_mesgs (Emsg *msg, const char *null_str, const char *lead);
+void print_load_object (FILE *out_file);
+void print_header (Experiment *exp, FILE *out_file);
+
+// Print Function metrics
+void get_width (Hist_data *data, MetricList *metrics_list,
+               Metric::HistMetric *hist_metric);
+void get_format (char **fmt_int, char **fmt_real0, char **fmt_real1,
+                MetricList *metrics_list, Metric::HistMetric *hist_metric,
+                int nspace);
+int print_label (FILE *out_file, MetricList *metrics_list,
+                Metric::HistMetric *hist_metric, int space);
+void print_anno_file (char *name, const char *sel, const char *srcFile,
+                     bool isDisasm, FILE *dis_file, FILE *inp_file,
+                     FILE *out_file, DbeView *dbev, bool xdefault);
+void print_html_title (FILE *out_file, char *title);
+void print_html_label (FILE *out_file, MetricList *metrics_list);
+void print_html_content (FILE *out_file, Hist_data *d, MetricList *metrics_list,
+                        int limit, Histable::NameFormat nfmt);
+void print_html_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item,
+                    MetricList *metrics_list, Histable::NameFormat nfmt);
+void print_html_trailer (FILE* out_file);
+char *html_ize_name (char *name);
+void print_delim_label (FILE *out_file, MetricList *metrics_list, char delim);
+void print_delim_content (FILE *out_file, Hist_data *data,
+                         MetricList *metrics_list, int limit,
+                         Histable::NameFormat nfmt, char delim);
+void print_delim_one (FILE *out_file, Hist_data *data, Hist_data::HistItem *item,
+              MetricList *metrics_list, Histable::NameFormat nfmt, char delim);
+void print_delim_trailer (FILE* out_file, char delim);
+char *csv_ize_name (char *name, char delim);
+char *split_metric_name (char *name);
+
+#endif
diff --git a/gprofng/src/QLParser.h b/gprofng/src/QLParser.h
new file mode 100644 (file)
index 0000000..c4665e8
--- /dev/null
@@ -0,0 +1,61 @@
+/* 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 _QLPARSER_H
+#define _QLPARSER_H
+
+#include <sstream>
+#include <istream>
+#include <iostream>
+#include "Expression.h"
+
+/* This class contains parser inputs (a string, if non-NULL: if NULL, use cin),
+   and outputs (obtained via operator(), which resets the output
+   expression).  The destructor deletes the returned expression to allow
+   exception throws on syntax error to clean up properly.  */
+
+namespace QL
+{
+  struct Result
+  {
+    std::stringstream streamify;
+  public:
+    std::istream in;
+    Expression *out;
+
+    Result () : in (std::cin.rdbuf ()), out (NULL) { }
+    Result (const char *instr) : streamify (std::string (instr)),
+       in (streamify.rdbuf ()), out (NULL) { }
+
+    Expression *operator() ()
+    {
+      Expression *o = out;
+      out = NULL;
+      return o;
+    }
+
+    ~Result ()
+    {
+      delete out;
+    }
+  };
+};
+
+#endif /* _QLPARSER_H */
diff --git a/gprofng/src/QLParser.tab.cc b/gprofng/src/QLParser.tab.cc
new file mode 100644 (file)
index 0000000..4517b2e
--- /dev/null
@@ -0,0 +1,1453 @@
+// A Bison parser, made by GNU Bison 3.7.5.
+
+// Skeleton implementation for Bison LALR(1) parsers in C++
+
+// Copyright (C) 2002-2015, 2018-2021 Free Software Foundation, Inc.
+
+// 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 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.  If not, see <http://www.gnu.org/licenses/>.
+
+// As a special exception, you may create a larger work that contains
+// part or all of the Bison parser skeleton and distribute that work
+// under terms of your choice, so long as that work isn't itself a
+// parser generator using the skeleton or a modified version thereof
+// as a parser skeleton.  Alternatively, if you modify or redistribute
+// the parser skeleton itself, you may (at your option) remove this
+// special exception, which will cause the skeleton and the resulting
+// Bison output files to be licensed under the GNU General Public
+// License without this special exception.
+
+// This special exception was added by the Free Software Foundation in
+// version 2.2 of Bison.
+
+// DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+// especially those whose name start with YY_ or yy_.  They are
+// private implementation details that can be changed or removed.
+
+// "%code top" blocks.
+#line 28 "QLParser.yy"
+
+#include <stdio.h>
+#include <string.h>
+#include <string>
+
+#line 45 "QLParser.tab.cc"
+
+
+
+
+#include "QLParser.tab.hh"
+
+
+// Unqualified %code blocks.
+#line 42 "QLParser.yy"
+
+namespace QL
+{
+  static QL::Parser::symbol_type yylex (QL::Result &result);
+}
+
+#line 61 "QLParser.tab.cc"
+
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+#  if ENABLE_NLS
+#   include <libintl.h> // FIXME: INFRINGES ON USER NAME SPACE.
+#   define YY_(msgid) dgettext ("bison-runtime", msgid)
+#  endif
+# endif
+# ifndef YY_
+#  define YY_(msgid) msgid
+# endif
+#endif
+
+
+// Whether we are compiled with exception support.
+#ifndef YY_EXCEPTIONS
+# if defined __GNUC__ && !defined __EXCEPTIONS
+#  define YY_EXCEPTIONS 0
+# else
+#  define YY_EXCEPTIONS 1
+# endif
+#endif
+
+
+
+// Enable debugging if requested.
+#if YYDEBUG
+
+// A pseudo ostream that takes yydebug_ into account.
+# define YYCDEBUG if (yydebug_) (*yycdebug_)
+
+# define YY_SYMBOL_PRINT(Title, Symbol)         \
+  do {                                          \
+    if (yydebug_)                               \
+    {                                           \
+      *yycdebug_ << Title << ' ';               \
+      yy_print_ (*yycdebug_, Symbol);           \
+      *yycdebug_ << '\n';                       \
+    }                                           \
+  } while (false)
+
+# define YY_REDUCE_PRINT(Rule)          \
+  do {                                  \
+    if (yydebug_)                       \
+      yy_reduce_print_ (Rule);          \
+  } while (false)
+
+# define YY_STACK_PRINT()               \
+  do {                                  \
+    if (yydebug_)                       \
+      yy_stack_print_ ();                \
+  } while (false)
+
+#else // !YYDEBUG
+
+# define YYCDEBUG if (false) std::cerr
+# define YY_SYMBOL_PRINT(Title, Symbol)  YY_USE (Symbol)
+# define YY_REDUCE_PRINT(Rule)           static_cast<void> (0)
+# define YY_STACK_PRINT()                static_cast<void> (0)
+
+#endif // !YYDEBUG
+
+#define yyerrok         (yyerrstatus_ = 0)
+#define yyclearin       (yyla.clear ())
+
+#define YYACCEPT        goto yyacceptlab
+#define YYABORT         goto yyabortlab
+#define YYERROR         goto yyerrorlab
+#define YYRECOVERING()  (!!yyerrstatus_)
+
+#line 50 "QLParser.yy"
+namespace QL {
+#line 135 "QLParser.tab.cc"
+
+  /// Build a parser object.
+  Parser::Parser (QL::Result &result_yyarg)
+#if YYDEBUG
+    : yydebug_ (false),
+      yycdebug_ (&std::cerr),
+#else
+    :
+#endif
+      result (result_yyarg)
+  {}
+
+  Parser::~Parser ()
+  {}
+
+  Parser::syntax_error::~syntax_error () YY_NOEXCEPT YY_NOTHROW
+  {}
+
+  /*---------------.
+  | symbol kinds.  |
+  `---------------*/
+
+
+
+  // by_state.
+  Parser::by_state::by_state () YY_NOEXCEPT
+    : state (empty_state)
+  {}
+
+  Parser::by_state::by_state (const by_state& that) YY_NOEXCEPT
+    : state (that.state)
+  {}
+
+  void
+  Parser::by_state::clear () YY_NOEXCEPT
+  {
+    state = empty_state;
+  }
+
+  void
+  Parser::by_state::move (by_state& that)
+  {
+    state = that.state;
+    that.clear ();
+  }
+
+  Parser::by_state::by_state (state_type s) YY_NOEXCEPT
+    : state (s)
+  {}
+
+  Parser::symbol_kind_type
+  Parser::by_state::kind () const YY_NOEXCEPT
+  {
+    if (state == empty_state)
+      return symbol_kind::S_YYEMPTY;
+    else
+      return YY_CAST (symbol_kind_type, yystos_[+state]);
+  }
+
+  Parser::stack_symbol_type::stack_symbol_type ()
+  {}
+
+  Parser::stack_symbol_type::stack_symbol_type (YY_RVREF (stack_symbol_type) that)
+    : super_type (YY_MOVE (that.state))
+  {
+    switch (that.kind ())
+    {
+      case symbol_kind::S_NUM: // "number"
+      case symbol_kind::S_NAME: // "name"
+      case symbol_kind::S_FNAME: // FNAME
+      case symbol_kind::S_JGROUP: // JGROUP
+      case symbol_kind::S_JPARENT: // JPARENT
+      case symbol_kind::S_QSTR: // QSTR
+      case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+      case symbol_kind::S_exp: // exp
+      case symbol_kind::S_term: // term
+        value.YY_MOVE_OR_COPY< Expression * > (YY_MOVE (that.value));
+        break;
+
+      default:
+        break;
+    }
+
+#if 201103L <= YY_CPLUSPLUS
+    // that is emptied.
+    that.state = empty_state;
+#endif
+  }
+
+  Parser::stack_symbol_type::stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) that)
+    : super_type (s)
+  {
+    switch (that.kind ())
+    {
+      case symbol_kind::S_NUM: // "number"
+      case symbol_kind::S_NAME: // "name"
+      case symbol_kind::S_FNAME: // FNAME
+      case symbol_kind::S_JGROUP: // JGROUP
+      case symbol_kind::S_JPARENT: // JPARENT
+      case symbol_kind::S_QSTR: // QSTR
+      case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+      case symbol_kind::S_exp: // exp
+      case symbol_kind::S_term: // term
+        value.move< Expression * > (YY_MOVE (that.value));
+        break;
+
+      default:
+        break;
+    }
+
+    // that is emptied.
+    that.kind_ = symbol_kind::S_YYEMPTY;
+  }
+
+#if YY_CPLUSPLUS < 201103L
+  Parser::stack_symbol_type&
+  Parser::stack_symbol_type::operator= (const stack_symbol_type& that)
+  {
+    state = that.state;
+    switch (that.kind ())
+    {
+      case symbol_kind::S_NUM: // "number"
+      case symbol_kind::S_NAME: // "name"
+      case symbol_kind::S_FNAME: // FNAME
+      case symbol_kind::S_JGROUP: // JGROUP
+      case symbol_kind::S_JPARENT: // JPARENT
+      case symbol_kind::S_QSTR: // QSTR
+      case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+      case symbol_kind::S_exp: // exp
+      case symbol_kind::S_term: // term
+        value.copy< Expression * > (that.value);
+        break;
+
+      default:
+        break;
+    }
+
+    return *this;
+  }
+
+  Parser::stack_symbol_type&
+  Parser::stack_symbol_type::operator= (stack_symbol_type& that)
+  {
+    state = that.state;
+    switch (that.kind ())
+    {
+      case symbol_kind::S_NUM: // "number"
+      case symbol_kind::S_NAME: // "name"
+      case symbol_kind::S_FNAME: // FNAME
+      case symbol_kind::S_JGROUP: // JGROUP
+      case symbol_kind::S_JPARENT: // JPARENT
+      case symbol_kind::S_QSTR: // QSTR
+      case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+      case symbol_kind::S_exp: // exp
+      case symbol_kind::S_term: // term
+        value.move< Expression * > (that.value);
+        break;
+
+      default:
+        break;
+    }
+
+    // that is emptied.
+    that.state = empty_state;
+    return *this;
+  }
+#endif
+
+  template <typename Base>
+  void
+  Parser::yy_destroy_ (const char* yymsg, basic_symbol<Base>& yysym) const
+  {
+    if (yymsg)
+      YY_SYMBOL_PRINT (yymsg, yysym);
+  }
+
+#if YYDEBUG
+  template <typename Base>
+  void
+  Parser::yy_print_ (std::ostream& yyo, const basic_symbol<Base>& yysym) const
+  {
+    std::ostream& yyoutput = yyo;
+    YY_USE (yyoutput);
+    if (yysym.empty ())
+      yyo << "empty symbol";
+    else
+      {
+        symbol_kind_type yykind = yysym.kind ();
+        yyo << (yykind < YYNTOKENS ? "token" : "nterm")
+            << ' ' << yysym.name () << " (";
+        YY_USE (yykind);
+        yyo << ')';
+      }
+  }
+#endif
+
+  void
+  Parser::yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym)
+  {
+    if (m)
+      YY_SYMBOL_PRINT (m, sym);
+    yystack_.push (YY_MOVE (sym));
+  }
+
+  void
+  Parser::yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym)
+  {
+#if 201103L <= YY_CPLUSPLUS
+    yypush_ (m, stack_symbol_type (s, std::move (sym)));
+#else
+    stack_symbol_type ss (s, sym);
+    yypush_ (m, ss);
+#endif
+  }
+
+  void
+  Parser::yypop_ (int n)
+  {
+    yystack_.pop (n);
+  }
+
+#if YYDEBUG
+  std::ostream&
+  Parser::debug_stream () const
+  {
+    return *yycdebug_;
+  }
+
+  void
+  Parser::set_debug_stream (std::ostream& o)
+  {
+    yycdebug_ = &o;
+  }
+
+
+  Parser::debug_level_type
+  Parser::debug_level () const
+  {
+    return yydebug_;
+  }
+
+  void
+  Parser::set_debug_level (debug_level_type l)
+  {
+    yydebug_ = l;
+  }
+#endif // YYDEBUG
+
+  Parser::state_type
+  Parser::yy_lr_goto_state_ (state_type yystate, int yysym)
+  {
+    int yyr = yypgoto_[yysym - YYNTOKENS] + yystate;
+    if (0 <= yyr && yyr <= yylast_ && yycheck_[yyr] == yystate)
+      return yytable_[yyr];
+    else
+      return yydefgoto_[yysym - YYNTOKENS];
+  }
+
+  bool
+  Parser::yy_pact_value_is_default_ (int yyvalue)
+  {
+    return yyvalue == yypact_ninf_;
+  }
+
+  bool
+  Parser::yy_table_value_is_error_ (int yyvalue)
+  {
+    return yyvalue == yytable_ninf_;
+  }
+
+  int
+  Parser::operator() ()
+  {
+    return parse ();
+  }
+
+  int
+  Parser::parse ()
+  {
+    int yyn;
+    /// Length of the RHS of the rule being reduced.
+    int yylen = 0;
+
+    // Error handling.
+    int yynerrs_ = 0;
+    int yyerrstatus_ = 0;
+
+    /// The lookahead symbol.
+    symbol_type yyla;
+
+    /// The return value of parse ().
+    int yyresult;
+
+#if YY_EXCEPTIONS
+    try
+#endif // YY_EXCEPTIONS
+      {
+    YYCDEBUG << "Starting parse\n";
+
+
+    /* Initialize the stack.  The initial state will be set in
+       yynewstate, since the latter expects the semantical and the
+       location values to have been already stored, initialize these
+       stacks with a primary value.  */
+    yystack_.clear ();
+    yypush_ (YY_NULLPTR, 0, YY_MOVE (yyla));
+
+  /*-----------------------------------------------.
+  | yynewstate -- push a new symbol on the stack.  |
+  `-----------------------------------------------*/
+  yynewstate:
+    YYCDEBUG << "Entering state " << int (yystack_[0].state) << '\n';
+    YY_STACK_PRINT ();
+
+    // Accept?
+    if (yystack_[0].state == yyfinal_)
+      YYACCEPT;
+
+    goto yybackup;
+
+
+  /*-----------.
+  | yybackup.  |
+  `-----------*/
+  yybackup:
+    // Try to take a decision without lookahead.
+    yyn = yypact_[+yystack_[0].state];
+    if (yy_pact_value_is_default_ (yyn))
+      goto yydefault;
+
+    // Read a lookahead token.
+    if (yyla.empty ())
+      {
+        YYCDEBUG << "Reading a token\n";
+#if YY_EXCEPTIONS
+        try
+#endif // YY_EXCEPTIONS
+          {
+            symbol_type yylookahead (yylex (result));
+            yyla.move (yylookahead);
+          }
+#if YY_EXCEPTIONS
+        catch (const syntax_error& yyexc)
+          {
+            YYCDEBUG << "Caught exception: " << yyexc.what() << '\n';
+            error (yyexc);
+            goto yyerrlab1;
+          }
+#endif // YY_EXCEPTIONS
+      }
+    YY_SYMBOL_PRINT ("Next token is", yyla);
+
+    if (yyla.kind () == symbol_kind::S_YYerror)
+    {
+      // The scanner already issued an error message, process directly
+      // to error recovery.  But do not keep the error token as
+      // lookahead, it is too special and may lead us to an endless
+      // loop in error recovery. */
+      yyla.kind_ = symbol_kind::S_YYUNDEF;
+      goto yyerrlab1;
+    }
+
+    /* If the proper action on seeing token YYLA.TYPE is to reduce or
+       to detect an error, take that action.  */
+    yyn += yyla.kind ();
+    if (yyn < 0 || yylast_ < yyn || yycheck_[yyn] != yyla.kind ())
+      {
+        goto yydefault;
+      }
+
+    // Reduce or error.
+    yyn = yytable_[yyn];
+    if (yyn <= 0)
+      {
+        if (yy_table_value_is_error_ (yyn))
+          goto yyerrlab;
+        yyn = -yyn;
+        goto yyreduce;
+      }
+
+    // Count tokens shifted since error; after three, turn off error status.
+    if (yyerrstatus_)
+      --yyerrstatus_;
+
+    // Shift the lookahead token.
+    yypush_ ("Shifting", state_type (yyn), YY_MOVE (yyla));
+    goto yynewstate;
+
+
+  /*-----------------------------------------------------------.
+  | yydefault -- do the default action for the current state.  |
+  `-----------------------------------------------------------*/
+  yydefault:
+    yyn = yydefact_[+yystack_[0].state];
+    if (yyn == 0)
+      goto yyerrlab;
+    goto yyreduce;
+
+
+  /*-----------------------------.
+  | yyreduce -- do a reduction.  |
+  `-----------------------------*/
+  yyreduce:
+    yylen = yyr2_[yyn];
+    {
+      stack_symbol_type yylhs;
+      yylhs.state = yy_lr_goto_state_ (yystack_[yylen].state, yyr1_[yyn]);
+      /* Variants are always initialized to an empty instance of the
+         correct type. The default '$$ = $1' action is NOT applied
+         when using variants.  */
+      switch (yyr1_[yyn])
+    {
+      case symbol_kind::S_NUM: // "number"
+      case symbol_kind::S_NAME: // "name"
+      case symbol_kind::S_FNAME: // FNAME
+      case symbol_kind::S_JGROUP: // JGROUP
+      case symbol_kind::S_JPARENT: // JPARENT
+      case symbol_kind::S_QSTR: // QSTR
+      case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+      case symbol_kind::S_exp: // exp
+      case symbol_kind::S_term: // term
+        yylhs.value.emplace< Expression * > ();
+        break;
+
+      default:
+        break;
+    }
+
+
+
+      // Perform the reduction.
+      YY_REDUCE_PRINT (yyn);
+#if YY_EXCEPTIONS
+      try
+#endif // YY_EXCEPTIONS
+        {
+          switch (yyn)
+            {
+  case 2: // S: %empty
+#line 104 "QLParser.yy"
+                                { result.out = new Expression (Expression::OP_NUM, (uint64_t) 1); }
+#line 577 "QLParser.tab.cc"
+    break;
+
+  case 3: // S: exp
+#line 105 "QLParser.yy"
+                                { result.out = new Expression (yystack_[0].value.as < Expression * > ()); }
+#line 583 "QLParser.tab.cc"
+    break;
+
+  case 4: // exp: exp DEG exp
+#line 107 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_DEG, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 589 "QLParser.tab.cc"
+    break;
+
+  case 5: // exp: exp MUL exp
+#line 108 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_MUL, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 595 "QLParser.tab.cc"
+    break;
+
+  case 6: // exp: exp DIV exp
+#line 109 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_DIV, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 601 "QLParser.tab.cc"
+    break;
+
+  case 7: // exp: exp REM exp
+#line 110 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_REM, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 607 "QLParser.tab.cc"
+    break;
+
+  case 8: // exp: exp ADD exp
+#line 111 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_ADD, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 613 "QLParser.tab.cc"
+    break;
+
+  case 9: // exp: exp MINUS exp
+#line 112 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_MINUS, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 619 "QLParser.tab.cc"
+    break;
+
+  case 10: // exp: exp LS exp
+#line 113 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_LS, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 625 "QLParser.tab.cc"
+    break;
+
+  case 11: // exp: exp RS exp
+#line 114 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_RS, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 631 "QLParser.tab.cc"
+    break;
+
+  case 12: // exp: exp LT exp
+#line 115 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_LT, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 637 "QLParser.tab.cc"
+    break;
+
+  case 13: // exp: exp LE exp
+#line 116 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_LE, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 643 "QLParser.tab.cc"
+    break;
+
+  case 14: // exp: exp GT exp
+#line 117 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_GT, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 649 "QLParser.tab.cc"
+    break;
+
+  case 15: // exp: exp GE exp
+#line 118 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_GE, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 655 "QLParser.tab.cc"
+    break;
+
+  case 16: // exp: exp EQ exp
+#line 119 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_EQ, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 661 "QLParser.tab.cc"
+    break;
+
+  case 17: // exp: exp NE exp
+#line 120 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_NE, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 667 "QLParser.tab.cc"
+    break;
+
+  case 18: // exp: exp BITAND exp
+#line 121 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_BITAND, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 673 "QLParser.tab.cc"
+    break;
+
+  case 19: // exp: exp BITXOR exp
+#line 122 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_BITXOR, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 679 "QLParser.tab.cc"
+    break;
+
+  case 20: // exp: exp BITOR exp
+#line 123 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_BITOR, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 685 "QLParser.tab.cc"
+    break;
+
+  case 21: // exp: exp AND exp
+#line 124 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_AND, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 691 "QLParser.tab.cc"
+    break;
+
+  case 22: // exp: exp OR exp
+#line 125 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_OR, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 697 "QLParser.tab.cc"
+    break;
+
+  case 23: // exp: exp NEQV exp
+#line 126 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_NEQV, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 703 "QLParser.tab.cc"
+    break;
+
+  case 24: // exp: exp EQV exp
+#line 127 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_EQV, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 709 "QLParser.tab.cc"
+    break;
+
+  case 25: // exp: exp QWE exp COLON exp
+#line 128 "QLParser.yy"
+                                { Expression colon = Expression (Expression::OP_COLON, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ());
+                                 yylhs.value.as < Expression * > () = new Expression (Expression::OP_QWE, yystack_[4].value.as < Expression * > (), &colon); }
+#line 716 "QLParser.tab.cc"
+    break;
+
+  case 26: // exp: exp COMMA exp
+#line 130 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_COMMA, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 722 "QLParser.tab.cc"
+    break;
+
+  case 27: // exp: exp IN exp
+#line 131 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_IN, yystack_[2].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 728 "QLParser.tab.cc"
+    break;
+
+  case 28: // exp: exp SOME IN exp
+#line 132 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_SOMEIN, yystack_[3].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 734 "QLParser.tab.cc"
+    break;
+
+  case 29: // exp: exp ORDR IN exp
+#line 133 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_ORDRIN, yystack_[3].value.as < Expression * > (), yystack_[0].value.as < Expression * > ()); }
+#line 740 "QLParser.tab.cc"
+    break;
+
+  case 30: // exp: term
+#line 134 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (yystack_[0].value.as < Expression * > ()); }
+#line 746 "QLParser.tab.cc"
+    break;
+
+  case 31: // term: MINUS term
+#line 136 "QLParser.yy"
+                                { Expression num = Expression (Expression::OP_NUM, (uint64_t) 0);
+                                 yylhs.value.as < Expression * > () = new Expression (Expression::OP_MINUS, &num, yystack_[0].value.as < Expression * > ()); }
+#line 753 "QLParser.tab.cc"
+    break;
+
+  case 32: // term: NOT term
+#line 138 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_NOT, yystack_[0].value.as < Expression * > (), NULL); }
+#line 759 "QLParser.tab.cc"
+    break;
+
+  case 33: // term: BITNOT term
+#line 139 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_BITNOT, yystack_[0].value.as < Expression * > (), NULL); }
+#line 765 "QLParser.tab.cc"
+    break;
+
+  case 34: // term: "(" exp ")"
+#line 140 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (yystack_[1].value.as < Expression * > ()); }
+#line 771 "QLParser.tab.cc"
+    break;
+
+  case 35: // term: FNAME "(" QSTR ")"
+#line 141 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_FUNC, yystack_[3].value.as < Expression * > (), yystack_[1].value.as < Expression * > ()); }
+#line 777 "QLParser.tab.cc"
+    break;
+
+  case 36: // term: HASPROP "(" "name" ")"
+#line 142 "QLParser.yy"
+                                 { yylhs.value.as < Expression * > () = new Expression (Expression::OP_HASPROP, yystack_[1].value.as < Expression * > (), NULL); }
+#line 783 "QLParser.tab.cc"
+    break;
+
+  case 37: // term: JGROUP "(" QSTR ")"
+#line 143 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (Expression::OP_JAVA, yystack_[3].value.as < Expression * > (), yystack_[1].value.as < Expression * > ()); }
+#line 789 "QLParser.tab.cc"
+    break;
+
+  case 38: // term: JPARENT "(" QSTR ")"
+#line 144 "QLParser.yy"
+                                 { yylhs.value.as < Expression * > () = new Expression (Expression::OP_JAVA, yystack_[3].value.as < Expression * > (), yystack_[1].value.as < Expression * > ()); }
+#line 795 "QLParser.tab.cc"
+    break;
+
+  case 39: // term: FILEIOVFD "(" QSTR ")"
+#line 145 "QLParser.yy"
+                                   { yylhs.value.as < Expression * > () = new Expression (Expression::OP_FILE, yystack_[3].value.as < Expression * > (), yystack_[1].value.as < Expression * > ()); }
+#line 801 "QLParser.tab.cc"
+    break;
+
+  case 40: // term: "number"
+#line 146 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (yystack_[0].value.as < Expression * > ()); }
+#line 807 "QLParser.tab.cc"
+    break;
+
+  case 41: // term: "name"
+#line 147 "QLParser.yy"
+                                { yylhs.value.as < Expression * > () = new Expression (yystack_[0].value.as < Expression * > ()); }
+#line 813 "QLParser.tab.cc"
+    break;
+
+
+#line 817 "QLParser.tab.cc"
+
+            default:
+              break;
+            }
+        }
+#if YY_EXCEPTIONS
+      catch (const syntax_error& yyexc)
+        {
+          YYCDEBUG << "Caught exception: " << yyexc.what() << '\n';
+          error (yyexc);
+          YYERROR;
+        }
+#endif // YY_EXCEPTIONS
+      YY_SYMBOL_PRINT ("-> $$ =", yylhs);
+      yypop_ (yylen);
+      yylen = 0;
+
+      // Shift the result of the reduction.
+      yypush_ (YY_NULLPTR, YY_MOVE (yylhs));
+    }
+    goto yynewstate;
+
+
+  /*--------------------------------------.
+  | yyerrlab -- here on detecting error.  |
+  `--------------------------------------*/
+  yyerrlab:
+    // If not already recovering from an error, report this error.
+    if (!yyerrstatus_)
+      {
+        ++yynerrs_;
+        std::string msg = YY_("syntax error");
+        error (YY_MOVE (msg));
+      }
+
+
+    if (yyerrstatus_ == 3)
+      {
+        /* If just tried and failed to reuse lookahead token after an
+           error, discard it.  */
+
+        // Return failure if at end of input.
+        if (yyla.kind () == symbol_kind::S_YYEOF)
+          YYABORT;
+        else if (!yyla.empty ())
+          {
+            yy_destroy_ ("Error: discarding", yyla);
+            yyla.clear ();
+          }
+      }
+
+    // Else will try to reuse lookahead token after shifting the error token.
+    goto yyerrlab1;
+
+
+  /*---------------------------------------------------.
+  | yyerrorlab -- error raised explicitly by YYERROR.  |
+  `---------------------------------------------------*/
+  yyerrorlab:
+    /* Pacify compilers when the user code never invokes YYERROR and
+       the label yyerrorlab therefore never appears in user code.  */
+    if (false)
+      YYERROR;
+
+    /* Do not reclaim the symbols of the rule whose action triggered
+       this YYERROR.  */
+    yypop_ (yylen);
+    yylen = 0;
+    YY_STACK_PRINT ();
+    goto yyerrlab1;
+
+
+  /*-------------------------------------------------------------.
+  | yyerrlab1 -- common code for both syntax error and YYERROR.  |
+  `-------------------------------------------------------------*/
+  yyerrlab1:
+    yyerrstatus_ = 3;   // Each real token shifted decrements this.
+    // Pop stack until we find a state that shifts the error token.
+    for (;;)
+      {
+        yyn = yypact_[+yystack_[0].state];
+        if (!yy_pact_value_is_default_ (yyn))
+          {
+            yyn += symbol_kind::S_YYerror;
+            if (0 <= yyn && yyn <= yylast_
+                && yycheck_[yyn] == symbol_kind::S_YYerror)
+              {
+                yyn = yytable_[yyn];
+                if (0 < yyn)
+                  break;
+              }
+          }
+
+        // Pop the current state because it cannot handle the error token.
+        if (yystack_.size () == 1)
+          YYABORT;
+
+        yy_destroy_ ("Error: popping", yystack_[0]);
+        yypop_ ();
+        YY_STACK_PRINT ();
+      }
+    {
+      stack_symbol_type error_token;
+
+
+      // Shift the error token.
+      error_token.state = state_type (yyn);
+      yypush_ ("Shifting", YY_MOVE (error_token));
+    }
+    goto yynewstate;
+
+
+  /*-------------------------------------.
+  | yyacceptlab -- YYACCEPT comes here.  |
+  `-------------------------------------*/
+  yyacceptlab:
+    yyresult = 0;
+    goto yyreturn;
+
+
+  /*-----------------------------------.
+  | yyabortlab -- YYABORT comes here.  |
+  `-----------------------------------*/
+  yyabortlab:
+    yyresult = 1;
+    goto yyreturn;
+
+
+  /*-----------------------------------------------------.
+  | yyreturn -- parsing is finished, return the result.  |
+  `-----------------------------------------------------*/
+  yyreturn:
+    if (!yyla.empty ())
+      yy_destroy_ ("Cleanup: discarding lookahead", yyla);
+
+    /* Do not reclaim the symbols of the rule whose action triggered
+       this YYABORT or YYACCEPT.  */
+    yypop_ (yylen);
+    YY_STACK_PRINT ();
+    while (1 < yystack_.size ())
+      {
+        yy_destroy_ ("Cleanup: popping", yystack_[0]);
+        yypop_ ();
+      }
+
+    return yyresult;
+  }
+#if YY_EXCEPTIONS
+    catch (...)
+      {
+        YYCDEBUG << "Exception caught: cleaning lookahead and stack\n";
+        // Do not try to display the values of the reclaimed symbols,
+        // as their printers might throw an exception.
+        if (!yyla.empty ())
+          yy_destroy_ (YY_NULLPTR, yyla);
+
+        while (1 < yystack_.size ())
+          {
+            yy_destroy_ (YY_NULLPTR, yystack_[0]);
+            yypop_ ();
+          }
+        throw;
+      }
+#endif // YY_EXCEPTIONS
+  }
+
+  void
+  Parser::error (const syntax_error& yyexc)
+  {
+    error (yyexc.what ());
+  }
+
+#if YYDEBUG || 0
+  const char *
+  Parser::symbol_name (symbol_kind_type yysymbol)
+  {
+    return yytname_[yysymbol];
+  }
+#endif // #if YYDEBUG || 0
+
+
+
+
+
+  const signed char Parser::yypact_ninf_ = -3;
+
+  const signed char Parser::yytable_ninf_ = -1;
+
+  const short
+  Parser::yypact_[] =
+  {
+       0,     0,    -3,    -3,    -2,     1,     8,    13,    14,     0,
+       0,     0,     2,   142,    -3,    50,     7,    15,     9,    11,
+      12,    -3,    -3,    -3,    -3,     0,     6,    38,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
+       0,    -3,    21,    22,    48,    49,    51,   188,     0,     0,
+     221,    96,    95,    95,    95,    95,    95,    95,    95,   141,
+     141,   141,   141,   141,   141,    17,    17,    17,    17,    17,
+      17,    17,    17,    -3,    -3,    -3,    -3,    -3,   188,   188,
+       0,   221
+  };
+
+  const signed char
+  Parser::yydefact_[] =
+  {
+       2,     0,    40,    41,     0,     0,     0,     0,     0,     0,
+       0,     0,     0,     3,    30,     0,     0,     0,     0,     0,
+       0,    31,    32,    33,     1,     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,    34,     0,     0,     0,     0,     0,    27,     0,     0,
+      26,     0,    21,    22,    24,    23,    18,    20,    19,    16,
+      17,    12,    14,    13,    15,    10,    11,     8,     9,     5,
+       6,     7,     4,    35,    36,    37,    38,    39,    28,    29,
+       0,    25
+  };
+
+  const signed char
+  Parser::yypgoto_[] =
+  {
+      -3,    -3,    -1,     4
+  };
+
+  const signed char
+  Parser::yydefgoto_[] =
+  {
+       0,    12,    13,    14
+  };
+
+  const signed char
+  Parser::yytable_[] =
+  {
+      15,    16,    24,     1,    17,     2,     3,     4,     5,     6,
+       7,    18,     8,    21,    22,    23,    19,    20,    52,    58,
+      54,    53,    55,    56,    57,    83,    84,    60,    61,    62,
+      63,    64,    65,    66,    67,    68,    69,    70,    71,    72,
+      73,    74,    75,    76,    77,    78,    79,    80,    81,    82,
+       9,    59,    85,    86,    51,    87,     0,    88,    89,    10,
+       0,    11,     0,    25,    26,    27,    28,     0,    29,     0,
+       0,     0,    30,     0,    31,    50,    32,    33,    34,    35,
+      36,     0,    37,     0,    38,     0,    39,     0,    40,    91,
+      41,     0,    42,     0,    43,     0,    44,     0,    45,     0,
+      46,     0,    47,     0,    48,     0,    49,     0,    50,    25,
+      26,    27,    28,     0,    29,     0,    90,     0,    30,     0,
+      31,     0,    32,    33,    34,    35,    36,    37,    37,    38,
+      38,    39,    39,    40,    40,    41,    41,    42,    42,    43,
+      43,    44,    44,    45,    45,    46,    46,    47,    47,    48,
+      48,    49,    49,    50,    50,    25,    26,    27,    28,     0,
+      29,     0,     0,     0,    30,     0,    31,     0,    32,    33,
+      34,    35,    36,    -1,    37,    -1,    38,    -1,    39,    -1,
+      40,    -1,    41,    -1,    42,    43,    43,    44,    44,    45,
+      45,    46,    46,    47,    47,    48,    48,    49,    49,    50,
+      50,    -1,    -1,    -1,    28,     0,    29,     0,     0,     0,
+      30,     0,    31,     0,    32,    33,    34,    35,    36,     0,
+      37,     0,    38,     0,    39,     0,    40,     0,    41,     0,
+      42,     0,    43,     0,    44,     0,    45,     0,    46,    29,
+      47,     0,    48,    30,    49,    31,    50,    32,    33,    34,
+      35,    36,     0,    37,     0,    38,     0,    39,     0,    40,
+       0,    41,     0,    42,     0,    43,     0,    44,     0,    45,
+       0,    46,     0,    47,     0,    48,     0,    49,     0,    50
+  };
+
+  const signed char
+  Parser::yycheck_[] =
+  {
+       1,     3,     0,     3,     3,     5,     6,     7,     8,     9,
+      10,     3,    12,     9,    10,    11,     3,     3,    11,    13,
+      11,     6,    11,    11,    25,     4,     4,    28,    29,    30,
+      31,    32,    33,    34,    35,    36,    37,    38,    39,    40,
+      41,    42,    43,    44,    45,    46,    47,    48,    49,    50,
+      50,    13,     4,     4,     4,     4,    -1,    58,    59,    59,
+      -1,    61,    -1,    13,    14,    15,    16,    -1,    18,    -1,
+      -1,    -1,    22,    -1,    24,    58,    26,    27,    28,    29,
+      30,    -1,    32,    -1,    34,    -1,    36,    -1,    38,    90,
+      40,    -1,    42,    -1,    44,    -1,    46,    -1,    48,    -1,
+      50,    -1,    52,    -1,    54,    -1,    56,    -1,    58,    13,
+      14,    15,    16,    -1,    18,    -1,    20,    -1,    22,    -1,
+      24,    -1,    26,    27,    28,    29,    30,    32,    32,    34,
+      34,    36,    36,    38,    38,    40,    40,    42,    42,    44,
+      44,    46,    46,    48,    48,    50,    50,    52,    52,    54,
+      54,    56,    56,    58,    58,    13,    14,    15,    16,    -1,
+      18,    -1,    -1,    -1,    22,    -1,    24,    -1,    26,    27,
+      28,    29,    30,    32,    32,    34,    34,    36,    36,    38,
+      38,    40,    40,    42,    42,    44,    44,    46,    46,    48,
+      48,    50,    50,    52,    52,    54,    54,    56,    56,    58,
+      58,    13,    14,    15,    16,    -1,    18,    -1,    -1,    -1,
+      22,    -1,    24,    -1,    26,    27,    28,    29,    30,    -1,
+      32,    -1,    34,    -1,    36,    -1,    38,    -1,    40,    -1,
+      42,    -1,    44,    -1,    46,    -1,    48,    -1,    50,    18,
+      52,    -1,    54,    22,    56,    24,    58,    26,    27,    28,
+      29,    30,    -1,    32,    -1,    34,    -1,    36,    -1,    38,
+      -1,    40,    -1,    42,    -1,    44,    -1,    46,    -1,    48,
+      -1,    50,    -1,    52,    -1,    54,    -1,    56,    -1,    58
+  };
+
+  const signed char
+  Parser::yystos_[] =
+  {
+       0,     3,     5,     6,     7,     8,     9,    10,    12,    50,
+      59,    61,    64,    65,    66,    65,     3,     3,     3,     3,
+       3,    66,    66,    66,     0,    13,    14,    15,    16,    18,
+      22,    24,    26,    27,    28,    29,    30,    32,    34,    36,
+      38,    40,    42,    44,    46,    48,    50,    52,    54,    56,
+      58,     4,    11,     6,    11,    11,    11,    65,    13,    13,
+      65,    65,    65,    65,    65,    65,    65,    65,    65,    65,
+      65,    65,    65,    65,    65,    65,    65,    65,    65,    65,
+      65,    65,    65,     4,     4,     4,     4,     4,    65,    65,
+      20,    65
+  };
+
+  const signed char
+  Parser::yyr1_[] =
+  {
+       0,    63,    64,    64,    65,    65,    65,    65,    65,    65,
+      65,    65,    65,    65,    65,    65,    65,    65,    65,    65,
+      65,    65,    65,    65,    65,    65,    65,    65,    65,    65,
+      65,    66,    66,    66,    66,    66,    66,    66,    66,    66,
+      66,    66
+  };
+
+  const signed char
+  Parser::yyr2_[] =
+  {
+       0,     2,     0,     1,     3,     3,     3,     3,     3,     3,
+       3,     3,     3,     3,     3,     3,     3,     3,     3,     3,
+       3,     3,     3,     3,     3,     5,     3,     3,     4,     4,
+       1,     2,     2,     2,     3,     4,     4,     4,     4,     4,
+       1,     1
+  };
+
+
+#if YYDEBUG
+  // YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+  // First, the terminals, then, starting at \a YYNTOKENS, nonterminals.
+  const char*
+  const Parser::yytname_[] =
+  {
+  "\"end of file\"", "error", "\"invalid token\"", "\"(\"", "\")\"",
+  "\"number\"", "\"name\"", "FNAME", "HASPROP", "JGROUP", "JPARENT",
+  "QSTR", "FILEIOVFD", "IN", "SOME", "ORDR", "COMMA", "\",\"", "QWE",
+  "\"?\"", "COLON", "\":\"", "AND", "\"&&\"", "OR", "\"|\"", "EQV", "NEQV",
+  "BITAND", "BITOR", "BITXOR", "\"^\"", "EQ", "\"=\"", "NE", "\"!=\"",
+  "LT", "\"<\"", "GT", "\">\"", "LE", "\"<=\"", "GE", "\">=\"", "LS",
+  "\"<<\"", "RS", "\">>\"", "ADD", "\"+\"", "MINUS", "\"-\"", "MUL",
+  "\"*\"", "DIV", "\"/\"", "REM", "\"%\"", "DEG", "NOT", "\"!\"", "BITNOT",
+  "\"~\"", "$accept", "S", "exp", "term", YY_NULLPTR
+  };
+#endif
+
+
+#if YYDEBUG
+  const unsigned char
+  Parser::yyrline_[] =
+  {
+       0,   104,   104,   105,   107,   108,   109,   110,   111,   112,
+     113,   114,   115,   116,   117,   118,   119,   120,   121,   122,
+     123,   124,   125,   126,   127,   128,   130,   131,   132,   133,
+     134,   136,   138,   139,   140,   141,   142,   143,   144,   145,
+     146,   147
+  };
+
+  void
+  Parser::yy_stack_print_ () const
+  {
+    *yycdebug_ << "Stack now";
+    for (stack_type::const_iterator
+           i = yystack_.begin (),
+           i_end = yystack_.end ();
+         i != i_end; ++i)
+      *yycdebug_ << ' ' << int (i->state);
+    *yycdebug_ << '\n';
+  }
+
+  void
+  Parser::yy_reduce_print_ (int yyrule) const
+  {
+    int yylno = yyrline_[yyrule];
+    int yynrhs = yyr2_[yyrule];
+    // Print the symbols being reduced, and their result.
+    *yycdebug_ << "Reducing stack by rule " << yyrule - 1
+               << " (line " << yylno << "):\n";
+    // The symbols being reduced.
+    for (int yyi = 0; yyi < yynrhs; yyi++)
+      YY_SYMBOL_PRINT ("   $" << yyi + 1 << " =",
+                       yystack_[(yynrhs) - (yyi + 1)]);
+  }
+#endif // YYDEBUG
+
+
+#line 50 "QLParser.yy"
+} // QL
+#line 1210 "QLParser.tab.cc"
+
+#line 149 "QLParser.yy"
+
+
+namespace QL
+{
+  static Parser::symbol_type
+  unget_ret (std::istream &in, char c, Parser::symbol_type tok)
+  {
+    in.putback (c);
+    return tok;
+  }
+
+  static Expression *
+  processName (char *name)
+  {
+    int propID = dbeSession->getPropIdByName (name);
+    if (propID != PROP_NONE)
+      {
+       Expression *expr = new Expression (Expression::OP_NUM, (uint64_t) propID);
+       Expression *ret = new Expression (Expression::OP_NAME, expr);
+       delete expr;
+       return ret;
+      }
+
+    // If a name is not statically known try user defined objects
+    Expression *expr = dbeSession->findObjDefByName (name);
+    if (expr != NULL)
+      return expr->copy();
+
+    throw Parser::syntax_error ("Name not found");
+  }
+
+  static Parser::symbol_type
+  yylex (QL::Result &result)
+  {
+    int base = 0;
+    int c;
+
+    do
+      c = result.in.get ();
+    while (result.in && (c == ' ' || c == '\t'));
+    if (!result.in)
+      return Parser::make_YYEOF ();
+
+    switch (c)
+      {
+      case '\n': return Parser::make_YYEOF ();
+      case '(': return Parser::make_LPAR () ;
+      case ')': return Parser::make_RPAR ();
+      case ',': return Parser::make_COMMA ();
+      case '%': return Parser::make_REM ();
+      case '/': return Parser::make_DIV ();
+      case '*': return Parser::make_MUL ();
+      case '-': return Parser::make_MINUS ();
+      case '+': return Parser::make_ADD ();
+      case '~': return Parser::make_BITNOT ();
+      case '^': return Parser::make_BITXOR ();
+      case '?': return Parser::make_QWE ();
+      case ':': return Parser::make_COLON ();
+      case '|':
+       c = result.in.get ();
+       if (c == '|')
+         return Parser::make_OR ();
+       else
+         return unget_ret (result.in, c, Parser::make_BITOR ());
+      case '&':
+       c = result.in.get ();
+       if (c == '&')
+         return Parser::make_AND ();
+       else
+         return unget_ret (result.in, c, Parser::make_BITAND ());
+      case '!':
+       c = result.in.get ();
+       if (c == '=')
+         return Parser::make_NE ();
+       else
+         return unget_ret (result.in, c, Parser::make_NOT ());
+      case '=':
+       c = result.in.get ();
+       if (c == '=')
+         return Parser::make_EQ ();
+       else
+         throw Parser::syntax_error ("Syntax error after =");
+      case '<':
+       c = result.in.get ();
+       if (c == '=')
+         return Parser::make_LE ();
+       else if (c == '<')
+         return Parser::make_LS ();
+       else
+         return unget_ret (result.in, c, Parser::make_LT ());
+      case '>':
+       c = result.in.get ();
+       if (c == '=')
+         return Parser::make_GE ();
+       else if (c == '>')
+         return Parser::make_RS ();
+       else
+         return unget_ret (result.in, c, Parser::make_GT ());
+      case '"':
+       {
+         int  maxsz = 16;
+         char *str = (char *) malloc (maxsz);
+         char *ptr = str;
+
+         for (;;)
+           {
+             c = result.in.get ();
+             if (!result.in)
+               {
+                 free (str);
+                 throw Parser::syntax_error ("Unclosed \"");
+               }
+
+             switch (c)
+               {
+               case '"':
+                 *ptr = (char)0;
+                 // XXX omazur: need new string type
+                 return Parser::make_QSTR (new Expression (Expression::OP_NUM, (uint64_t) str));
+               case 0:
+               case '\n':
+                 free (str);
+                 throw Parser::syntax_error ("Multiline strings are not supported");
+               default:
+                 if (ptr - str >= maxsz)
+                   {
+                     size_t len = ptr - str;
+                     maxsz = maxsz > 8192 ? maxsz + 8192 : maxsz * 2;
+                     char *new_s = (char *) realloc (str, maxsz);
+                     str = new_s;
+                     ptr = str + len;
+                   }
+                 *ptr++ = c;
+               }
+           }
+       }
+      default:
+       if (c == '0')
+         {
+           base = 8;
+           c = result.in.get ();
+           if ( c == 'x' )
+             {
+               base = 16;
+               c = result.in.get ();
+             }
+         }
+       else if (c >= '1' && c <='9')
+         base = 10;
+
+       if (base)
+         {
+           uint64_t lval = 0;
+           for (;;)
+             {
+               int digit = -1;
+               switch (c)
+                 {
+                 case '0': case '1': case '2': case '3':
+                 case '4': case '5': case '6': case '7':
+                   digit = c - '0';
+                   break;
+                 case '8': case '9':
+                   if (base > 8)
+                     digit = c - '0';
+                   break;
+                 case 'a': case 'b': case 'c':
+                 case 'd': case 'e': case 'f':
+                   if (base == 16)
+                     digit = c - 'a' + 10;
+                   break;
+                 case 'A': case 'B': case 'C':
+                 case 'D': case 'E': case 'F':
+                   if (base == 16)
+                     digit = c - 'A' + 10;
+                   break;
+                 }
+               if  (digit == -1)
+                 {
+                   result.in.putback (c);
+                   break;
+                 }
+               lval = lval * base + digit;
+               c = result.in.get ();
+             }
+           return Parser::make_NUM (new Expression (Expression::OP_NUM, lval));
+         }
+
+       if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
+         {
+           char name[32];      // omazur XXX: accept any length
+           name[0] = (char)c;
+           for (size_t i = 1; i < sizeof (name); i++)
+             {
+               c = result.in.get ();
+               if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
+                   (c >= '0' && c <= '9') || (c == '_'))
+                 name[i] = c;
+               else
+                 {
+                   name[i] = (char)0;
+                   result.in.putback (c);
+                   break;
+                 }
+             }
+
+           if (strcasecmp (name, NTXT ("IN")) == 0)
+             return Parser::make_IN ();
+           else if (strcasecmp (name, NTXT ("SOME")) == 0)
+             return Parser::make_SOME ();
+           else if (strcasecmp (name, NTXT ("ORDERED")) == 0)
+             return Parser::make_ORDR ();
+           else if (strcasecmp (name, NTXT ("TRUE")) == 0)
+             return Parser::make_NUM (new Expression (Expression::OP_NUM, (uint64_t) 1));
+           else if (strcasecmp (name, NTXT ("FALSE")) == 0)
+             return Parser::make_NUM (new Expression (Expression::OP_NUM, (uint64_t) 0));
+           else if (strcasecmp (name, NTXT ("FNAME")) == 0)
+             return Parser::make_FNAME (new Expression (Expression::OP_NUM, Expression::FUNC_FNAME));
+           else if (strcasecmp (name, NTXT ("HAS_PROP")) == 0)
+             return Parser::make_HASPROP ();
+           else if (strcasecmp (name, NTXT ("JGROUP")) == 0)
+             return Parser::make_JGROUP (new Expression (Expression::OP_NUM, Expression::JAVA_JGROUP));
+           else if (strcasecmp (name, NTXT ("JPARENT")) == 0 )
+             return Parser::make_JPARENT (new Expression (Expression::OP_NUM, Expression::JAVA_JPARENT));
+           else if (strcasecmp (name, NTXT ("DNAME")) == 0)
+             return Parser::make_FNAME (new Expression (Expression::OP_NUM, Expression::FUNC_DNAME));
+           else if (strcasecmp (name, NTXT ("FILEIOVFD")) == 0 )
+             return Parser::make_FILEIOVFD (new Expression (Expression::OP_NUM, (uint64_t) 0));
+
+           return Parser::make_NAME (processName (name));
+         }
+
+       throw Parser::syntax_error ("Syntax error");
+      }
+  }
+  void
+  Parser::error (const std::string &)
+  {
+    // do nothing for now
+  }
+}
+
diff --git a/gprofng/src/QLParser.tab.hh b/gprofng/src/QLParser.tab.hh
new file mode 100644 (file)
index 0000000..eaf2cb5
--- /dev/null
@@ -0,0 +1,2038 @@
+// A Bison parser, made by GNU Bison 3.7.5.
+
+// Skeleton interface for Bison LALR(1) parsers in C++
+
+// Copyright (C) 2002-2015, 2018-2021 Free Software Foundation, Inc.
+
+// 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 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.  If not, see <http://www.gnu.org/licenses/>.
+
+// As a special exception, you may create a larger work that contains
+// part or all of the Bison parser skeleton and distribute that work
+// under terms of your choice, so long as that work isn't itself a
+// parser generator using the skeleton or a modified version thereof
+// as a parser skeleton.  Alternatively, if you modify or redistribute
+// the parser skeleton itself, you may (at your option) remove this
+// special exception, which will cause the skeleton and the resulting
+// Bison output files to be licensed under the GNU General Public
+// License without this special exception.
+
+// This special exception was added by the Free Software Foundation in
+// version 2.2 of Bison.
+
+
+/**
+ ** \file QLParser.tab.hh
+ ** Define the QL::parser class.
+ */
+
+// C++ LALR(1) parser skeleton written by Akim Demaille.
+
+// DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
+// especially those whose name start with YY_ or yy_.  They are
+// private implementation details that can be changed or removed.
+
+#ifndef YY_YY_QLPARSER_TAB_HH_INCLUDED
+# define YY_YY_QLPARSER_TAB_HH_INCLUDED
+// "%code requires" blocks.
+#line 33 "QLParser.yy"
+
+#include "QLParser.h"
+#include "DbeSession.h"
+#include "Expression.h"
+#include "Table.h"
+#include "i18n.h"
+
+#line 57 "QLParser.tab.hh"
+
+# include <cassert>
+# include <cstdlib> // std::abort
+# include <iostream>
+# include <stdexcept>
+# include <string>
+# include <vector>
+
+#if defined __cplusplus
+# define YY_CPLUSPLUS __cplusplus
+#else
+# define YY_CPLUSPLUS 199711L
+#endif
+
+// Support move semantics when possible.
+#if 201103L <= YY_CPLUSPLUS
+# define YY_MOVE           std::move
+# define YY_MOVE_OR_COPY   move
+# define YY_MOVE_REF(Type) Type&&
+# define YY_RVREF(Type)    Type&&
+# define YY_COPY(Type)     Type
+#else
+# define YY_MOVE
+# define YY_MOVE_OR_COPY   copy
+# define YY_MOVE_REF(Type) Type&
+# define YY_RVREF(Type)    const Type&
+# define YY_COPY(Type)     const Type&
+#endif
+
+// Support noexcept when possible.
+#if 201103L <= YY_CPLUSPLUS
+# define YY_NOEXCEPT noexcept
+# define YY_NOTHROW
+#else
+# define YY_NOEXCEPT
+# define YY_NOTHROW throw ()
+#endif
+
+// Support constexpr when possible.
+#if 201703 <= YY_CPLUSPLUS
+# define YY_CONSTEXPR constexpr
+#else
+# define YY_CONSTEXPR
+#endif
+
+#include <typeinfo>
+#ifndef YY_ASSERT
+# include <cassert>
+# define YY_ASSERT assert
+#endif
+
+
+#ifndef YY_ATTRIBUTE_PURE
+# if defined __GNUC__ && 2 < __GNUC__ + (96 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_PURE __attribute__ ((__pure__))
+# else
+#  define YY_ATTRIBUTE_PURE
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# if defined __GNUC__ && 2 < __GNUC__ + (7 <= __GNUC_MINOR__)
+#  define YY_ATTRIBUTE_UNUSED __attribute__ ((__unused__))
+# else
+#  define YY_ATTRIBUTE_UNUSED
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E.  */
+#if ! defined lint || defined __GNUC__
+# define YY_USE(E) ((void) (E))
+#else
+# define YY_USE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized.  */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN                            \
+    _Pragma ("GCC diagnostic push")                                     \
+    _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")              \
+    _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END      \
+    _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+#if defined __cplusplus && defined __GNUC__ && ! defined __ICC && 6 <= __GNUC__
+# define YY_IGNORE_USELESS_CAST_BEGIN                          \
+    _Pragma ("GCC diagnostic push")                            \
+    _Pragma ("GCC diagnostic ignored \"-Wuseless-cast\"")
+# define YY_IGNORE_USELESS_CAST_END            \
+    _Pragma ("GCC diagnostic pop")
+#endif
+#ifndef YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_BEGIN
+# define YY_IGNORE_USELESS_CAST_END
+#endif
+
+# ifndef YY_CAST
+#  ifdef __cplusplus
+#   define YY_CAST(Type, Val) static_cast<Type> (Val)
+#   define YY_REINTERPRET_CAST(Type, Val) reinterpret_cast<Type> (Val)
+#  else
+#   define YY_CAST(Type, Val) ((Type) (Val))
+#   define YY_REINTERPRET_CAST(Type, Val) ((Type) (Val))
+#  endif
+# endif
+# ifndef YY_NULLPTR
+#  if defined __cplusplus
+#   if 201103L <= __cplusplus
+#    define YY_NULLPTR nullptr
+#   else
+#    define YY_NULLPTR 0
+#   endif
+#  else
+#   define YY_NULLPTR ((void*)0)
+#  endif
+# endif
+
+/* Debug traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+
+#line 50 "QLParser.yy"
+namespace QL {
+#line 192 "QLParser.tab.hh"
+
+
+
+
+  /// A Bison parser.
+  class Parser
+  {
+  public:
+#ifndef YYSTYPE
+  /// A buffer to store and retrieve objects.
+  ///
+  /// Sort of a variant, but does not keep track of the nature
+  /// of the stored data, since that knowledge is available
+  /// via the current parser state.
+  class semantic_type
+  {
+  public:
+    /// Type of *this.
+    typedef semantic_type self_type;
+
+    /// Empty construction.
+    semantic_type () YY_NOEXCEPT
+      : yybuffer_ ()
+      , yytypeid_ (YY_NULLPTR)
+    {}
+
+    /// Construct and fill.
+    template <typename T>
+    semantic_type (YY_RVREF (T) t)
+      : yytypeid_ (&typeid (T))
+    {
+      YY_ASSERT (sizeof (T) <= size);
+      new (yyas_<T> ()) T (YY_MOVE (t));
+    }
+
+#if 201103L <= YY_CPLUSPLUS
+    /// Non copyable.
+    semantic_type (const self_type&) = delete;
+    /// Non copyable.
+    self_type& operator= (const self_type&) = delete;
+#endif
+
+    /// Destruction, allowed only if empty.
+    ~semantic_type () YY_NOEXCEPT
+    {
+      YY_ASSERT (!yytypeid_);
+    }
+
+# if 201103L <= YY_CPLUSPLUS
+    /// Instantiate a \a T in here from \a t.
+    template <typename T, typename... U>
+    T&
+    emplace (U&&... u)
+    {
+      YY_ASSERT (!yytypeid_);
+      YY_ASSERT (sizeof (T) <= size);
+      yytypeid_ = & typeid (T);
+      return *new (yyas_<T> ()) T (std::forward <U>(u)...);
+    }
+# else
+    /// Instantiate an empty \a T in here.
+    template <typename T>
+    T&
+    emplace ()
+    {
+      YY_ASSERT (!yytypeid_);
+      YY_ASSERT (sizeof (T) <= size);
+      yytypeid_ = & typeid (T);
+      return *new (yyas_<T> ()) T ();
+    }
+
+    /// Instantiate a \a T in here from \a t.
+    template <typename T>
+    T&
+    emplace (const T& t)
+    {
+      YY_ASSERT (!yytypeid_);
+      YY_ASSERT (sizeof (T) <= size);
+      yytypeid_ = & typeid (T);
+      return *new (yyas_<T> ()) T (t);
+    }
+# endif
+
+    /// Instantiate an empty \a T in here.
+    /// Obsolete, use emplace.
+    template <typename T>
+    T&
+    build ()
+    {
+      return emplace<T> ();
+    }
+
+    /// Instantiate a \a T in here from \a t.
+    /// Obsolete, use emplace.
+    template <typename T>
+    T&
+    build (const T& t)
+    {
+      return emplace<T> (t);
+    }
+
+    /// Accessor to a built \a T.
+    template <typename T>
+    T&
+    as () YY_NOEXCEPT
+    {
+      YY_ASSERT (yytypeid_);
+      YY_ASSERT (*yytypeid_ == typeid (T));
+      YY_ASSERT (sizeof (T) <= size);
+      return *yyas_<T> ();
+    }
+
+    /// Const accessor to a built \a T (for %printer).
+    template <typename T>
+    const T&
+    as () const YY_NOEXCEPT
+    {
+      YY_ASSERT (yytypeid_);
+      YY_ASSERT (*yytypeid_ == typeid (T));
+      YY_ASSERT (sizeof (T) <= size);
+      return *yyas_<T> ();
+    }
+
+    /// Swap the content with \a that, of same type.
+    ///
+    /// Both variants must be built beforehand, because swapping the actual
+    /// data requires reading it (with as()), and this is not possible on
+    /// unconstructed variants: it would require some dynamic testing, which
+    /// should not be the variant's responsibility.
+    /// Swapping between built and (possibly) non-built is done with
+    /// self_type::move ().
+    template <typename T>
+    void
+    swap (self_type& that) YY_NOEXCEPT
+    {
+      YY_ASSERT (yytypeid_);
+      YY_ASSERT (*yytypeid_ == *that.yytypeid_);
+      std::swap (as<T> (), that.as<T> ());
+    }
+
+    /// Move the content of \a that to this.
+    ///
+    /// Destroys \a that.
+    template <typename T>
+    void
+    move (self_type& that)
+    {
+# if 201103L <= YY_CPLUSPLUS
+      emplace<T> (std::move (that.as<T> ()));
+# else
+      emplace<T> ();
+      swap<T> (that);
+# endif
+      that.destroy<T> ();
+    }
+
+# if 201103L <= YY_CPLUSPLUS
+    /// Move the content of \a that to this.
+    template <typename T>
+    void
+    move (self_type&& that)
+    {
+      emplace<T> (std::move (that.as<T> ()));
+      that.destroy<T> ();
+    }
+#endif
+
+    /// Copy the content of \a that to this.
+    template <typename T>
+    void
+    copy (const self_type& that)
+    {
+      emplace<T> (that.as<T> ());
+    }
+
+    /// Destroy the stored \a T.
+    template <typename T>
+    void
+    destroy ()
+    {
+      as<T> ().~T ();
+      yytypeid_ = YY_NULLPTR;
+    }
+
+  private:
+#if YY_CPLUSPLUS < 201103L
+    /// Non copyable.
+    semantic_type (const self_type&);
+    /// Non copyable.
+    self_type& operator= (const self_type&);
+#endif
+
+    /// Accessor to raw memory as \a T.
+    template <typename T>
+    T*
+    yyas_ () YY_NOEXCEPT
+    {
+      void *yyp = yybuffer_.yyraw;
+      return static_cast<T*> (yyp);
+     }
+
+    /// Const accessor to raw memory as \a T.
+    template <typename T>
+    const T*
+    yyas_ () const YY_NOEXCEPT
+    {
+      const void *yyp = yybuffer_.yyraw;
+      return static_cast<const T*> (yyp);
+     }
+
+    /// An auxiliary type to compute the largest semantic type.
+    union union_type
+    {
+      // "number"
+      // "name"
+      // FNAME
+      // JGROUP
+      // JPARENT
+      // QSTR
+      // FILEIOVFD
+      // exp
+      // term
+      char dummy1[sizeof (Expression *)];
+    };
+
+    /// The size of the largest semantic type.
+    enum { size = sizeof (union_type) };
+
+    /// A buffer to store semantic values.
+    union
+    {
+      /// Strongest alignment constraints.
+      long double yyalign_me;
+      /// A buffer large enough to store any of the semantic values.
+      char yyraw[size];
+    } yybuffer_;
+
+    /// Whether the content is built: if defined, the name of the stored type.
+    const std::type_info *yytypeid_;
+  };
+
+#else
+    typedef YYSTYPE semantic_type;
+#endif
+
+    /// Syntax errors thrown from user actions.
+    struct syntax_error : std::runtime_error
+    {
+      syntax_error (const std::string& m)
+        : std::runtime_error (m)
+      {}
+
+      syntax_error (const syntax_error& s)
+        : std::runtime_error (s.what ())
+      {}
+
+      ~syntax_error () YY_NOEXCEPT YY_NOTHROW;
+    };
+
+    /// Token kinds.
+    struct token
+    {
+      enum token_kind_type
+      {
+        L_YYEMPTY = -2,
+    L_YYEOF = 0,                   // "end of file"
+    L_YYerror = 256,               // error
+    L_YYUNDEF = 257,               // "invalid token"
+    L_LPAR = 258,                  // "("
+    L_RPAR = 259,                  // ")"
+    L_NUM = 260,                   // "number"
+    L_NAME = 261,                  // "name"
+    L_FNAME = 262,                 // FNAME
+    L_HASPROP = 263,               // HASPROP
+    L_JGROUP = 264,                // JGROUP
+    L_JPARENT = 265,               // JPARENT
+    L_QSTR = 266,                  // QSTR
+    L_FILEIOVFD = 267,             // FILEIOVFD
+    L_IN = 268,                    // IN
+    L_SOME = 269,                  // SOME
+    L_ORDR = 270,                  // ORDR
+    L_COMMA = 271,                 // COMMA
+    L_QWE = 273,                   // QWE
+    L_COLON = 275,                 // COLON
+    L_AND = 277,                   // AND
+    L_OR = 279,                    // OR
+    L_EQV = 281,                   // EQV
+    L_NEQV = 282,                  // NEQV
+    L_BITAND = 283,                // BITAND
+    L_BITOR = 284,                 // BITOR
+    L_BITXOR = 285,                // BITXOR
+    L_EQ = 287,                    // EQ
+    L_NE = 289,                    // NE
+    L_LT = 291,                    // LT
+    L_GT = 293,                    // GT
+    L_LE = 295,                    // LE
+    L_GE = 297,                    // GE
+    L_LS = 299,                    // LS
+    L_RS = 301,                    // RS
+    L_ADD = 303,                   // ADD
+    L_MINUS = 305,                 // MINUS
+    L_MUL = 307,                   // MUL
+    L_DIV = 309,                   // DIV
+    L_REM = 311,                   // REM
+    L_DEG = 313,                   // DEG
+    L_NOT = 314,                   // NOT
+    L_BITNOT = 316                 // BITNOT
+      };
+      /// Backward compatibility alias (Bison 3.6).
+      typedef token_kind_type yytokentype;
+    };
+
+    /// Token kind, as returned by yylex.
+    typedef token::yytokentype token_kind_type;
+
+    /// Backward compatibility alias (Bison 3.6).
+    typedef token_kind_type token_type;
+
+    /// Symbol kinds.
+    struct symbol_kind
+    {
+      enum symbol_kind_type
+      {
+        YYNTOKENS = 63, ///< Number of tokens.
+        S_YYEMPTY = -2,
+        S_YYEOF = 0,                             // "end of file"
+        S_YYerror = 1,                           // error
+        S_YYUNDEF = 2,                           // "invalid token"
+        S_LPAR = 3,                              // "("
+        S_RPAR = 4,                              // ")"
+        S_NUM = 5,                               // "number"
+        S_NAME = 6,                              // "name"
+        S_FNAME = 7,                             // FNAME
+        S_HASPROP = 8,                           // HASPROP
+        S_JGROUP = 9,                            // JGROUP
+        S_JPARENT = 10,                          // JPARENT
+        S_QSTR = 11,                             // QSTR
+        S_FILEIOVFD = 12,                        // FILEIOVFD
+        S_IN = 13,                               // IN
+        S_SOME = 14,                             // SOME
+        S_ORDR = 15,                             // ORDR
+        S_COMMA = 16,                            // COMMA
+        S_17_ = 17,                              // ","
+        S_QWE = 18,                              // QWE
+        S_19_ = 19,                              // "?"
+        S_COLON = 20,                            // COLON
+        S_21_ = 21,                              // ":"
+        S_AND = 22,                              // AND
+        S_23_ = 23,                              // "&&"
+        S_OR = 24,                               // OR
+        S_25_ = 25,                              // "|"
+        S_EQV = 26,                              // EQV
+        S_NEQV = 27,                             // NEQV
+        S_BITAND = 28,                           // BITAND
+        S_BITOR = 29,                            // BITOR
+        S_BITXOR = 30,                           // BITXOR
+        S_31_ = 31,                              // "^"
+        S_EQ = 32,                               // EQ
+        S_33_ = 33,                              // "="
+        S_NE = 34,                               // NE
+        S_35_ = 35,                              // "!="
+        S_LT = 36,                               // LT
+        S_37_ = 37,                              // "<"
+        S_GT = 38,                               // GT
+        S_39_ = 39,                              // ">"
+        S_LE = 40,                               // LE
+        S_41_ = 41,                              // "<="
+        S_GE = 42,                               // GE
+        S_43_ = 43,                              // ">="
+        S_LS = 44,                               // LS
+        S_45_ = 45,                              // "<<"
+        S_RS = 46,                               // RS
+        S_47_ = 47,                              // ">>"
+        S_ADD = 48,                              // ADD
+        S_49_ = 49,                              // "+"
+        S_MINUS = 50,                            // MINUS
+        S_51_ = 51,                              // "-"
+        S_MUL = 52,                              // MUL
+        S_53_ = 53,                              // "*"
+        S_DIV = 54,                              // DIV
+        S_55_ = 55,                              // "/"
+        S_REM = 56,                              // REM
+        S_57_ = 57,                              // "%"
+        S_DEG = 58,                              // DEG
+        S_NOT = 59,                              // NOT
+        S_60_ = 60,                              // "!"
+        S_BITNOT = 61,                           // BITNOT
+        S_62_ = 62,                              // "~"
+        S_YYACCEPT = 63,                         // $accept
+        S_S = 64,                                // S
+        S_exp = 65,                              // exp
+        S_term = 66                              // term
+      };
+    };
+
+    /// (Internal) symbol kind.
+    typedef symbol_kind::symbol_kind_type symbol_kind_type;
+
+    /// The number of tokens.
+    static const symbol_kind_type YYNTOKENS = symbol_kind::YYNTOKENS;
+
+    /// A complete symbol.
+    ///
+    /// Expects its Base type to provide access to the symbol kind
+    /// via kind ().
+    ///
+    /// Provide access to semantic value.
+    template <typename Base>
+    struct basic_symbol : Base
+    {
+      /// Alias to Base.
+      typedef Base super_type;
+
+      /// Default constructor.
+      basic_symbol ()
+        : value ()
+      {}
+
+#if 201103L <= YY_CPLUSPLUS
+      /// Move constructor.
+      basic_symbol (basic_symbol&& that)
+        : Base (std::move (that))
+        , value ()
+      {
+        switch (this->kind ())
+    {
+      case symbol_kind::S_NUM: // "number"
+      case symbol_kind::S_NAME: // "name"
+      case symbol_kind::S_FNAME: // FNAME
+      case symbol_kind::S_JGROUP: // JGROUP
+      case symbol_kind::S_JPARENT: // JPARENT
+      case symbol_kind::S_QSTR: // QSTR
+      case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+      case symbol_kind::S_exp: // exp
+      case symbol_kind::S_term: // term
+        value.move< Expression * > (std::move (that.value));
+        break;
+
+      default:
+        break;
+    }
+
+      }
+#endif
+
+      /// Copy constructor.
+      basic_symbol (const basic_symbol& that);
+
+      /// Constructors for typed symbols.
+#if 201103L <= YY_CPLUSPLUS
+      basic_symbol (typename Base::kind_type t)
+        : Base (t)
+      {}
+#else
+      basic_symbol (typename Base::kind_type t)
+        : Base (t)
+      {}
+#endif
+
+#if 201103L <= YY_CPLUSPLUS
+      basic_symbol (typename Base::kind_type t, Expression *&& v)
+        : Base (t)
+        , value (std::move (v))
+      {}
+#else
+      basic_symbol (typename Base::kind_type t, const Expression *& v)
+        : Base (t)
+        , value (v)
+      {}
+#endif
+
+      /// Destroy the symbol.
+      ~basic_symbol ()
+      {
+        clear ();
+      }
+
+      /// Destroy contents, and record that is empty.
+      void clear () YY_NOEXCEPT
+      {
+        // User destructor.
+        symbol_kind_type yykind = this->kind ();
+        basic_symbol<Base>& yysym = *this;
+        (void) yysym;
+        switch (yykind)
+        {
+      case symbol_kind::S_NUM: // "number"
+#line 100 "QLParser.yy"
+                    { delete yysym.value.template as < Expression * > (); }
+#line 682 "QLParser.tab.hh"
+        break;
+
+      case symbol_kind::S_NAME: // "name"
+#line 100 "QLParser.yy"
+                    { delete yysym.value.template as < Expression * > (); }
+#line 688 "QLParser.tab.hh"
+        break;
+
+      case symbol_kind::S_FNAME: // FNAME
+#line 100 "QLParser.yy"
+                    { delete yysym.value.template as < Expression * > (); }
+#line 694 "QLParser.tab.hh"
+        break;
+
+      case symbol_kind::S_JGROUP: // JGROUP
+#line 100 "QLParser.yy"
+                    { delete yysym.value.template as < Expression * > (); }
+#line 700 "QLParser.tab.hh"
+        break;
+
+      case symbol_kind::S_JPARENT: // JPARENT
+#line 100 "QLParser.yy"
+                    { delete yysym.value.template as < Expression * > (); }
+#line 706 "QLParser.tab.hh"
+        break;
+
+      case symbol_kind::S_QSTR: // QSTR
+#line 100 "QLParser.yy"
+                    { delete yysym.value.template as < Expression * > (); }
+#line 712 "QLParser.tab.hh"
+        break;
+
+      case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+#line 100 "QLParser.yy"
+                    { delete yysym.value.template as < Expression * > (); }
+#line 718 "QLParser.tab.hh"
+        break;
+
+      case symbol_kind::S_exp: // exp
+#line 100 "QLParser.yy"
+                    { delete yysym.value.template as < Expression * > (); }
+#line 724 "QLParser.tab.hh"
+        break;
+
+      case symbol_kind::S_term: // term
+#line 100 "QLParser.yy"
+                    { delete yysym.value.template as < Expression * > (); }
+#line 730 "QLParser.tab.hh"
+        break;
+
+       default:
+          break;
+        }
+
+        // Value type destructor.
+switch (yykind)
+    {
+      case symbol_kind::S_NUM: // "number"
+      case symbol_kind::S_NAME: // "name"
+      case symbol_kind::S_FNAME: // FNAME
+      case symbol_kind::S_JGROUP: // JGROUP
+      case symbol_kind::S_JPARENT: // JPARENT
+      case symbol_kind::S_QSTR: // QSTR
+      case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+      case symbol_kind::S_exp: // exp
+      case symbol_kind::S_term: // term
+        value.template destroy< Expression * > ();
+        break;
+
+      default:
+        break;
+    }
+
+        Base::clear ();
+      }
+
+#if YYDEBUG || 0
+      /// The user-facing name of this symbol.
+      const char *name () const YY_NOEXCEPT
+      {
+        return Parser::symbol_name (this->kind ());
+      }
+#endif // #if YYDEBUG || 0
+
+
+      /// Backward compatibility (Bison 3.6).
+      symbol_kind_type type_get () const YY_NOEXCEPT;
+
+      /// Whether empty.
+      bool empty () const YY_NOEXCEPT;
+
+      /// Destructive move, \a s is emptied into this.
+      void move (basic_symbol& s);
+
+      /// The semantic value.
+      semantic_type value;
+
+    private:
+#if YY_CPLUSPLUS < 201103L
+      /// Assignment operator.
+      basic_symbol& operator= (const basic_symbol& that);
+#endif
+    };
+
+    /// Type access provider for token (enum) based symbols.
+    struct by_kind
+    {
+      /// Default constructor.
+      by_kind ();
+
+#if 201103L <= YY_CPLUSPLUS
+      /// Move constructor.
+      by_kind (by_kind&& that);
+#endif
+
+      /// Copy constructor.
+      by_kind (const by_kind& that);
+
+      /// The symbol kind as needed by the constructor.
+      typedef token_kind_type kind_type;
+
+      /// Constructor from (external) token numbers.
+      by_kind (kind_type t);
+
+      /// Record that this symbol is empty.
+      void clear () YY_NOEXCEPT;
+
+      /// Steal the symbol kind from \a that.
+      void move (by_kind& that);
+
+      /// The (internal) type number (corresponding to \a type).
+      /// \a empty when empty.
+      symbol_kind_type kind () const YY_NOEXCEPT;
+
+      /// Backward compatibility (Bison 3.6).
+      symbol_kind_type type_get () const YY_NOEXCEPT;
+
+      /// The symbol kind.
+      /// \a S_YYEMPTY when empty.
+      symbol_kind_type kind_;
+    };
+
+    /// Backward compatibility for a private implementation detail (Bison 3.6).
+    typedef by_kind by_type;
+
+    /// "External" symbols: returned by the scanner.
+    struct symbol_type : basic_symbol<by_kind>
+    {
+      /// Superclass.
+      typedef basic_symbol<by_kind> super_type;
+
+      /// Empty symbol.
+      symbol_type () {}
+
+      /// Constructor for valueless symbols, and symbols from each type.
+#if 201103L <= YY_CPLUSPLUS
+      symbol_type (int tok)
+        : super_type(token_type (tok))
+#else
+      symbol_type (int tok)
+        : super_type(token_type (tok))
+#endif
+      {
+        YY_ASSERT (tok == token::L_YYEOF
+                   || (token::L_YYerror <= tok && tok <= token::L_RPAR)
+                   || tok == token::L_HASPROP
+                   || (token::L_IN <= tok && tok <= 317));
+      }
+#if 201103L <= YY_CPLUSPLUS
+      symbol_type (int tok, Expression * v)
+        : super_type(token_type (tok), std::move (v))
+#else
+      symbol_type (int tok, const Expression *& v)
+        : super_type(token_type (tok), v)
+#endif
+      {
+        YY_ASSERT ((token::L_NUM <= tok && tok <= token::L_FNAME)
+                   || (token::L_JGROUP <= tok && tok <= token::L_FILEIOVFD));
+      }
+    };
+
+    /// Build a parser object.
+    Parser (QL::Result &result_yyarg);
+    virtual ~Parser ();
+
+#if 201103L <= YY_CPLUSPLUS
+    /// Non copyable.
+    Parser (const Parser&) = delete;
+    /// Non copyable.
+    Parser& operator= (const Parser&) = delete;
+#endif
+
+    /// Parse.  An alias for parse ().
+    /// \returns  0 iff parsing succeeded.
+    int operator() ();
+
+    /// Parse.
+    /// \returns  0 iff parsing succeeded.
+    virtual int parse ();
+
+#if YYDEBUG
+    /// The current debugging stream.
+    std::ostream& debug_stream () const YY_ATTRIBUTE_PURE;
+    /// Set the current debugging stream.
+    void set_debug_stream (std::ostream &);
+
+    /// Type for debugging levels.
+    typedef int debug_level_type;
+    /// The current debugging level.
+    debug_level_type debug_level () const YY_ATTRIBUTE_PURE;
+    /// Set the current debugging level.
+    void set_debug_level (debug_level_type l);
+#endif
+
+    /// Report a syntax error.
+    /// \param msg    a description of the syntax error.
+    virtual void error (const std::string& msg);
+
+    /// Report a syntax error.
+    void error (const syntax_error& err);
+
+#if YYDEBUG || 0
+    /// The user-facing name of the symbol whose (internal) number is
+    /// YYSYMBOL.  No bounds checking.
+    static const char *symbol_name (symbol_kind_type yysymbol);
+#endif // #if YYDEBUG || 0
+
+
+    // Implementation of make_symbol for each symbol type.
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_YYEOF ()
+      {
+        return symbol_type (token::L_YYEOF);
+      }
+#else
+      static
+      symbol_type
+      make_YYEOF ()
+      {
+        return symbol_type (token::L_YYEOF);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_YYerror ()
+      {
+        return symbol_type (token::L_YYerror);
+      }
+#else
+      static
+      symbol_type
+      make_YYerror ()
+      {
+        return symbol_type (token::L_YYerror);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_YYUNDEF ()
+      {
+        return symbol_type (token::L_YYUNDEF);
+      }
+#else
+      static
+      symbol_type
+      make_YYUNDEF ()
+      {
+        return symbol_type (token::L_YYUNDEF);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_LPAR ()
+      {
+        return symbol_type (token::L_LPAR);
+      }
+#else
+      static
+      symbol_type
+      make_LPAR ()
+      {
+        return symbol_type (token::L_LPAR);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_RPAR ()
+      {
+        return symbol_type (token::L_RPAR);
+      }
+#else
+      static
+      symbol_type
+      make_RPAR ()
+      {
+        return symbol_type (token::L_RPAR);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_NUM (Expression * v)
+      {
+        return symbol_type (token::L_NUM, std::move (v));
+      }
+#else
+      static
+      symbol_type
+      make_NUM (const Expression *& v)
+      {
+        return symbol_type (token::L_NUM, v);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_NAME (Expression * v)
+      {
+        return symbol_type (token::L_NAME, std::move (v));
+      }
+#else
+      static
+      symbol_type
+      make_NAME (const Expression *& v)
+      {
+        return symbol_type (token::L_NAME, v);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_FNAME (Expression * v)
+      {
+        return symbol_type (token::L_FNAME, std::move (v));
+      }
+#else
+      static
+      symbol_type
+      make_FNAME (const Expression *& v)
+      {
+        return symbol_type (token::L_FNAME, v);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_HASPROP ()
+      {
+        return symbol_type (token::L_HASPROP);
+      }
+#else
+      static
+      symbol_type
+      make_HASPROP ()
+      {
+        return symbol_type (token::L_HASPROP);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_JGROUP (Expression * v)
+      {
+        return symbol_type (token::L_JGROUP, std::move (v));
+      }
+#else
+      static
+      symbol_type
+      make_JGROUP (const Expression *& v)
+      {
+        return symbol_type (token::L_JGROUP, v);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_JPARENT (Expression * v)
+      {
+        return symbol_type (token::L_JPARENT, std::move (v));
+      }
+#else
+      static
+      symbol_type
+      make_JPARENT (const Expression *& v)
+      {
+        return symbol_type (token::L_JPARENT, v);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_QSTR (Expression * v)
+      {
+        return symbol_type (token::L_QSTR, std::move (v));
+      }
+#else
+      static
+      symbol_type
+      make_QSTR (const Expression *& v)
+      {
+        return symbol_type (token::L_QSTR, v);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_FILEIOVFD (Expression * v)
+      {
+        return symbol_type (token::L_FILEIOVFD, std::move (v));
+      }
+#else
+      static
+      symbol_type
+      make_FILEIOVFD (const Expression *& v)
+      {
+        return symbol_type (token::L_FILEIOVFD, v);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_IN ()
+      {
+        return symbol_type (token::L_IN);
+      }
+#else
+      static
+      symbol_type
+      make_IN ()
+      {
+        return symbol_type (token::L_IN);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_SOME ()
+      {
+        return symbol_type (token::L_SOME);
+      }
+#else
+      static
+      symbol_type
+      make_SOME ()
+      {
+        return symbol_type (token::L_SOME);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_ORDR ()
+      {
+        return symbol_type (token::L_ORDR);
+      }
+#else
+      static
+      symbol_type
+      make_ORDR ()
+      {
+        return symbol_type (token::L_ORDR);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_COMMA ()
+      {
+        return symbol_type (token::L_COMMA);
+      }
+#else
+      static
+      symbol_type
+      make_COMMA ()
+      {
+        return symbol_type (token::L_COMMA);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_QWE ()
+      {
+        return symbol_type (token::L_QWE);
+      }
+#else
+      static
+      symbol_type
+      make_QWE ()
+      {
+        return symbol_type (token::L_QWE);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_COLON ()
+      {
+        return symbol_type (token::L_COLON);
+      }
+#else
+      static
+      symbol_type
+      make_COLON ()
+      {
+        return symbol_type (token::L_COLON);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_AND ()
+      {
+        return symbol_type (token::L_AND);
+      }
+#else
+      static
+      symbol_type
+      make_AND ()
+      {
+        return symbol_type (token::L_AND);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_OR ()
+      {
+        return symbol_type (token::L_OR);
+      }
+#else
+      static
+      symbol_type
+      make_OR ()
+      {
+        return symbol_type (token::L_OR);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_EQV ()
+      {
+        return symbol_type (token::L_EQV);
+      }
+#else
+      static
+      symbol_type
+      make_EQV ()
+      {
+        return symbol_type (token::L_EQV);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_NEQV ()
+      {
+        return symbol_type (token::L_NEQV);
+      }
+#else
+      static
+      symbol_type
+      make_NEQV ()
+      {
+        return symbol_type (token::L_NEQV);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_BITAND ()
+      {
+        return symbol_type (token::L_BITAND);
+      }
+#else
+      static
+      symbol_type
+      make_BITAND ()
+      {
+        return symbol_type (token::L_BITAND);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_BITOR ()
+      {
+        return symbol_type (token::L_BITOR);
+      }
+#else
+      static
+      symbol_type
+      make_BITOR ()
+      {
+        return symbol_type (token::L_BITOR);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_BITXOR ()
+      {
+        return symbol_type (token::L_BITXOR);
+      }
+#else
+      static
+      symbol_type
+      make_BITXOR ()
+      {
+        return symbol_type (token::L_BITXOR);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_EQ ()
+      {
+        return symbol_type (token::L_EQ);
+      }
+#else
+      static
+      symbol_type
+      make_EQ ()
+      {
+        return symbol_type (token::L_EQ);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_NE ()
+      {
+        return symbol_type (token::L_NE);
+      }
+#else
+      static
+      symbol_type
+      make_NE ()
+      {
+        return symbol_type (token::L_NE);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_LT ()
+      {
+        return symbol_type (token::L_LT);
+      }
+#else
+      static
+      symbol_type
+      make_LT ()
+      {
+        return symbol_type (token::L_LT);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_GT ()
+      {
+        return symbol_type (token::L_GT);
+      }
+#else
+      static
+      symbol_type
+      make_GT ()
+      {
+        return symbol_type (token::L_GT);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_LE ()
+      {
+        return symbol_type (token::L_LE);
+      }
+#else
+      static
+      symbol_type
+      make_LE ()
+      {
+        return symbol_type (token::L_LE);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_GE ()
+      {
+        return symbol_type (token::L_GE);
+      }
+#else
+      static
+      symbol_type
+      make_GE ()
+      {
+        return symbol_type (token::L_GE);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_LS ()
+      {
+        return symbol_type (token::L_LS);
+      }
+#else
+      static
+      symbol_type
+      make_LS ()
+      {
+        return symbol_type (token::L_LS);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_RS ()
+      {
+        return symbol_type (token::L_RS);
+      }
+#else
+      static
+      symbol_type
+      make_RS ()
+      {
+        return symbol_type (token::L_RS);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_ADD ()
+      {
+        return symbol_type (token::L_ADD);
+      }
+#else
+      static
+      symbol_type
+      make_ADD ()
+      {
+        return symbol_type (token::L_ADD);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_MINUS ()
+      {
+        return symbol_type (token::L_MINUS);
+      }
+#else
+      static
+      symbol_type
+      make_MINUS ()
+      {
+        return symbol_type (token::L_MINUS);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_MUL ()
+      {
+        return symbol_type (token::L_MUL);
+      }
+#else
+      static
+      symbol_type
+      make_MUL ()
+      {
+        return symbol_type (token::L_MUL);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_DIV ()
+      {
+        return symbol_type (token::L_DIV);
+      }
+#else
+      static
+      symbol_type
+      make_DIV ()
+      {
+        return symbol_type (token::L_DIV);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_REM ()
+      {
+        return symbol_type (token::L_REM);
+      }
+#else
+      static
+      symbol_type
+      make_REM ()
+      {
+        return symbol_type (token::L_REM);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_DEG ()
+      {
+        return symbol_type (token::L_DEG);
+      }
+#else
+      static
+      symbol_type
+      make_DEG ()
+      {
+        return symbol_type (token::L_DEG);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_NOT ()
+      {
+        return symbol_type (token::L_NOT);
+      }
+#else
+      static
+      symbol_type
+      make_NOT ()
+      {
+        return symbol_type (token::L_NOT);
+      }
+#endif
+#if 201103L <= YY_CPLUSPLUS
+      static
+      symbol_type
+      make_BITNOT ()
+      {
+        return symbol_type (token::L_BITNOT);
+      }
+#else
+      static
+      symbol_type
+      make_BITNOT ()
+      {
+        return symbol_type (token::L_BITNOT);
+      }
+#endif
+
+
+  private:
+#if YY_CPLUSPLUS < 201103L
+    /// Non copyable.
+    Parser (const Parser&);
+    /// Non copyable.
+    Parser& operator= (const Parser&);
+#endif
+
+
+    /// Stored state numbers (used for stacks).
+    typedef signed char state_type;
+
+    /// Compute post-reduction state.
+    /// \param yystate   the current state
+    /// \param yysym     the nonterminal to push on the stack
+    static state_type yy_lr_goto_state_ (state_type yystate, int yysym);
+
+    /// Whether the given \c yypact_ value indicates a defaulted state.
+    /// \param yyvalue   the value to check
+    static bool yy_pact_value_is_default_ (int yyvalue);
+
+    /// Whether the given \c yytable_ value indicates a syntax error.
+    /// \param yyvalue   the value to check
+    static bool yy_table_value_is_error_ (int yyvalue);
+
+    static const signed char yypact_ninf_;
+    static const signed char yytable_ninf_;
+
+    /// Convert a scanner token kind \a t to a symbol kind.
+    /// In theory \a t should be a token_kind_type, but character literals
+    /// are valid, yet not members of the token_type enum.
+    static symbol_kind_type yytranslate_ (int t);
+
+#if YYDEBUG || 0
+    /// For a symbol, its name in clear.
+    static const char* const yytname_[];
+#endif // #if YYDEBUG || 0
+
+
+    // Tables.
+    // YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+    // STATE-NUM.
+    static const short yypact_[];
+
+    // YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+    // Performed when YYTABLE does not specify something else to do.  Zero
+    // means the default is an error.
+    static const signed char yydefact_[];
+
+    // YYPGOTO[NTERM-NUM].
+    static const signed char yypgoto_[];
+
+    // YYDEFGOTO[NTERM-NUM].
+    static const signed char yydefgoto_[];
+
+    // YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM.  If
+    // positive, shift that token.  If negative, reduce the rule whose
+    // number is the opposite.  If YYTABLE_NINF, syntax error.
+    static const signed char yytable_[];
+
+    static const signed char yycheck_[];
+
+    // YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+    // symbol of state STATE-NUM.
+    static const signed char yystos_[];
+
+    // YYR1[YYN] -- Symbol number of symbol that rule YYN derives.
+    static const signed char yyr1_[];
+
+    // YYR2[YYN] -- Number of symbols on the right hand side of rule YYN.
+    static const signed char yyr2_[];
+
+
+#if YYDEBUG
+    // YYRLINE[YYN] -- Source line where rule number YYN was defined.
+    static const unsigned char yyrline_[];
+    /// Report on the debug stream that the rule \a r is going to be reduced.
+    virtual void yy_reduce_print_ (int r) const;
+    /// Print the state stack on the debug stream.
+    virtual void yy_stack_print_ () const;
+
+    /// Debugging level.
+    int yydebug_;
+    /// Debug stream.
+    std::ostream* yycdebug_;
+
+    /// \brief Display a symbol kind, value and location.
+    /// \param yyo    The output stream.
+    /// \param yysym  The symbol.
+    template <typename Base>
+    void yy_print_ (std::ostream& yyo, const basic_symbol<Base>& yysym) const;
+#endif
+
+    /// \brief Reclaim the memory associated to a symbol.
+    /// \param yymsg     Why this token is reclaimed.
+    ///                  If null, print nothing.
+    /// \param yysym     The symbol.
+    template <typename Base>
+    void yy_destroy_ (const char* yymsg, basic_symbol<Base>& yysym) const;
+
+  private:
+    /// Type access provider for state based symbols.
+    struct by_state
+    {
+      /// Default constructor.
+      by_state () YY_NOEXCEPT;
+
+      /// The symbol kind as needed by the constructor.
+      typedef state_type kind_type;
+
+      /// Constructor.
+      by_state (kind_type s) YY_NOEXCEPT;
+
+      /// Copy constructor.
+      by_state (const by_state& that) YY_NOEXCEPT;
+
+      /// Record that this symbol is empty.
+      void clear () YY_NOEXCEPT;
+
+      /// Steal the symbol kind from \a that.
+      void move (by_state& that);
+
+      /// The symbol kind (corresponding to \a state).
+      /// \a symbol_kind::S_YYEMPTY when empty.
+      symbol_kind_type kind () const YY_NOEXCEPT;
+
+      /// The state number used to denote an empty symbol.
+      /// We use the initial state, as it does not have a value.
+      enum { empty_state = 0 };
+
+      /// The state.
+      /// \a empty when empty.
+      state_type state;
+    };
+
+    /// "Internal" symbol: element of the stack.
+    struct stack_symbol_type : basic_symbol<by_state>
+    {
+      /// Superclass.
+      typedef basic_symbol<by_state> super_type;
+      /// Construct an empty symbol.
+      stack_symbol_type ();
+      /// Move or copy construction.
+      stack_symbol_type (YY_RVREF (stack_symbol_type) that);
+      /// Steal the contents from \a sym to build this.
+      stack_symbol_type (state_type s, YY_MOVE_REF (symbol_type) sym);
+#if YY_CPLUSPLUS < 201103L
+      /// Assignment, needed by push_back by some old implementations.
+      /// Moves the contents of that.
+      stack_symbol_type& operator= (stack_symbol_type& that);
+
+      /// Assignment, needed by push_back by other implementations.
+      /// Needed by some other old implementations.
+      stack_symbol_type& operator= (const stack_symbol_type& that);
+#endif
+    };
+
+    /// A stack with random access from its top.
+    template <typename T, typename S = std::vector<T> >
+    class stack
+    {
+    public:
+      // Hide our reversed order.
+      typedef typename S::iterator iterator;
+      typedef typename S::const_iterator const_iterator;
+      typedef typename S::size_type size_type;
+      typedef typename std::ptrdiff_t index_type;
+
+      stack (size_type n = 200)
+        : seq_ (n)
+      {}
+
+#if 201103L <= YY_CPLUSPLUS
+      /// Non copyable.
+      stack (const stack&) = delete;
+      /// Non copyable.
+      stack& operator= (const stack&) = delete;
+#endif
+
+      /// Random access.
+      ///
+      /// Index 0 returns the topmost element.
+      const T&
+      operator[] (index_type i) const
+      {
+        return seq_[size_type (size () - 1 - i)];
+      }
+
+      /// Random access.
+      ///
+      /// Index 0 returns the topmost element.
+      T&
+      operator[] (index_type i)
+      {
+        return seq_[size_type (size () - 1 - i)];
+      }
+
+      /// Steal the contents of \a t.
+      ///
+      /// Close to move-semantics.
+      void
+      push (YY_MOVE_REF (T) t)
+      {
+        seq_.push_back (T ());
+        operator[] (0).move (t);
+      }
+
+      /// Pop elements from the stack.
+      void
+      pop (std::ptrdiff_t n = 1) YY_NOEXCEPT
+      {
+        for (; 0 < n; --n)
+          seq_.pop_back ();
+      }
+
+      /// Pop all elements from the stack.
+      void
+      clear () YY_NOEXCEPT
+      {
+        seq_.clear ();
+      }
+
+      /// Number of elements on the stack.
+      index_type
+      size () const YY_NOEXCEPT
+      {
+        return index_type (seq_.size ());
+      }
+
+      /// Iterator on top of the stack (going downwards).
+      const_iterator
+      begin () const YY_NOEXCEPT
+      {
+        return seq_.begin ();
+      }
+
+      /// Bottom of the stack.
+      const_iterator
+      end () const YY_NOEXCEPT
+      {
+        return seq_.end ();
+      }
+
+      /// Present a slice of the top of a stack.
+      class slice
+      {
+      public:
+        slice (const stack& stack, index_type range)
+          : stack_ (stack)
+          , range_ (range)
+        {}
+
+        const T&
+        operator[] (index_type i) const
+        {
+          return stack_[range_ - i];
+        }
+
+      private:
+        const stack& stack_;
+        index_type range_;
+      };
+
+    private:
+#if YY_CPLUSPLUS < 201103L
+      /// Non copyable.
+      stack (const stack&);
+      /// Non copyable.
+      stack& operator= (const stack&);
+#endif
+      /// The wrapped container.
+      S seq_;
+    };
+
+
+    /// Stack type.
+    typedef stack<stack_symbol_type> stack_type;
+
+    /// The stack.
+    stack_type yystack_;
+
+    /// Push a new state on the stack.
+    /// \param m    a debug message to display
+    ///             if null, no trace is output.
+    /// \param sym  the symbol
+    /// \warning the contents of \a s.value is stolen.
+    void yypush_ (const char* m, YY_MOVE_REF (stack_symbol_type) sym);
+
+    /// Push a new look ahead token on the state on the stack.
+    /// \param m    a debug message to display
+    ///             if null, no trace is output.
+    /// \param s    the state
+    /// \param sym  the symbol (for its value and location).
+    /// \warning the contents of \a sym.value is stolen.
+    void yypush_ (const char* m, state_type s, YY_MOVE_REF (symbol_type) sym);
+
+    /// Pop \a n symbols from the stack.
+    void yypop_ (int n = 1);
+
+    /// Constants.
+    enum
+    {
+      yylast_ = 279,     ///< Last index in yytable_.
+      yynnts_ = 4,  ///< Number of nonterminal symbols.
+      yyfinal_ = 24 ///< Termination state number.
+    };
+
+
+    // User arguments.
+    QL::Result &result;
+
+  };
+
+  inline
+  Parser::symbol_kind_type
+  Parser::yytranslate_ (int t)
+  {
+    // YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to
+    // TOKEN-NUM as returned by yylex.
+    static
+    const signed char
+    translate_table[] =
+    {
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
+      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
+      55,    56,    57,    58,    59,    60,    61,    62
+    };
+    // Last valid token kind.
+    const int code_max = 317;
+
+    if (t <= 0)
+      return symbol_kind::S_YYEOF;
+    else if (t <= code_max)
+      return YY_CAST (symbol_kind_type, translate_table[t]);
+    else
+      return symbol_kind::S_YYUNDEF;
+  }
+
+  // basic_symbol.
+  template <typename Base>
+  Parser::basic_symbol<Base>::basic_symbol (const basic_symbol& that)
+    : Base (that)
+    , value ()
+  {
+    switch (this->kind ())
+    {
+      case symbol_kind::S_NUM: // "number"
+      case symbol_kind::S_NAME: // "name"
+      case symbol_kind::S_FNAME: // FNAME
+      case symbol_kind::S_JGROUP: // JGROUP
+      case symbol_kind::S_JPARENT: // JPARENT
+      case symbol_kind::S_QSTR: // QSTR
+      case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+      case symbol_kind::S_exp: // exp
+      case symbol_kind::S_term: // term
+        value.copy< Expression * > (YY_MOVE (that.value));
+        break;
+
+      default:
+        break;
+    }
+
+  }
+
+
+
+  template <typename Base>
+  Parser::symbol_kind_type
+  Parser::basic_symbol<Base>::type_get () const YY_NOEXCEPT
+  {
+    return this->kind ();
+  }
+
+  template <typename Base>
+  bool
+  Parser::basic_symbol<Base>::empty () const YY_NOEXCEPT
+  {
+    return this->kind () == symbol_kind::S_YYEMPTY;
+  }
+
+  template <typename Base>
+  void
+  Parser::basic_symbol<Base>::move (basic_symbol& s)
+  {
+    super_type::move (s);
+    switch (this->kind ())
+    {
+      case symbol_kind::S_NUM: // "number"
+      case symbol_kind::S_NAME: // "name"
+      case symbol_kind::S_FNAME: // FNAME
+      case symbol_kind::S_JGROUP: // JGROUP
+      case symbol_kind::S_JPARENT: // JPARENT
+      case symbol_kind::S_QSTR: // QSTR
+      case symbol_kind::S_FILEIOVFD: // FILEIOVFD
+      case symbol_kind::S_exp: // exp
+      case symbol_kind::S_term: // term
+        value.move< Expression * > (YY_MOVE (s.value));
+        break;
+
+      default:
+        break;
+    }
+
+  }
+
+  // by_kind.
+  inline
+  Parser::by_kind::by_kind ()
+    : kind_ (symbol_kind::S_YYEMPTY)
+  {}
+
+#if 201103L <= YY_CPLUSPLUS
+  inline
+  Parser::by_kind::by_kind (by_kind&& that)
+    : kind_ (that.kind_)
+  {
+    that.clear ();
+  }
+#endif
+
+  inline
+  Parser::by_kind::by_kind (const by_kind& that)
+    : kind_ (that.kind_)
+  {}
+
+  inline
+  Parser::by_kind::by_kind (token_kind_type t)
+    : kind_ (yytranslate_ (t))
+  {}
+
+  inline
+  void
+  Parser::by_kind::clear () YY_NOEXCEPT
+  {
+    kind_ = symbol_kind::S_YYEMPTY;
+  }
+
+  inline
+  void
+  Parser::by_kind::move (by_kind& that)
+  {
+    kind_ = that.kind_;
+    that.clear ();
+  }
+
+  inline
+  Parser::symbol_kind_type
+  Parser::by_kind::kind () const YY_NOEXCEPT
+  {
+    return kind_;
+  }
+
+  inline
+  Parser::symbol_kind_type
+  Parser::by_kind::type_get () const YY_NOEXCEPT
+  {
+    return this->kind ();
+  }
+
+#line 50 "QLParser.yy"
+} // QL
+#line 2034 "QLParser.tab.hh"
+
+
+
+
+#endif // !YY_YY_QLPARSER_TAB_HH_INCLUDED
diff --git a/gprofng/src/QLParser.yy b/gprofng/src/QLParser.yy
new file mode 100644 (file)
index 0000000..689d0e1
--- /dev/null
@@ -0,0 +1,390 @@
+/* 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.  */
+
+// To rebuild QLParser.tab.cc and QLParser.tab.hh, use bison 3.6 or newer:
+// cd gprofng/src && bison QLParser.yy
+
+// For "api.parser.class"
+%require "3.3"
+%language "C++"
+
+%code top {
+#include <stdio.h>
+#include <string.h>
+#include <string>
+}
+%code requires {
+#include "QLParser.h"
+#include "DbeSession.h"
+#include "Expression.h"
+#include "Table.h"
+#include "i18n.h"
+}
+
+%code
+{
+namespace QL
+{
+  static QL::Parser::symbol_type yylex (QL::Result &result);
+}
+}
+
+%defines
+%define api.namespace {QL}
+%define api.parser.class {Parser}
+%define api.token.constructor
+%define api.value.type variant
+// Later: api.value.automove
+%define api.token.prefix {L_}
+%define parse.assert
+%param {QL::Result &result}
+
+%start S
+
+%token LPAR "("
+  RPAR ")"
+  NUM "number"
+  NAME "name"
+  FNAME 
+  HASPROP
+  JGROUP
+  JPARENT
+  QSTR
+  FILEIOVFD
+
+%nonassoc IN SOME ORDR
+%left  COMMA ","
+%right QWE "?"
+       COLON ":"
+%left  AND "&&"
+       OR "|"
+       EQV NEQV
+       BITAND BITOR
+       BITXOR "^"
+%nonassoc EQ "="
+         NE "!="
+         LT "<"
+         GT ">"
+         LE "<="
+         GE ">="
+%left LS "<<"
+      RS ">>"
+      ADD "+"
+      MINUS "-"
+      MUL "*"
+      DIV "/"
+      REM "%"
+%right DEG
+       NOT "!"
+       BITNOT "~"
+
+%type <Expression *> QSTR NUM NAME FNAME JGROUP JPARENT FILEIOVFD exp term
+
+%destructor { delete $$; } <*>;
+
+%%
+
+S:     /* empty */             { result.out = new Expression (Expression::OP_NUM, (uint64_t) 1); }
+|      exp                     { result.out = new Expression ($1); }
+
+exp:     exp DEG exp           { $$ = new Expression (Expression::OP_DEG, $1, $3); } /* dead? */
+       | exp MUL exp           { $$ = new Expression (Expression::OP_MUL, $1, $3); }
+       | exp DIV exp           { $$ = new Expression (Expression::OP_DIV, $1, $3); }
+       | exp REM exp           { $$ = new Expression (Expression::OP_REM, $1, $3); }
+       | exp ADD exp           { $$ = new Expression (Expression::OP_ADD, $1, $3); }
+       | exp MINUS exp         { $$ = new Expression (Expression::OP_MINUS, $1, $3); }
+       | exp LS  exp           { $$ = new Expression (Expression::OP_LS, $1, $3); }
+       | exp RS  exp           { $$ = new Expression (Expression::OP_RS, $1, $3); }
+       | exp LT  exp           { $$ = new Expression (Expression::OP_LT, $1, $3); }
+       | exp LE  exp           { $$ = new Expression (Expression::OP_LE, $1, $3); }
+       | exp GT  exp           { $$ = new Expression (Expression::OP_GT, $1, $3); }
+       | exp GE  exp           { $$ = new Expression (Expression::OP_GE, $1, $3); }
+       | exp EQ  exp           { $$ = new Expression (Expression::OP_EQ, $1, $3); }
+       | exp NE  exp           { $$ = new Expression (Expression::OP_NE, $1, $3); }
+       | exp BITAND exp        { $$ = new Expression (Expression::OP_BITAND, $1, $3); }
+       | exp BITXOR exp        { $$ = new Expression (Expression::OP_BITXOR, $1, $3); }
+       | exp BITOR  exp        { $$ = new Expression (Expression::OP_BITOR, $1, $3); }
+       | exp AND exp           { $$ = new Expression (Expression::OP_AND, $1, $3); }
+       | exp OR  exp           { $$ = new Expression (Expression::OP_OR, $1, $3); }
+       | exp NEQV exp          { $$ = new Expression (Expression::OP_NEQV, $1, $3); } /* dead? */
+       | exp EQV exp           { $$ = new Expression (Expression::OP_EQV, $1, $3); } /* dead? */
+       | exp QWE exp COLON exp { Expression colon = Expression (Expression::OP_COLON, $3, $5);
+                                 $$ = new Expression (Expression::OP_QWE, $1, &colon); }
+       | exp COMMA  exp        { $$ = new Expression (Expression::OP_COMMA, $1, $3); }
+       | exp IN exp            { $$ = new Expression (Expression::OP_IN, $1, $3); }
+       | exp SOME IN exp       { $$ = new Expression (Expression::OP_SOMEIN, $1, $4); }
+       | exp ORDR IN exp       { $$ = new Expression (Expression::OP_ORDRIN, $1, $4); }
+       | term                  { $$ = new Expression ($1); }
+
+term:    MINUS term            { Expression num = Expression (Expression::OP_NUM, (uint64_t) 0);
+                                 $$ = new Expression (Expression::OP_MINUS, &num, $2); }
+       | NOT    term           { $$ = new Expression (Expression::OP_NOT, $2, NULL); }
+       | BITNOT term           { $$ = new Expression (Expression::OP_BITNOT, $2, NULL); }
+       | LPAR exp RPAR         { $$ = new Expression ($2); }
+       | FNAME LPAR QSTR RPAR  { $$ = new Expression (Expression::OP_FUNC, $1, $3); }
+       | HASPROP LPAR NAME RPAR { $$ = new Expression (Expression::OP_HASPROP, $3, NULL); }
+       | JGROUP LPAR QSTR RPAR { $$ = new Expression (Expression::OP_JAVA, $1, $3); }
+       | JPARENT LPAR QSTR RPAR { $$ = new Expression (Expression::OP_JAVA, $1, $3); }
+       | FILEIOVFD LPAR QSTR RPAR { $$ = new Expression (Expression::OP_FILE, $1, $3); }
+       | NUM                   { $$ = new Expression ($1); }
+       | NAME                  { $$ = new Expression ($1); }
+
+%%
+
+namespace QL
+{
+  static Parser::symbol_type
+  unget_ret (std::istream &in, char c, Parser::symbol_type tok)
+  {
+    in.putback (c);
+    return tok;
+  }
+
+  static Expression *
+  processName (char *name)
+  {
+    int propID = dbeSession->getPropIdByName (name);
+    if (propID != PROP_NONE)
+      {
+       Expression *expr = new Expression (Expression::OP_NUM, (uint64_t) propID);
+       Expression *ret = new Expression (Expression::OP_NAME, expr);
+       delete expr;
+       return ret;
+      }
+
+    // If a name is not statically known try user defined objects
+    Expression *expr = dbeSession->findObjDefByName (name);
+    if (expr != NULL)
+      return expr->copy();
+
+    throw Parser::syntax_error ("Name not found");
+  }
+
+  static Parser::symbol_type
+  yylex (QL::Result &result)
+  {
+    int base = 0;
+    int c;
+
+    do
+      c = result.in.get ();
+    while (result.in && (c == ' ' || c == '\t'));
+    if (!result.in)
+      return Parser::make_YYEOF ();
+
+    switch (c)
+      {
+      case '\n': return Parser::make_YYEOF ();
+      case '(': return Parser::make_LPAR () ;
+      case ')': return Parser::make_RPAR ();
+      case ',': return Parser::make_COMMA ();
+      case '%': return Parser::make_REM ();
+      case '/': return Parser::make_DIV ();
+      case '*': return Parser::make_MUL ();
+      case '-': return Parser::make_MINUS ();
+      case '+': return Parser::make_ADD ();
+      case '~': return Parser::make_BITNOT ();
+      case '^': return Parser::make_BITXOR ();
+      case '?': return Parser::make_QWE ();
+      case ':': return Parser::make_COLON ();
+      case '|':
+       c = result.in.get ();
+       if (c == '|')
+         return Parser::make_OR ();
+       else
+         return unget_ret (result.in, c, Parser::make_BITOR ());
+      case '&':
+       c = result.in.get ();
+       if (c == '&')
+         return Parser::make_AND ();
+       else
+         return unget_ret (result.in, c, Parser::make_BITAND ());
+      case '!':
+       c = result.in.get ();
+       if (c == '=')
+         return Parser::make_NE ();
+       else
+         return unget_ret (result.in, c, Parser::make_NOT ());
+      case '=':
+       c = result.in.get ();
+       if (c == '=')
+         return Parser::make_EQ ();
+       else
+         throw Parser::syntax_error ("Syntax error after =");
+      case '<':
+       c = result.in.get ();
+       if (c == '=')
+         return Parser::make_LE ();
+       else if (c == '<')
+         return Parser::make_LS ();
+       else
+         return unget_ret (result.in, c, Parser::make_LT ());
+      case '>':
+       c = result.in.get ();
+       if (c == '=')
+         return Parser::make_GE ();
+       else if (c == '>')
+         return Parser::make_RS ();
+       else
+         return unget_ret (result.in, c, Parser::make_GT ());
+      case '"':
+       {
+         int  maxsz = 16;
+         char *str = (char *) malloc (maxsz);
+         char *ptr = str;
+
+         for (;;)
+           {
+             c = result.in.get ();
+             if (!result.in)
+               {
+                 free (str);
+                 throw Parser::syntax_error ("Unclosed \"");
+               }
+
+             switch (c)
+               {
+               case '"':
+                 *ptr = (char)0;
+                 // XXX omazur: need new string type
+                 return Parser::make_QSTR (new Expression (Expression::OP_NUM, (uint64_t) str));
+               case 0:
+               case '\n':
+                 free (str);
+                 throw Parser::syntax_error ("Multiline strings are not supported");
+               default:
+                 if (ptr - str >= maxsz)
+                   {
+                     size_t len = ptr - str;
+                     maxsz = maxsz > 8192 ? maxsz + 8192 : maxsz * 2;
+                     char *new_s = (char *) realloc (str, maxsz);
+                     str = new_s;
+                     ptr = str + len;
+                   }
+                 *ptr++ = c;
+               }
+           }
+       }
+      default:
+       if (c == '0')
+         {
+           base = 8;
+           c = result.in.get ();
+           if ( c == 'x' )
+             {
+               base = 16;
+               c = result.in.get ();
+             }
+         }
+       else if (c >= '1' && c <='9')
+         base = 10;
+
+       if (base)
+         {
+           uint64_t lval = 0;
+           for (;;)
+             {
+               int digit = -1;
+               switch (c)
+                 {
+                 case '0': case '1': case '2': case '3':
+                 case '4': case '5': case '6': case '7':
+                   digit = c - '0';
+                   break;
+                 case '8': case '9':
+                   if (base > 8)
+                     digit = c - '0';
+                   break;
+                 case 'a': case 'b': case 'c':
+                 case 'd': case 'e': case 'f':
+                   if (base == 16)
+                     digit = c - 'a' + 10;
+                   break;
+                 case 'A': case 'B': case 'C':
+                 case 'D': case 'E': case 'F':
+                   if (base == 16)
+                     digit = c - 'A' + 10;
+                   break;
+                 }
+               if  (digit == -1)
+                 {
+                   result.in.putback (c);
+                   break;
+                 }
+               lval = lval * base + digit;
+               c = result.in.get ();
+             }
+           return Parser::make_NUM (new Expression (Expression::OP_NUM, lval));
+         }
+
+       if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
+         {
+           char name[32];      // omazur XXX: accept any length
+           name[0] = (char)c;
+           for (size_t i = 1; i < sizeof (name); i++)
+             {
+               c = result.in.get ();
+               if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') ||
+                   (c >= '0' && c <= '9') || (c == '_'))
+                 name[i] = c;
+               else
+                 {
+                   name[i] = (char)0;
+                   result.in.putback (c);
+                   break;
+                 }
+             }
+
+           if (strcasecmp (name, NTXT ("IN")) == 0)
+             return Parser::make_IN ();
+           else if (strcasecmp (name, NTXT ("SOME")) == 0)
+             return Parser::make_SOME ();
+           else if (strcasecmp (name, NTXT ("ORDERED")) == 0)
+             return Parser::make_ORDR ();
+           else if (strcasecmp (name, NTXT ("TRUE")) == 0)
+             return Parser::make_NUM (new Expression (Expression::OP_NUM, (uint64_t) 1));
+           else if (strcasecmp (name, NTXT ("FALSE")) == 0)
+             return Parser::make_NUM (new Expression (Expression::OP_NUM, (uint64_t) 0));
+           else if (strcasecmp (name, NTXT ("FNAME")) == 0)
+             return Parser::make_FNAME (new Expression (Expression::OP_NUM, Expression::FUNC_FNAME));
+           else if (strcasecmp (name, NTXT ("HAS_PROP")) == 0)
+             return Parser::make_HASPROP ();
+           else if (strcasecmp (name, NTXT ("JGROUP")) == 0)
+             return Parser::make_JGROUP (new Expression (Expression::OP_NUM, Expression::JAVA_JGROUP));
+           else if (strcasecmp (name, NTXT ("JPARENT")) == 0 )
+             return Parser::make_JPARENT (new Expression (Expression::OP_NUM, Expression::JAVA_JPARENT));
+           else if (strcasecmp (name, NTXT ("DNAME")) == 0)
+             return Parser::make_FNAME (new Expression (Expression::OP_NUM, Expression::FUNC_DNAME));
+           else if (strcasecmp (name, NTXT ("FILEIOVFD")) == 0 )
+             return Parser::make_FILEIOVFD (new Expression (Expression::OP_NUM, (uint64_t) 0));
+
+           return Parser::make_NAME (processName (name));
+         }
+
+       throw Parser::syntax_error ("Syntax error");
+      }
+  }
+  void
+  Parser::error (const std::string &)
+  {
+    // do nothing for now
+  }
+}
+
diff --git a/gprofng/src/SAXParser.h b/gprofng/src/SAXParser.h
new file mode 100644 (file)
index 0000000..dde3e06
--- /dev/null
@@ -0,0 +1,49 @@
+/* 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.  */
+
+/*
+ *     javax/xml/parsers/SAXParser.java
+ *
+ *     Based on JavaTM 2 Platform Standard Ed. 5.0
+ */
+
+#ifndef _SAXParser_h
+#define _SAXParser_h
+
+class File;
+class DefaultHandler;
+class SAXException;
+
+class SAXParser
+{
+public:
+
+  virtual ~SAXParser () { }
+  virtual void reset () { }
+  virtual void parse (File*, DefaultHandler*) = 0;
+  virtual bool isNamespaceAware () = 0;
+  virtual bool isValidating () = 0;
+
+protected:
+
+  SAXParser () { }
+};
+
+#endif /* _SAXParser_h */
diff --git a/gprofng/src/SAXParserFactory.cc b/gprofng/src/SAXParserFactory.cc
new file mode 100644 (file)
index 0000000..7d9e851
--- /dev/null
@@ -0,0 +1,666 @@
+/* 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 <ctype.h>
+
+#include "util.h"
+#include "vec.h"
+#include "DefaultHandler.h"
+#include "SAXParser.h"
+#include "SAXParserFactory.h"
+#include "StringBuilder.h"
+
+/*
+ *  Private implementation of Attributes
+ */
+class AttributesP : public Attributes
+{
+public:
+  AttributesP ();
+  ~AttributesP ();
+  int getLength ();
+  const char *getQName (int index);
+  const char *getValue (int index);
+  int getIndex (const char *qName);
+  const char *getValue (const char *qName);
+  void append (char *qName, char *value);
+
+private:
+  Vector<char*> *names;
+  Vector<char*> *values;
+};
+
+AttributesP::AttributesP ()
+{
+  names = new Vector<char*>;
+  values = new Vector<char*>;
+}
+
+AttributesP::~AttributesP ()
+{
+  Destroy (names);
+  Destroy (values);
+}
+
+int
+AttributesP::getLength ()
+{
+  return names->size ();
+}
+
+const char *
+AttributesP::getQName (int index)
+{
+  if (index < 0 || index >= names->size ())
+    return NULL;
+  return names->fetch (index);
+}
+
+const char *
+AttributesP::getValue (int index)
+{
+  if (index < 0 || index >= values->size ())
+    return NULL;
+  return values->fetch (index);
+}
+
+int
+AttributesP::getIndex (const char *qName)
+{
+  for (int idx = 0; idx < names->size (); idx++)
+    if (strcmp (names->fetch (idx), qName) == 0)
+      return idx;
+  return -1;
+}
+
+const char *
+AttributesP::getValue (const char *qName)
+{
+  for (int idx = 0; idx < names->size (); idx++)
+    if (strcmp (names->fetch (idx), qName) == 0)
+      return values->fetch (idx);
+  return NULL;
+}
+
+void
+AttributesP::append (char *qName, char *value)
+{
+  names->append (qName);
+  values->append (value);
+}
+
+/*
+ *  Implementation of SAXException
+ */
+SAXException::SAXException ()
+{
+  message = strdup ("null");
+}
+
+SAXException::SAXException (const char *_message)
+{
+  if (_message == NULL)
+    message = strdup ("null");
+  else
+    message = strdup (_message);
+}
+
+SAXException::~SAXException ()
+{
+  free (message);
+}
+
+char *
+SAXException::getMessage ()
+{
+  return message;
+}
+
+/*
+ *  SAXParseException
+ */
+SAXParseException::SAXParseException (char *message, int _lineNumber, int _columnNumber)
+: SAXException (message == NULL ? GTXT ("XML parse error") : message)
+{
+  lineNumber = _lineNumber;
+  columnNumber = _columnNumber;
+}
+
+/*
+ *  Private implementation of SAXParser
+ */
+class SAXParserP : public SAXParser
+{
+public:
+  SAXParserP ();
+  ~SAXParserP ();
+  void reset ();
+  void parse (File*, DefaultHandler*);
+
+  bool
+  isNamespaceAware ()
+  {
+    return false;
+  }
+
+  bool
+  isValidating ()
+  {
+    return false;
+  }
+
+private:
+
+  static const int CH_EOF = -1;
+
+  void nextch ();
+  bool isWSpace ();
+  void skipWSpaces ();
+  void scanString (const char *str);
+  char *parseName ();
+  char *parseString ();
+  char *decodeString (char *str);
+  Attributes *parseAttributes ();
+  void parseTag ();
+  void parseDocument ();
+  void parsePart (int idx);
+
+  DefaultHandler *dh;
+  int bufsz;
+  char *buffer;
+  int cntsz;
+  int idx;
+  int curch;
+  int line;
+  int column;
+};
+
+SAXParserP::SAXParserP ()
+{
+  dh = NULL;
+  bufsz = 0x2000;
+  buffer = (char*) malloc (bufsz);
+  cntsz = 0;
+  idx = 0;
+  line = 1;
+  column = 0;
+}
+
+SAXParserP::~SAXParserP ()
+{
+  free (buffer);
+}
+
+void
+SAXParserP::reset ()
+{
+  dh = NULL;
+  bufsz = 8192;
+  buffer = (char*) realloc (buffer, bufsz);
+  cntsz = 0;
+  idx = 0;
+  line = 1;
+  column = 0;
+}
+
+void
+SAXParserP::parse (File *f, DefaultHandler *_dh)
+{
+  if (_dh == NULL)
+    return;
+  dh = _dh;
+  FILE *file = (FILE*) f;
+  int rem = bufsz;
+  cntsz = 0;
+  idx = 0;
+  for (;;)
+    {
+      int n = (int) fread (buffer + cntsz, 1, rem, file);
+      if (ferror (file) || n <= 0)
+       break;
+      cntsz += n;
+      if (feof (file))
+       break;
+      rem -= n;
+      if (rem == 0)
+       {
+         int oldbufsz = bufsz;
+         bufsz = bufsz >= 0x100000 ? bufsz + 0x100000 : bufsz * 2;
+         buffer = (char*) realloc (buffer, bufsz);
+         rem = bufsz - oldbufsz;
+       }
+    }
+  nextch ();
+  parseDocument ();
+}
+
+static int
+hex (char c)
+{
+  if (c >= '0' && c <= '9')
+    return (c - '0');
+  else if (c >= 'a' && c <= 'f')
+      return 10 + (c - 'a');
+  return -1;
+}
+
+void
+SAXParserP::nextch ()
+{
+  curch = idx >= cntsz ? CH_EOF : buffer[idx++];
+  if (curch == '\n')
+    {
+      line += 1;
+      column = 0;
+    }
+  else
+    column += 1;
+}
+
+bool
+SAXParserP::isWSpace ()
+{
+  return curch == ' ' || curch == '\t' || curch == '\n' || curch == '\r';
+}
+
+void
+SAXParserP::skipWSpaces ()
+{
+  while (isWSpace ())
+    nextch ();
+}
+
+void
+SAXParserP::scanString (const char *str)
+{
+  if (str == NULL || *str == '\0')
+    return;
+  for (;;)
+    {
+      if (curch == CH_EOF)
+       break;
+      else if (curch == *str)
+       {
+         const char *p = str;
+         for (;;)
+           {
+             p += 1;
+             nextch ();
+             if (*p == '\0')
+               return;
+             if (curch != *p)
+               break;
+           }
+       }
+      nextch ();
+    }
+}
+
+char *
+SAXParserP::parseName ()
+{
+  StringBuilder *name = new StringBuilder ();
+
+  if ((curch >= 'A' && curch <= 'Z') || (curch >= 'a' && curch <= 'z'))
+    {
+      name->append ((char) curch);
+      nextch ();
+      while (isalnum (curch) != 0 || curch == '_')
+       {
+         name->append ((char) curch);
+         nextch ();
+       }
+    }
+
+  char *res = name->toString ();
+  delete name;
+  return res;
+}
+
+/**
+ * Replaces encoded XML characters with original characters
+ * Attention: this method reuses the same string that is passed as the argument
+ * @param str
+ * @return str
+ */
+char *
+SAXParserP::decodeString (char * str)
+{
+  // Check if string has %22% and replace it with double quotes
+  // Also replace all other special combinations.
+  char *from = str;
+  char *to = str;
+  if (strstr (from, "%") || strstr (from, "&"))
+    {
+      int len = strlen (from);
+      for (int i = 0; i < len; i++)
+       {
+         int nch = from[i];
+         // Process &...; combinations
+         if (nch == '&' && i + 3 < len)
+           {
+             if (from[i + 2] == 't' && from[i + 3] == ';')
+               {
+                 // check &lt; &gt;
+                 if (from[i + 1] == 'l')
+                   {
+                     nch = '<';
+                     i += 3;
+                   }
+                 else if (from[i + 1] == 'g')
+                   {
+                     nch = '>';
+                     i += 3;
+                   }
+               }
+             else if (i + 4 < len && from[i + 4] == ';')
+               {
+                 // check &amp;
+                 if (from[i + 1] == 'a' && from[i + 2] == 'm' && from[i + 3] == 'p')
+                   {
+                     nch = '&';
+                     i += 4;
+                   }
+               }
+             else if ((i + 5 < len) && (from[i + 5] == ';'))
+               {
+                 // check &apos; &quot;
+                 if (from[i + 1] == 'a' && from[i + 2] == 'p'
+                     && from[i + 3] == 'o' && from[i + 4] == 's')
+                   {
+                     nch = '\'';
+                     i += 5;
+                   }
+                 if (from[i + 1] == 'q' && from[i + 2] == 'u' && from[i + 3] == 'o' && from[i + 4] == 't')
+                   {
+                     nch = '"';
+                     i += 5;
+                   }
+               }
+           }
+         // Process %XX% combinations
+         if (nch == '%' && i + 3 < len && from[i + 3] == '%')
+           {
+             int ch = hex (from[i + 1]);
+             if (ch >= 0)
+               {
+                 int ch2 = hex (from[i + 2]);
+                 if (ch2 >= 0)
+                   {
+                     ch = ch * 16 + ch2;
+                     nch = ch;
+                     i += 3;
+                   }
+               }
+           }
+         *to++ = (char) nch;
+       }
+      *to = '\0';
+    }
+  return str;
+}
+
+char *
+SAXParserP::parseString ()
+{
+  StringBuilder *str = new StringBuilder ();
+  int quote = '>';
+  if (curch == '"')
+    {
+      quote = curch;
+      nextch ();
+    }
+  for (;;)
+    {
+      if (curch == CH_EOF)
+       break;
+      if (curch == quote)
+       {
+         nextch ();
+         break;
+       }
+      str->append ((char) curch);
+      nextch ();
+    }
+
+  char *res = str->toString ();
+  // Decode XML characters
+  res = decodeString (res);
+  delete str;
+  return res;
+}
+
+Attributes *
+SAXParserP::parseAttributes ()
+{
+  AttributesP *attrs = new AttributesP ();
+
+  for (;;)
+    {
+      skipWSpaces ();
+      char *name = parseName ();
+      if (name == NULL || *name == '\0')
+       {
+         free (name);
+         break;
+       }
+      skipWSpaces ();
+      if (curch != '=')
+       {
+         SAXParseException *e = new SAXParseException (NULL, line, column);
+         dh->error (e);
+         scanString (">");
+         free (name);
+         return attrs;
+       }
+      nextch ();
+      skipWSpaces ();
+      char *value = parseString ();
+      attrs->append (name, value);
+    }
+  return attrs;
+}
+
+void
+SAXParserP::parseTag ()
+{
+  skipWSpaces ();
+  bool empty = false;
+  char *name = parseName ();
+  if (name == NULL || *name == '\0')
+    {
+      SAXParseException *e = new SAXParseException (NULL, line, column);
+      dh->error (e);
+      scanString (">");
+      free (name);
+      return;
+    }
+
+  Attributes *attrs = parseAttributes ();
+  if (curch == '/')
+    {
+      nextch ();
+      empty = true;
+    }
+  if (curch == '>')
+    nextch ();
+  else
+    {
+      empty = false;
+      SAXParseException *e = new SAXParseException (NULL, line, column);
+      dh->error (e);
+      scanString (">");
+    }
+  if (curch == CH_EOF)
+    {
+      free (name);
+      delete attrs;
+      return;
+    }
+  dh->startElement (NULL, NULL, name, attrs);
+  if (empty)
+    {
+      dh->endElement (NULL, NULL, name);
+      free (name);
+      delete attrs;
+      return;
+    }
+
+  StringBuilder *chars = new StringBuilder ();
+  bool wspaces = true;
+  for (;;)
+    {
+      if (curch == CH_EOF)
+       break;
+      else if (curch == '<')
+       {
+         if (chars->length () > 0)
+           {
+             char *str = chars->toString ();
+             // Decode XML characters
+             str = decodeString (str);
+             if (wspaces)
+               dh->ignorableWhitespace (str, 0, chars->length ());
+             else
+               dh->characters (str, 0, chars->length ());
+             free (str);
+             chars->setLength (0);
+             wspaces = true;
+           }
+         nextch ();
+         if (curch == '/')
+           {
+             nextch ();
+             char *ename = parseName ();
+             if (ename && *ename != '\0')
+               {
+                 if (strcmp (name, ename) == 0)
+                   {
+                     skipWSpaces ();
+                     if (curch == '>')
+                       {
+                         nextch ();
+                         dh->endElement (NULL, NULL, name);
+                         free (ename);
+                         break;
+                       }
+                     SAXParseException *e = new SAXParseException (NULL, line, column);
+                     dh->error (e);
+                   }
+                 else
+                   {
+                     SAXParseException *e = new SAXParseException (NULL, line, column);
+                     dh->error (e);
+                   }
+                 scanString (">");
+               }
+             free (ename);
+           }
+         else
+           parseTag ();
+       }
+      else
+       {
+         if (!isWSpace ())
+           wspaces = false;
+         chars->append ((char) curch);
+         nextch ();
+       }
+    }
+
+  free (name);
+  delete attrs;
+  delete chars;
+  return;
+}
+
+void
+SAXParserP::parseDocument ()
+{
+  dh->startDocument ();
+  for (;;)
+    {
+      if (curch == CH_EOF)
+       break;
+      if (curch == '<')
+       {
+         nextch ();
+         if (curch == '?')
+           scanString ("?>");
+         else if (curch == '!')
+           scanString (">");
+         else
+           parseTag ();
+       }
+      else
+       nextch ();
+    }
+  dh->endDocument ();
+}
+
+/*
+ *  Private implementation of SAXParserFactory
+ */
+class SAXParserFactoryP : public SAXParserFactory
+{
+public:
+  SAXParserFactoryP () { }
+  ~SAXParserFactoryP () { }
+  SAXParser *newSAXParser ();
+
+  void
+  setFeature (const char *, bool) { }
+
+  bool
+  getFeature (const char *)
+  {
+    return false;
+  }
+};
+
+SAXParser *
+SAXParserFactoryP::newSAXParser ()
+{
+  return new SAXParserP ();
+}
+
+/*
+ *  SAXParserFactory
+ */
+const char *SAXParserFactory::DEFAULT_PROPERTY_NAME = "javax.xml.parsers.SAXParserFactory";
+
+SAXParserFactory *
+SAXParserFactory::newInstance ()
+{
+  return new SAXParserFactoryP ();
+}
+
+void
+DefaultHandler::dump_startElement (const char *qName, Attributes *attrs)
+{
+  fprintf (stderr, NTXT ("DefaultHandler::startElement qName='%s'\n"), STR (qName));
+  for (int i = 0, sz = attrs ? attrs->getLength () : 0; i < sz; i++)
+    {
+      const char *qn = attrs->getQName (i);
+      const char *vl = attrs->getValue (i);
+      fprintf (stderr, NTXT ("  %d  '%s' = '%s'\n"), i, STR (qn), STR (vl));
+    }
+}
diff --git a/gprofng/src/SAXParserFactory.h b/gprofng/src/SAXParserFactory.h
new file mode 100644 (file)
index 0000000..8e2c366
--- /dev/null
@@ -0,0 +1,75 @@
+/* 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.  */
+
+/*
+ *     javax/xml/parsers/SAXParserFactory.java
+ *
+ *     Based on JavaTM 2 Platform Standard Ed. 5.0
+ */
+
+#ifndef _SAXParserFactory_h
+#define _SAXParserFactory_h
+
+class SAXParser;
+
+class SAXParserFactory
+{
+public:
+  static SAXParserFactory *newInstance ();
+
+  virtual ~SAXParserFactory () { }
+  virtual SAXParser *newSAXParser () = 0;
+  virtual void setFeature (const char *name, bool value) = 0;
+  virtual bool getFeature (const char *name) = 0;
+
+  void
+  setNamespaceAware (bool awareness)
+  {
+    namespaceAware = awareness;
+  }
+
+  void
+  setValidating (bool _validating)
+  {
+    validating = _validating;
+  }
+
+  bool
+  isNamespaceAware ()
+  {
+    return namespaceAware;
+  }
+
+  bool
+  isValidating ()
+  {
+    return validating;
+  }
+
+protected:
+  SAXParserFactory () { }
+
+private:
+  static const char *DEFAULT_PROPERTY_NAME;
+  bool validating;
+  bool namespaceAware;
+};
+
+#endif /* _SAXParserFactory_h */
diff --git a/gprofng/src/Sample.cc b/gprofng/src/Sample.cc
new file mode 100644 (file)
index 0000000..7c00334
--- /dev/null
@@ -0,0 +1,94 @@
+/* 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 <assert.h>
+#include "Sample.h"
+#include "util.h"
+#include "Exp_Layout.h"
+
+Sample::Sample (int num)
+{
+  number = num;
+  prusage = NULL;
+  start_time = end_time = 0;
+  start_label = end_label = NULL;
+  validated = false;
+}
+
+Sample::~Sample ()
+{
+  delete prusage;
+  free (start_label);
+  free (end_label);
+}
+
+PrUsage *
+Sample::get_usage ()
+{
+  if (validated == false)
+    {
+      validate_usage ();
+      validated = true;
+    }
+  return prusage;
+}
+
+void
+Sample::validate_usage ()
+{
+  if (prusage == NULL || validated)
+    return;
+  validated = true;
+
+  // Make sure that none of the times are negative, force to zero if so
+  if (prusage->pr_utime < 0)
+    prusage->pr_utime = 0;
+  if (prusage->pr_stime < 0)
+    prusage->pr_stime = 0;
+  if (prusage->pr_ttime < 0)
+    prusage->pr_ttime = 0;
+  if (prusage->pr_tftime < 0)
+    prusage->pr_tftime = 0;
+  if (prusage->pr_dftime < 0)
+    prusage->pr_dftime = 0;
+  if (prusage->pr_kftime < 0)
+    prusage->pr_kftime = 0;
+  if (prusage->pr_ltime < 0)
+    prusage->pr_ltime = 0;
+  if (prusage->pr_slptime < 0)
+    prusage->pr_slptime = 0;
+  if (prusage->pr_wtime < 0)
+    prusage->pr_wtime = 0;
+  if (prusage->pr_stoptime < 0)
+    prusage->pr_stoptime = 0;
+  if (prusage->pr_rtime < 0)
+    prusage->pr_rtime = 0;
+
+  // Now make sure that the sum of states is >= prusage->pr_rtime
+  hrtime_t sum = prusage->pr_utime + prusage->pr_stime + prusage->pr_ttime
+         + prusage->pr_tftime + prusage->pr_dftime + prusage->pr_kftime
+         + prusage->pr_ltime + prusage->pr_slptime + prusage->pr_wtime
+         + prusage->pr_stoptime;
+
+  sum = sum - prusage->pr_rtime;
+  if (sum < 0)// increment sleep time to make it match
+    prusage->pr_slptime = prusage->pr_slptime - sum;
+}
diff --git a/gprofng/src/Sample.h b/gprofng/src/Sample.h
new file mode 100644 (file)
index 0000000..312bdcc
--- /dev/null
@@ -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.  */
+
+#ifndef _SAMPLE_H
+#define _SAMPLE_H
+
+// A data Sample object represents a single sample's worth of data.  This
+// object is private and is only used by Experiment and Sample_sel.
+
+#include "dbe_types.h"
+
+class PrUsage;
+
+class Sample
+{
+  friend class Experiment; // see post_process(), read_overview_file()
+public:
+  Sample (int num);
+  ~Sample ();
+  PrUsage *get_usage ();
+
+  char *
+  get_start_label ()
+  {
+    return start_label;
+  }
+
+  char *
+  get_end_label ()
+  {
+    return end_label;
+  }
+
+  hrtime_t
+  get_start_time ()
+  {
+    return start_time;
+  }
+
+  hrtime_t
+  get_end_time ()
+  {
+    return end_time;
+  }
+
+  int
+  get_number ()
+  {
+    return number;
+  }
+
+private:
+  void validate_usage ();   // Make sure usage data is consistent
+  bool validated;           // if validation performed
+  char *start_label;        // sample start label
+  char *end_label;          // sample end label
+  hrtime_t start_time;      // sample start time
+  hrtime_t end_time;        // sample end time
+  PrUsage *prusage;         // process usage data
+  int number;               // sample number
+};
+
+#endif /* _SAMPLE_H */
diff --git a/gprofng/src/SegMem.h b/gprofng/src/SegMem.h
new file mode 100644 (file)
index 0000000..fbfe727
--- /dev/null
@@ -0,0 +1,76 @@
+/* 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 _SEGMEM_H
+#define _SEGMEM_H
+
+#include "dbe_types.h"
+class Histable;
+
+class SegMem
+{
+public:
+
+  // The various segments types.
+  enum Seg_mode
+  {
+    READ,
+    WRITE,
+    EXEC,
+    UNKNOWN
+  };
+
+  void
+  set_file_offset (uint64_t fo)
+  {
+    file_offset = fo;
+  }
+
+  uint64_t
+  get_file_offset ()
+  {
+    return file_offset;
+  }
+
+  void
+  set_mode (Seg_mode sm)
+  {
+    mode = sm;
+  }
+
+  Seg_mode
+  get_mode ()
+  {
+    return mode;
+  }
+
+  Size size;            // Size of this instance
+  Histable *obj;        // Pointer to Segment/Function object
+  Vaddr base;           // Base address
+  hrtime_t load_time;
+  hrtime_t unload_time;
+  Size page_size;
+
+private:
+  uint64_t file_offset;
+  Seg_mode mode;
+};
+
+#endif /* _SEGMEM_H */
diff --git a/gprofng/src/Settings.cc b/gprofng/src/Settings.cc
new file mode 100644 (file)
index 0000000..965b917
--- /dev/null
@@ -0,0 +1,1586 @@
+/* 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 <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/param.h>
+
+#include "enums.h"
+#include "Settings.h"
+#include "DbeSession.h"
+#include "Command.h"
+#include "Application.h"
+#include "MemorySpace.h"
+#include "StringBuilder.h"
+#include "Table.h"
+#include "Emsg.h"
+#include "util.h"
+#include "i18n.h"
+
+// Commands for compiler commentary
+static const char *comp_cmd[] = {
+  NTXT ("basic"),
+  NTXT ("version"),
+  NTXT ("warn"),
+  NTXT ("parallel"),
+  NTXT ("query"),
+  NTXT ("loop"),
+  NTXT ("pipe"),
+  NTXT ("inline"),
+  NTXT ("memops"),
+  NTXT ("fe"),
+  NTXT ("codegen"),
+  NTXT ("src"),
+  NTXT ("asrc"),
+  NTXT ("nosrc"),
+  NTXT ("hex"),
+  NTXT ("nohex"),
+  NTXT ("threshold"),
+  NTXT ("cf")
+};
+
+static const int comp_vis[] = {
+  CCMV_BASIC,
+  CCMV_VER,
+  CCMV_WARN,
+  CCMV_PAR,
+  CCMV_QUERY,
+  CCMV_LOOP,
+  CCMV_PIPE,
+  CCMV_INLINE,
+  CCMV_MEMOPS,
+  CCMV_FE,
+  CCMV_CG,
+  COMP_SRC,
+  COMP_SRC_METRIC,
+  COMP_NOSRC,
+  COMP_HEX,
+  COMP_NOHEX,
+  COMP_THRESHOLD,
+  COMP_CMPLINE
+};
+
+const int comp_size = sizeof (comp_cmd) / sizeof (char *);
+
+// Commands for timeline
+typedef enum
+{
+  TLCMD_INVALID,
+  TLCMD_ENTITY_MODE,
+  TLCMD_ALIGN,
+  TLCMD_DEPTH
+} TLModeSubcommand;
+
+typedef struct
+{
+  const char * cmdText;
+  TLModeSubcommand cmdType;
+  int cmdId;
+} TLModeCmd;
+static const TLModeCmd tlmode_cmd[] = {
+  // MODE commands
+  {NTXT ("lwp"),        TLCMD_ENTITY_MODE, PROP_LWPID},
+  {NTXT ("thread"),     TLCMD_ENTITY_MODE, PROP_THRID},
+  {NTXT ("cpu"),        TLCMD_ENTITY_MODE, PROP_CPUID},
+  {NTXT ("experiment"), TLCMD_ENTITY_MODE, PROP_EXPID},
+  // ALIGN commands
+  {NTXT ("root"),       TLCMD_ALIGN, TLSTACK_ALIGN_ROOT},
+  {NTXT ("leaf"),       TLCMD_ALIGN, TLSTACK_ALIGN_LEAF},
+  // DEPTH commands
+  {NTXT ("depth"),      TLCMD_DEPTH, 0 /* don't care */}
+};
+
+static const int tlmode_size = sizeof (tlmode_cmd) / sizeof (TLModeCmd);
+
+// Constructor
+
+Settings::Settings (Application *_app)
+{
+  // Remember the application
+  app = _app;
+
+  // Clear all default strings
+  str_vmode = NULL;
+  str_en_desc = NULL;
+  str_datamode = NULL;
+  str_scompcom = NULL;
+  str_sthresh = NULL;
+  str_dcompcom = NULL;
+  str_dthresh = NULL;
+  str_dmetrics = NULL;
+  str_dsort = NULL;
+  str_tlmode = NULL;
+  str_tldata = NULL;
+  str_tabs = NULL;
+  str_rtabs = NULL;
+  str_search_path = NULL;
+  str_name_format = NULL;
+  str_limit = NULL;
+  str_printmode = NULL;
+  str_compare = NULL;
+  preload_libdirs = NULL;
+  pathmaps = new Vector<pathmap_t*>;
+  lo_expands = new Vector<lo_expand_t*>;
+  lo_expand_default = LIBEX_SHOW;
+  is_loexpand_default = true;
+  tabs_processed = false;
+
+  // set default-default values
+  name_format = Histable::NA;
+  view_mode = VMODE_USER;
+  en_desc = false;
+  en_desc_cmp = NULL;
+  en_desc_usr = NULL;
+  src_compcom = 2147483647;
+  dis_compcom = 2147483647;
+#define DEFAULT_SRC_DIS_THRESHOLD 75
+  threshold_src = DEFAULT_SRC_DIS_THRESHOLD;
+  threshold_dis = DEFAULT_SRC_DIS_THRESHOLD;
+  src_visible = true;
+  srcmetric_visible = false;
+  hex_visible = false;
+  cmpline_visible = true;
+  funcline_visible = true;
+  tldata = NULL;
+  tlmode = 0;
+  stack_align = 0;
+  stack_depth = 0;
+  limit = 0;
+  // print mode is initialized after the .rc files are read
+  print_delim = ',';
+  compare_mode = CMP_DISABLE;
+  machinemodel = NULL;
+  ignore_no_xhwcprof = false;
+  ignore_fs_warn = false;
+
+  // construct the master list of tabs
+  buildMasterTabList ();
+
+  indx_tab_state = new Vector<bool>;
+  indx_tab_order = new Vector<int>;
+  mem_tab_state = new Vector<bool>;
+  mem_tab_order = new Vector<int>;
+
+  // note that the .rc files are not read here, but later
+}
+
+// Constructor for duplicating an existing Settings class
+
+Settings::Settings (Settings * _settings)
+{
+  int index;
+  app = _settings->app;
+
+  // Copy all default strings
+  str_vmode = dbe_strdup (_settings->str_vmode);
+  str_en_desc = dbe_strdup (_settings->str_en_desc);
+  str_datamode = dbe_strdup (_settings->str_datamode);
+  str_scompcom = dbe_strdup (_settings->str_scompcom);
+  str_sthresh = dbe_strdup (_settings->str_sthresh);
+  str_dcompcom = dbe_strdup (_settings->str_dcompcom);
+  str_dthresh = dbe_strdup (_settings->str_dthresh);
+  str_dmetrics = dbe_strdup (_settings->str_dmetrics);
+  str_dsort = dbe_strdup (_settings->str_dsort);
+  str_tlmode = dbe_strdup (_settings->str_tlmode);
+  str_tldata = dbe_strdup (_settings->str_tldata);
+  str_tabs = dbe_strdup (_settings->str_tabs);
+  str_rtabs = dbe_strdup (_settings->str_rtabs);
+  str_search_path = dbe_strdup (_settings->str_search_path);
+  str_name_format = dbe_strdup (_settings->str_name_format);
+  str_limit = dbe_strdup (_settings->str_limit);
+  str_printmode = dbe_strdup (_settings->str_printmode);
+  str_compare = dbe_strdup (_settings->str_compare);
+  preload_libdirs = dbe_strdup (_settings->preload_libdirs);
+
+  // replicate the pathmap vector
+  pathmap_t *thismap;
+  pathmap_t *newmap;
+  pathmaps = new Vector<pathmap_t*>;
+
+  Vec_loop (pathmap_t*, _settings->pathmaps, index, thismap)
+  {
+    newmap = new pathmap_t;
+    newmap->old_prefix = dbe_strdup (thismap->old_prefix);
+    newmap->new_prefix = dbe_strdup (thismap->new_prefix);
+    pathmaps->append (newmap);
+  }
+
+  // replicate the lo_expand vector and default
+  lo_expand_t *this_lo_ex;
+  lo_expand_t *new_lo_ex;
+  lo_expand_default = _settings->lo_expand_default;
+  is_loexpand_default = _settings->is_loexpand_default;
+  lo_expands = new Vector<lo_expand_t*>;
+
+  Vec_loop (lo_expand_t*, _settings->lo_expands, index, this_lo_ex)
+  {
+    new_lo_ex = new lo_expand_t;
+    new_lo_ex->libname = dbe_strdup (this_lo_ex->libname);
+    new_lo_ex->expand = this_lo_ex->expand;
+    lo_expands->append (new_lo_ex);
+  }
+  tabs_processed = _settings->tabs_processed;
+
+  // Copy the various values from the _settings instance
+  name_format = _settings->name_format;
+  view_mode = _settings->view_mode;
+  en_desc = false;
+  en_desc_cmp = NULL;
+  en_desc_usr = NULL;
+  if (_settings->en_desc_usr)
+    set_en_desc (_settings->en_desc_usr, true);
+  src_compcom = _settings->src_compcom;
+  dis_compcom = _settings->dis_compcom;
+  threshold_src = _settings->threshold_src;
+  threshold_dis = _settings->threshold_dis;
+  src_visible = _settings->src_visible;
+  srcmetric_visible = _settings->srcmetric_visible;
+  hex_visible = _settings->hex_visible;
+  cmpline_visible = _settings->cmpline_visible;
+  funcline_visible = _settings->funcline_visible;
+  tldata = dbe_strdup (_settings->tldata);
+  tlmode = _settings->tlmode;
+  stack_align = _settings->stack_align;
+  stack_depth = _settings->stack_depth;
+  limit = _settings->limit;
+  print_mode = _settings->print_mode;
+  print_delim = _settings->print_delim;
+  compare_mode = _settings->compare_mode;
+  machinemodel = dbe_strdup (_settings->machinemodel);
+  ignore_no_xhwcprof = _settings->ignore_no_xhwcprof;
+  ignore_fs_warn = _settings->ignore_fs_warn;
+
+  // copy the tab list, too
+  tab_list = new Vector<DispTab*>;
+  DispTab *dsptab;
+
+  Vec_loop (DispTab*, _settings->tab_list, index, dsptab)
+  {
+    DispTab *ntab;
+    ntab = new DispTab (dsptab->type, dsptab->order, dsptab->visible, dsptab->cmdtoken);
+    ntab->setAvailability (dsptab->available);
+    tab_list->append (ntab);
+  }
+
+  // construct the master list of memory tabs & copy order
+  index = _settings->mem_tab_state->size ();
+  mem_tab_state = new Vector<bool>(index);
+  mem_tab_order = new Vector<int>(index);
+  for (int i = 0; i < index; i++)
+    {
+      mem_tab_state->append (false);
+      mem_tab_order->append (_settings->mem_tab_order->fetch (i));
+    }
+
+  // construct the master list of index tabs & copy order
+  index = _settings->indx_tab_state->size ();
+  indx_tab_state = new Vector<bool>(index);
+  indx_tab_order = new Vector<int>(index);
+  for (int i = 0; i < index; i++)
+    indx_tab_order->append (_settings->indx_tab_order->fetch (i));
+  set_IndxTabState (_settings->indx_tab_state);
+}
+
+Settings::~Settings ()
+{
+  for (int i = 0; i < pathmaps->size (); ++i)
+    {
+      pathmap_t *pmap = pathmaps->fetch (i);
+      free (pmap->old_prefix);
+      free (pmap->new_prefix);
+      delete pmap;
+    }
+  delete pathmaps;
+
+  for (int i = 0; i < lo_expands->size (); ++i)
+    {
+      lo_expand_t *lo_ex = lo_expands->fetch (i);
+      free (lo_ex->libname);
+      delete lo_ex;
+    }
+  delete lo_expands;
+
+  tab_list->destroy ();
+  delete tab_list;
+  delete indx_tab_state;
+  delete indx_tab_order;
+  delete mem_tab_state;
+  delete mem_tab_order;
+
+  free (str_vmode);
+  free (str_en_desc);
+  free (str_datamode);
+  free (str_scompcom);
+  free (str_sthresh);
+  free (str_dcompcom);
+  free (str_dthresh);
+  free (str_dmetrics);
+  free (str_dsort);
+  free (str_tlmode);
+  free (str_tldata);
+  free (str_tabs);
+  free (str_rtabs);
+  free (str_search_path);
+  free (str_name_format);
+  free (str_limit);
+  free (str_compare);
+  free (str_printmode);
+  free (preload_libdirs);
+  free (tldata);
+  free (en_desc_usr);
+  if (en_desc_cmp)
+    {
+      regfree (en_desc_cmp);
+      delete en_desc_cmp;
+    }
+}
+
+/**
+ * Read .er.rc file from the specified location
+ * @param path
+ * @return
+ */
+char *
+Settings::read_rc (char *path)
+{
+  StringBuilder sb;
+  Emsgqueue *commentq = new Emsgqueue (NTXT ("setting_commentq"));
+
+  // Check file name
+  if (NULL == path)
+    return dbe_strdup (GTXT ("Error: empty file name"));
+  bool override = true;
+  set_rc (path, true, commentq, override);
+  Emsg *msg = commentq->fetch ();
+  while (msg != NULL)
+    {
+      char *str = msg->get_msg ();
+      sb.append (str);
+      msg = msg->next;
+    }
+  return sb.toString ();
+}
+
+void
+Settings::read_rc (bool ipc_or_rdt_mode)
+{
+  bool override = false;
+
+  // Read file from the current working directory
+  char *rc_path = realpath (NTXT ("./.gprofng.rc"), NULL);
+  if (rc_path)
+    set_rc (rc_path, true, app->get_comments_queue (), override, ipc_or_rdt_mode);
+
+  // Read file from the user's home directory
+  char *home = getenv (NTXT ("HOME"));
+  if (home)
+    {
+      char *strbuf = dbe_sprintf (NTXT ("%s/.gprofng.rc"), home);
+      char *home_rc_path = realpath (strbuf, NULL);
+      if (home_rc_path)
+       {
+         if (rc_path == NULL || strcmp (rc_path, home_rc_path) != 0)
+           set_rc (home_rc_path, true, app->get_comments_queue (), override, ipc_or_rdt_mode);
+         free (home_rc_path);
+       }
+      free (strbuf);
+    }
+  free (rc_path);
+
+  // Read system-wide file
+  rc_path = dbe_sprintf (NTXT ("%s/../etc/gprofng.rc"), app->get_run_dir ());
+  if (access (rc_path, R_OK | F_OK) != 0)
+    {
+      StringBuilder sb;
+      sb.sprintf (GTXT ("Warning: Default gprofng.rc file (%s) missing; configuration error "), rc_path);
+      Emsg *m = new Emsg (CMSG_COMMENT, sb);
+      app->get_comments_queue ()->append (m);
+    }
+  else
+    set_rc (rc_path, false, app->get_comments_queue (), override);
+  free (rc_path);
+  is_loexpand_default = true;
+  if (str_printmode == NULL)
+    {
+      // only if there's none set
+      print_mode = PM_TEXT;
+      str_printmode = dbe_strdup (NTXT ("text"));
+    }
+}
+
+
+//  Handle various settings from reading the name .rc file
+//     This function is called for each .rc file read, and, for
+//     some settings, it accumulates the strings from the files.
+//     For others, it accepts the first appearance for a setting in a
+//     .rc file, and ignores subsequent appearances from other files.
+//  Error messages are appended to the Emsgqueue specified by the caller
+
+#define MAXARGS 20
+
+void
+Settings::set_rc (const char *path, bool msg, Emsgqueue *commentq,
+                 bool override, bool ipc_or_rdt_mode)
+{
+  CmdType cmd_type;
+  int arg_count, cparam;
+  char *cmd, *end_cmd, *strbuf;
+  char *arglist[MAXARGS];
+  StringBuilder sb;
+
+  FILE *fptr = fopen (path, NTXT ("r"));
+  if (fptr == NULL)
+    return;
+
+  if (msg)
+    {
+      sb.sprintf (GTXT ("Processed %s for default settings"), path);
+      Emsg *m = new Emsg (CMSG_COMMENT, sb);
+      commentq->append (m);
+    }
+  int line_no = 0;
+  end_cmd = NULL;
+  while (!feof (fptr))
+    {
+      char *script = read_line (fptr);
+      if (script == NULL)
+       continue;
+      line_no++;
+      strtok (script, NTXT ("\n"));
+
+      // extract the command
+      cmd = strtok (script, NTXT (" \t"));
+      if (cmd == NULL || *cmd == '#' || *cmd == '\n')
+       {
+         free (script);
+         continue;
+       }
+      char *remainder = strtok (NULL, NTXT ("\n"));
+      // now extract the arguments
+      int nargs = 0;
+      for (;;)
+       {
+         if (nargs >= MAXARGS)
+           {
+             if (!msg)
+               {
+                 msg = true; // suppress repeats of header
+                 Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings"));
+                 commentq->append (m);
+               }
+             sb.sprintf (GTXT ("Warning: more than %d arguments to %s command, line %d\n"),
+                         MAXARGS, cmd, line_no);
+             Emsg *m = new Emsg (CMSG_COMMENT, sb);
+             commentq->append (m);
+             break;
+           }
+
+         char *nextarg = strtok (remainder, NTXT ("\n"));
+         if (nextarg == NULL || *nextarg == '#')
+           break;
+         arglist[nargs++] = parse_qstring (nextarg, &end_cmd);
+         remainder = end_cmd;
+         if (remainder == NULL)
+           break;
+         // skip any blanks or tabs to get to next argument
+         while (*remainder == ' ' || *remainder == '\t')
+           remainder++;
+       }
+      cmd_type = Command::get_command (cmd, arg_count, cparam);
+      // check for extra arguments
+      if ((cmd_type != UNKNOWN_CMD && cmd_type != INDXOBJDEF) && (nargs > arg_count))
+       {
+         if (!msg)
+           {
+             msg = true; // suppress repeats of header
+             Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings"));
+             commentq->append (m);
+           }
+         sb.sprintf (GTXT ("Warning: extra arguments to %s command, line %d\n"), cmd, line_no);
+         Emsg *m = new Emsg (CMSG_COMMENT, sb);
+         commentq->append (m);
+       }
+      if (nargs < arg_count)
+       {
+         if (!msg)
+           {
+             msg = true; // suppress repeats of header
+             Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings"));
+             commentq->append (m);
+           }
+         sb.sprintf (GTXT ("Error: missing arguments to %s command, line %d\n"),
+                     cmd, line_no);
+         Emsg *m = new Emsg (CMSG_COMMENT, sb);
+         commentq->append (m);
+
+         // ignore this command
+         free (script);
+         continue;
+       }
+      if (ipc_or_rdt_mode && (cmd_type != ADDPATH) && (cmd_type != PATHMAP))
+       {
+         free (script);
+         continue;
+       }
+      switch (cmd_type)
+       {
+       case SCOMPCOM:
+         if (!str_scompcom || override)
+           {
+             str_scompcom = dbe_strdup (arglist[0]);
+             proc_compcom (arglist[0], true, true);
+           }
+         break;
+       case STHRESH:
+         if (!str_sthresh || override)
+           {
+             str_sthresh = dbe_strdup (arglist[0]);
+             proc_thresh (arglist[0], true, true);
+             break;
+           }
+         break;
+       case DCOMPCOM:
+         if (!str_dcompcom || override)
+           {
+             str_dcompcom = dbe_strdup (arglist[0]);
+             proc_compcom (arglist[0], false, true);
+           }
+         break;
+       case COMPCOM:
+         // process as if it were for both source and disassembly
+         //    note that if it is set, subsequent SCOMPCOM and DCOMPCOM
+         //    will be ignored
+         if (!str_scompcom || override)
+           {
+             str_scompcom = dbe_strdup (arglist[0]);
+             proc_compcom (arglist[0], true, true);
+           }
+         if (!str_dcompcom || override)
+           {
+             str_dcompcom = dbe_strdup (arglist[0]);
+             proc_compcom (arglist[0], false, true);
+           }
+         break;
+       case DTHRESH:
+         if (!str_dthresh || override)
+           {
+             str_dthresh = dbe_strdup (arglist[0]);
+             proc_thresh (arglist[0], false, true);
+           }
+         break;
+       case DMETRICS:
+         // append new settings to old, if necessary
+         if (str_dmetrics)
+           {
+             char *name = strstr (str_dmetrics, ":name");
+             if (name == NULL)
+               strbuf = dbe_sprintf ("%s:%s", str_dmetrics, arglist[0]);
+             else
+               {
+                 char * next = strstr (name + 1, ":");
+                 if (next == NULL)
+                   {
+                     name[0] = '\0';
+                     strbuf = dbe_sprintf ("%s:%s:name", str_dmetrics, arglist[0]);
+                   }
+                 else
+                   strbuf = dbe_sprintf ("%s:%s", str_dmetrics, arglist[0]);
+               }
+             free (str_dmetrics);
+             str_dmetrics = strbuf;
+           }
+         else
+           str_dmetrics = dbe_strdup (arglist[0]);
+         break;
+       case DSORT:
+         // append new settings to old, if necessary
+         if (str_dsort)
+           {
+             strbuf = dbe_sprintf (NTXT ("%s:%s"), str_dsort, arglist[0]);
+             free (str_dsort);
+             str_dsort = strbuf;
+           }
+         else
+           str_dsort = dbe_strdup (arglist[0]);
+         break;
+       case TLMODE:
+         if (!str_tlmode || override)
+           {
+             str_tlmode = dbe_strdup (arglist[0]);
+             proc_tlmode (arglist[0], true);
+           }
+         break;
+       case TLDATA:
+         if (!str_tldata || override)
+           {
+             str_tldata = dbe_strdup (arglist[0]);
+             proc_tldata (arglist[0], true);
+           }
+         break;
+       case TABS:
+         if (!str_tabs || override)
+           // the string is processed later, after all .rc files are read
+           str_tabs = dbe_strdup (arglist[0]);
+         break;
+       case RTABS:
+         if (!str_rtabs || override)
+           // the string is processed later, after all .rc files are read
+           str_rtabs = dbe_strdup (arglist[0]);
+         break;
+       case ADDPATH:
+         if (str_search_path)
+           {
+             strbuf = dbe_sprintf (NTXT ("%s:%s"), str_search_path, arglist[0]);
+             free (str_search_path);
+             str_search_path = strbuf;
+           }
+         else
+           str_search_path = dbe_strdup (arglist[0]);
+         break;
+       case PATHMAP:
+         {
+           char *err = add_pathmap (pathmaps, arglist[0], arglist[1]);
+           free (err);     // XXX error is not reported
+           break;
+         }
+       case LIBDIRS:
+         if (preload_libdirs == NULL)
+           preload_libdirs = dbe_strdup (arglist[0]);
+         break;
+       case NAMEFMT:
+         if (name_format == Histable::NA)
+           set_name_format (arglist[0]);
+         break;
+       case VIEWMODE:
+         if (!str_vmode || override)
+           {
+             str_vmode = dbe_strdup (arglist[0]);
+             set_view_mode (arglist[0], true);
+           }
+         break;
+       case EN_DESC:
+         if (!str_en_desc || override)
+           {
+             str_en_desc = dbe_strdup (arglist[0]);
+             set_en_desc (arglist[0], true);
+           }
+         break;
+       case LIMIT:
+         if (!str_limit || override)
+           {
+             str_limit = dbe_strdup (arglist[0]);
+             set_limit (arglist[0], true);
+           }
+         break;
+       case PRINTMODE:
+         if (!str_printmode || override)
+           set_printmode (arglist[0]);
+         break;
+       case COMPARE:
+         if (!str_compare || override)
+           {
+             char *s = arglist[0];
+             if (s)
+               str_compare = dbe_strdup (s);
+             else
+               s = NTXT ("");
+             if (strcasecmp (s, NTXT ("OFF")) == 0
+                 || strcmp (s, NTXT ("0")) == 0)
+               set_compare_mode (CMP_DISABLE);
+             else if (strcasecmp (s, NTXT ("ON")) == 0
+                      || strcmp (s, NTXT ("1")) == 0)
+               set_compare_mode (CMP_ENABLE);
+             else if (strcasecmp (s, NTXT ("DELTA")) == 0)
+               set_compare_mode (CMP_DELTA);
+             else if (strcasecmp (s, NTXT ("RATIO")) == 0)
+               set_compare_mode (CMP_RATIO);
+             else
+               {
+                 sb.sprintf (GTXT ("   .er.rc:%d The argument of 'compare' should be 'on', 'off', 'delta', or 'ratio'"),
+                             (int) line_no);
+                 Emsg *m = new Emsg (CMSG_COMMENT, sb);
+                 commentq->append (m);
+               }
+           }
+         break;
+
+       case INDXOBJDEF:
+         {
+           char *ret = dbeSession->indxobj_define (arglist[0], NULL, arglist[1], (nargs >= 3) ? PTXT (arglist[2]) : NULL, (nargs >= 4) ? PTXT (arglist[3]) : NULL);
+           if (ret != NULL)
+             {
+               sb.sprintf (GTXT ("   %s: line %d `%s %s %s'\n"),
+                           ret, line_no, cmd, arglist[0], arglist[1]);
+               Emsg *m = new Emsg (CMSG_COMMENT, sb);
+               commentq->append (m);
+             }
+           break;
+         }
+#ifdef sparc
+         //XXX: should be conditional on the experiment ARCH, not dbe ARCH
+       case IGNORE_NO_XHWCPROF:
+         // ignore absence of -xhwcprof info for dataspace profiling
+         set_ignore_no_xhwcprof (true);
+         break;
+#endif // sparc
+       case IGNORE_FS_WARN:
+         // ignore file system warning in experiments
+         set_ignore_fs_warn (true);
+         break;
+       case OBJECT_SHOW:
+         // Add the named libraries to the lib_expands array
+         set_libexpand (arglist[0], LIBEX_SHOW, true);
+         break;
+       case OBJECT_HIDE:
+         // Add the named libraries to the lib_expands array
+         set_libexpand (arglist[0], LIBEX_HIDE, true);
+         break;
+       case OBJECT_API:
+         // Add the named libraries to the lib_expands array
+         set_libexpand (arglist[0], LIBEX_API, true);
+         break;
+       case COMMENT:
+         // ignore the line
+         break;
+       default:
+         {
+           // unexpected command in an rc file
+           if (!msg)
+             {
+               // if quiet, can remain so no longer
+               msg = true;
+               Emsg *m = new Emsg (CMSG_COMMENT, GTXT ("Processed system gprofng.rc file for default settings"));
+               commentq->append (m);
+             }
+           sb.sprintf (GTXT ("   Unrecognized .gprofng.rc command on line %d: `%.64s'"),
+                       line_no, cmd);
+           Emsg *m = new Emsg (CMSG_COMMENT, sb);
+           commentq->append (m);
+           break;
+         }
+       }
+      free (script);
+    }
+  fclose (fptr);
+}
+
+Cmd_status
+Settings::set_view_mode (char *arg, bool rc)
+{
+  if (!strcasecmp (arg, NTXT ("user")))
+    view_mode = VMODE_USER;
+  else if (!strcasecmp (arg, NTXT ("expert")))
+    view_mode = VMODE_EXPERT;
+  else if (!strcasecmp (arg, NTXT ("machine")))
+    view_mode = VMODE_MACHINE;
+  else if (!rc)
+    return CMD_BAD_ARG;
+  return CMD_OK;
+}
+
+Cmd_status
+Settings::set_en_desc (char *arg, bool rc)
+{
+  regex_t *regex_desc = NULL;
+
+  // cases below should be similar to Coll_Ctrl::set_follow_mode() cases
+  if (!strcasecmp (arg, NTXT ("on")))
+    en_desc = true;
+  else if (!strcasecmp (arg, NTXT ("off")))
+    en_desc = false;
+  else if (arg[0] == '=' && arg[1] != 0)
+    {
+      // user has specified a string matching specification
+      int ercode;
+      { // compile regex_desc
+       char * str = dbe_sprintf (NTXT ("^%s$"), arg + 1);
+       regex_desc = new regex_t;
+       memset (regex_desc, 0, sizeof (regex_t));
+       ercode = regcomp (regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+       free (str);
+      }
+      if (ercode)
+       {
+         // syntax error in parsing string
+         delete regex_desc;
+         if (!rc)
+           return CMD_BAD_ARG;
+         return CMD_OK;
+       }
+      en_desc = true;
+    }
+  else
+    {
+      if (!rc)
+       return CMD_BAD_ARG;
+      return CMD_OK;
+    }
+  free (en_desc_usr);
+  en_desc_usr = dbe_strdup (arg);
+  if (en_desc_cmp)
+    {
+      regfree (en_desc_cmp);
+      delete en_desc_cmp;
+    }
+  en_desc_cmp = regex_desc;
+  return CMD_OK;
+}
+
+// See if a descendant matches either the lineage or the executable name
+bool
+Settings::check_en_desc (const char *lineage, const char *targname)
+{
+  bool rc;
+  if (en_desc_cmp == NULL)
+    return en_desc;     // no specification was set, use the binary on/off value
+  if (lineage == NULL)  // user doesn't care about specification
+    return en_desc;     // use the binary on/off specification
+  if (!regexec (en_desc_cmp, lineage, 0, NULL, 0))
+    rc = true;          // this one matches user specification
+  else if (targname == NULL)
+    rc = false;         //a NULL name does not match any expression
+  else if (!regexec (en_desc_cmp, targname, 0, NULL, 0))
+    rc = true;          // this one matches the executable name
+  else
+    rc = false;
+  return rc;
+}
+
+char *
+Settings::set_limit (char *arg, bool)
+{
+  limit = (int) strtol (arg, (char **) NULL, 10);
+  return NULL;
+}
+
+char *
+Settings::set_printmode (char *arg)
+{
+  if (arg == NULL)
+    return dbe_sprintf (GTXT ("The argument to '%s' must be '%s' or '%s' or a single-character"),
+                       NTXT ("printmode"), NTXT ("text"), NTXT ("html"));
+  if (strlen (arg) == 1)
+    {
+      print_mode = PM_DELIM_SEP_LIST;
+      print_delim = arg[0];
+    }
+  else if (!strcasecmp (arg, NTXT ("text")))
+    print_mode = PM_TEXT;
+  else if (!strcasecmp (arg, NTXT ("html")))
+    print_mode = PM_HTML;
+  else
+    return dbe_sprintf (GTXT ("The argument to '%s' must be '%s' or '%s' or a single-character"),
+                       NTXT ("printmode"), NTXT ("text"), NTXT ("html"));
+  free (str_printmode);
+  str_printmode = dbe_strdup (arg);
+  return NULL;
+}
+
+Cmd_status
+Settings::proc_compcom (const char *cmd, bool isSrc, bool rc)
+{
+  int ck_compcom_bits, ck_threshold;
+  bool ck_hex_visible = false;
+  bool ck_src_visible = false;
+  bool ck_srcmetric_visible = false;
+  bool got_compcom_bits, got_threshold, got_src_visible, got_srcmetric_visible;
+  bool got_hex_visible, got;
+  int len, i;
+  char *mcmd, *param;
+  int flag, value = 0;
+  Cmd_status status;
+  char buf[BUFSIZ], *list;
+
+  if (cmd == NULL)
+    return CMD_BAD;
+  ck_compcom_bits = 0;
+  ck_threshold = 0;
+  got_compcom_bits = got_threshold = got_src_visible = false;
+  got_srcmetric_visible = got_hex_visible = false;
+  snprintf (buf, sizeof (buf), NTXT ("%s"), cmd);
+  list = buf;
+  while ((mcmd = strtok (list, NTXT (":"))) != NULL)
+    {
+      list = NULL;
+      // if "all" or "none"
+      if (!strcasecmp (mcmd, Command::ALL_CMD))
+       {
+         got_compcom_bits = true;
+         ck_compcom_bits = CCMV_ALL;
+         continue;
+       }
+      else if (!strcasecmp (mcmd, Command::NONE_CMD))
+       {
+         got_compcom_bits = true;
+         ck_compcom_bits = 0;
+         continue;
+       }
+
+      // Find parameter after '='
+      param = strchr (mcmd, '=');
+      if (param)
+       {
+         *param = '\0';
+         param++;
+       }
+      status = CMD_OK;
+      got = false;
+      flag = 0;
+      len = (int) strlen (mcmd);
+      for (i = 0; status == CMD_OK && i < comp_size; i++)
+       if (!strncasecmp (mcmd, comp_cmd[i], len))
+         {
+           if (got) // Ambiguous comp_com command
+             status = CMD_AMBIGUOUS;
+           else
+             {
+               got = true;
+               flag = comp_vis[i];
+               // Check argument
+               if (flag == COMP_THRESHOLD)
+                 {
+                   if (param == NULL)
+                     status = CMD_BAD_ARG;
+                   else
+                     {
+                       value = (int) strtol (param, &param, 10);
+                       if (value < 0 || value > 100)
+                         status = CMD_OUTRANGE;
+                     }
+                 }
+               else if (param != NULL)
+                 status = CMD_BAD_ARG;
+             }
+         }
+
+      // Not valid comp_com command
+      if (!got)
+       status = CMD_INVALID;
+      if (status != CMD_OK)
+       {
+         if (!rc)
+           return status;
+         continue;
+       }
+
+      // Set bits
+      switch (flag)
+       {
+       case COMP_CMPLINE:
+         cmpline_visible = true;
+         break;
+       case COMP_FUNCLINE:
+         funcline_visible = true;
+         break;
+       case COMP_THRESHOLD:
+         got_threshold = true;
+         ck_threshold = value;
+         break;
+       case COMP_SRC:
+         got_src_visible = true;
+         ck_src_visible = true;
+         break;
+       case COMP_SRC_METRIC:
+         got_srcmetric_visible = true;
+         ck_srcmetric_visible = true;
+         got_src_visible = true;
+         ck_src_visible = true;
+         break;
+       case COMP_NOSRC:
+         got_src_visible = true;
+         ck_src_visible = false;
+         break;
+       case COMP_HEX:
+         got_hex_visible = true;
+         ck_hex_visible = true;
+         break;
+       case COMP_NOHEX:
+         got_hex_visible = true;
+         ck_hex_visible = false;
+         break;
+       case CCMV_BASIC:
+         got_compcom_bits = true;
+         ck_compcom_bits = CCMV_BASIC;
+         break;
+       default:
+         got_compcom_bits = true;
+         ck_compcom_bits |= flag;
+       }
+    }
+
+  // No error, update
+  if (got_compcom_bits)
+    {
+      if (isSrc)
+       src_compcom = ck_compcom_bits;
+      else
+       dis_compcom = ck_compcom_bits;
+    }
+  if (got_threshold)
+    {
+      if (isSrc)
+       threshold_src = ck_threshold;
+      else
+       threshold_dis = ck_threshold;
+    }
+  if (got_src_visible)
+      src_visible = ck_src_visible;
+  if (got_srcmetric_visible)
+      srcmetric_visible = ck_srcmetric_visible;
+  if (got_hex_visible)
+      hex_visible = ck_hex_visible;
+  return CMD_OK;
+}
+
+// Process a threshold setting
+Cmd_status
+Settings::proc_thresh (char *cmd, bool isSrc, bool rc)
+{
+  int value;
+  if (cmd == NULL)
+    value = DEFAULT_SRC_DIS_THRESHOLD; // the default
+  else
+    value = (int) strtol (cmd, &cmd, 10);
+  if (value < 0 || value > 100)
+    {
+      if (!rc)
+       return CMD_OUTRANGE;
+      value = DEFAULT_SRC_DIS_THRESHOLD;
+    }
+  if (isSrc)
+    threshold_src = value;
+  else
+    threshold_dis = value;
+  return CMD_OK;
+}
+
+// return any error string from processing visibility settings
+char *
+Settings::get_compcom_errstr (Cmd_status status, const char *cmd)
+{
+  int i;
+  StringBuilder sb;
+  switch (status)
+    {
+    case CMD_BAD:
+      sb.append (GTXT ("No commentary classes has been specified."));
+      break;
+    case CMD_AMBIGUOUS:
+      sb.append (GTXT ("Ambiguous commentary classes: "));
+      break;
+    case CMD_BAD_ARG:
+      sb.append (GTXT ("Invalid argument for commentary classes: "));
+      break;
+    case CMD_OUTRANGE:
+      sb.append (GTXT ("Out of range commentary classes argument: "));
+      break;
+    case CMD_INVALID:
+      sb.append (GTXT ("Invalid commentary classes: "));
+      break;
+    case CMD_OK:
+      break;
+    }
+  if (cmd)
+    sb.append (cmd);
+  sb.append (GTXT ("\nAvailable commentary classes: "));
+  for (i = 0; i < comp_size; i++)
+    {
+      sb.append (comp_cmd[i]);
+      if (i == comp_size - 1)
+       sb.append (NTXT ("=#\n"));
+      else
+       sb.append (NTXT (":"));
+    }
+  return sb.toString ();
+}
+
+// Process a timeline-mode setting
+Cmd_status
+Settings::proc_tlmode (char *cmd, bool rc)
+{
+  bool got_tlmode, got_stack_align, got_stack_depth, got;
+  int ck_tlmode = 0, ck_stack_align = 0, ck_stack_depth = 0;
+  int len, i;
+  char *mcmd, *param;
+  int cmd_id, value = 0;
+  TLModeSubcommand cmd_type;
+  Cmd_status status;
+  char buf[BUFSIZ], *list;
+  if (cmd == NULL)
+    return CMD_BAD;
+  got_tlmode = got_stack_align = got_stack_depth = false;
+  snprintf (buf, sizeof (buf), NTXT ("%s"), cmd);
+  list = buf;
+  while ((mcmd = strtok (list, NTXT (":"))) != NULL)
+    {
+      list = NULL;
+
+      // Find parameter after '='
+      param = strchr (mcmd, '=');
+      if (param)
+       {
+         *param = '\0';
+         param++;
+       }
+      status = CMD_OK;
+      got = false;
+      cmd_id = 0;
+      cmd_type = TLCMD_INVALID;
+      len = (int) strlen (mcmd);
+      for (i = 0; status == CMD_OK && i < tlmode_size; i++)
+       {
+         if (!strncasecmp (mcmd, tlmode_cmd[i].cmdText, len))
+           {
+             if (got) // Ambiguous timeline mode
+               status = CMD_AMBIGUOUS;
+             else
+               {
+                 got = true;
+                 cmd_type = tlmode_cmd[i].cmdType;
+                 cmd_id = tlmode_cmd[i].cmdId;
+
+                 // Check argument
+                 if (cmd_type == TLCMD_DEPTH)
+                   {
+                     if (param == NULL)
+                       status = CMD_BAD_ARG;
+                     else
+                       {
+                         value = (int) strtol (param, &param, 10);
+                         if (value <= 0 || value > 256)
+                           status = CMD_OUTRANGE;
+                       }
+                   }
+                 else if (param != NULL)
+                   status = CMD_BAD_ARG;
+               }
+           }
+       }
+
+      // Not valid timeline mode
+      if (!got)
+       status = CMD_INVALID;
+      if (status != CMD_OK)
+       {
+         if (!rc)
+           return status;
+         continue;
+       }
+
+      // Set bits
+      switch (cmd_type)
+       {
+       case TLCMD_ENTITY_MODE:
+         got_tlmode = true;
+         ck_tlmode = cmd_id;
+         break;
+       case TLCMD_ALIGN:
+         got_stack_align = true;
+         ck_stack_align = cmd_id;
+         break;
+       case TLCMD_DEPTH:
+         got_stack_depth = true;
+         ck_stack_depth = value;
+         break;
+       default:
+         break;
+       }
+    }
+
+  // No error, update
+  if (got_tlmode)
+    tlmode = ck_tlmode;
+  if (got_stack_align)
+    stack_align = ck_stack_align;
+  if (got_stack_depth)
+    stack_depth = ck_stack_depth;
+  return CMD_OK;
+}
+
+// Process timeline data specification
+Cmd_status
+Settings::proc_tldata (const char *cmd, bool /* if true, ignore any error */)
+{
+  free (tldata);
+  tldata = dbe_strdup (cmd); // let GUI parse it
+  return CMD_OK;
+}
+
+void
+Settings::set_tldata (const char* _tldata_str)
+{
+  free (tldata);
+  tldata = dbe_strdup (_tldata_str);
+}
+
+char*
+Settings::get_tldata ()
+{
+  return dbe_strdup (tldata);
+}
+
+Cmd_status
+Settings::set_name_format (char *arg)
+{
+  char *colon = strchr (arg, ':');
+  size_t arg_len = (colon) ? (colon - arg) : strlen (arg);
+  Histable::NameFormat fname_fmt = Histable::NA;
+  if (!strncasecmp (arg, NTXT ("long"), arg_len))
+    fname_fmt = Histable::LONG;
+  else if (!strncasecmp (arg, NTXT ("short"), arg_len))
+    fname_fmt = Histable::SHORT;
+  else if (!strncasecmp (arg, NTXT ("mangled"), arg_len))
+    fname_fmt = Histable::MANGLED;
+  else
+    return CMD_BAD_ARG;
+
+  bool soname_fmt = false;
+  if (colon && (colon + 1))
+    {
+      colon++;
+      if (!strcasecmp (colon, NTXT ("soname")))
+       soname_fmt = true;
+      else if (!strcasecmp (colon, NTXT ("nosoname")))
+       soname_fmt = false;
+      else
+       return CMD_BAD_ARG;
+    }
+  name_format = Histable::make_fmt (fname_fmt, soname_fmt);
+  return CMD_OK;
+}
+
+void
+Settings::buildMasterTabList ()
+{
+  tab_list = new Vector<DispTab*>;
+  int i = -1;
+
+  // Add tabs for all the known reports
+  tab_list->append (new DispTab (DSP_DEADLOCKS, i, false, DEADLOCK_EVNTS));
+  tab_list->append (new DispTab (DSP_FUNCTION, i, false, FUNCS));
+  tab_list->append (new DispTab (DSP_TIMELINE, i, false, TIMELINE));
+  tab_list->append (new DispTab (DSP_CALLTREE, i, false, CALLTREE));
+  tab_list->append (new DispTab (DSP_CALLFLAME, i, false, CALLFLAME));
+  tab_list->append (new DispTab (DSP_DUALSOURCE, i, false, DUALSOURCE));
+  tab_list->append (new DispTab (DSP_SOURCE_DISASM, i, false, SOURCEDISAM));
+  tab_list->append (new DispTab (DSP_SOURCE, i, false, SOURCE));
+  tab_list->append (new DispTab (DSP_LINE, i, false, HOTLINES));
+  tab_list->append (new DispTab (DSP_DISASM, i, false, DISASM));
+  tab_list->append (new DispTab (DSP_PC, i, false, HOTPCS));
+  tab_list->append (new DispTab (DSP_LEAKLIST, i, false, LEAKS));
+  tab_list->append (new DispTab (DSP_IOACTIVITY, i, false, IOACTIVITY));
+  tab_list->append (new DispTab (DSP_HEAPCALLSTACK, i, false, HEAP));
+  tab_list->append (new DispTab (DSP_IFREQ, i, false, IFREQ));
+  tab_list->append (new DispTab (DSP_CALLER, i, false, GPROF));
+  tab_list->append (new DispTab (DSP_STATIS, i, false, STATISTICS));
+  tab_list->append (new DispTab (DSP_EXP, i, false, HEADER));
+}
+
+// Update tablist based on data availability
+void
+Settings::updateTabAvailability ()
+{
+  int index;
+  DispTab *dsptab;
+
+  Vec_loop (DispTab*, tab_list, index, dsptab)
+  {
+    if (dsptab->type == DSP_DATAOBJ)
+      dsptab->setAvailability (dbeSession->is_datamode_available ());
+    else if (dsptab->type == DSP_DLAYOUT)
+      dsptab->setAvailability (dbeSession->is_datamode_available ());
+    else if (dsptab->type == DSP_LEAKLIST)
+      dsptab->setAvailability (false);
+    else if (dsptab->type == DSP_IOACTIVITY)
+      dsptab->setAvailability (dbeSession->is_iodata_available ());
+    else if (dsptab->type == DSP_HEAPCALLSTACK)
+      dsptab->setAvailability (dbeSession->is_heapdata_available ());
+    else if (dsptab->type == DSP_TIMELINE)
+      dsptab->setAvailability (dbeSession->is_timeline_available ());
+    else if (dsptab->type == DSP_IFREQ)
+      dsptab->setAvailability (dbeSession->is_ifreq_available ());
+    else if (dsptab->type == DSP_RACES)
+      dsptab->setAvailability (dbeSession->is_racelist_available ());
+    else if (dsptab->type == DSP_DEADLOCKS)
+      dsptab->setAvailability (dbeSession->is_deadlocklist_available ());
+    else if (dsptab->type == DSP_DUALSOURCE)
+      dsptab->setAvailability (dbeSession->is_racelist_available ()
+                              || dbeSession->is_deadlocklist_available ());
+  }
+}
+
+// Process a tab setting
+Cmd_status
+Settings::proc_tabs (bool _rdtMode)
+{
+  int arg_cnt, cparam;
+  int count = 0;
+  int index;
+  DispTab *dsptab;
+  char *cmd;
+  if (tabs_processed == true)
+    return CMD_OK;
+  tabs_processed = true;
+  if (_rdtMode == true)
+    {
+      if (str_rtabs == NULL)
+       str_rtabs = strdup ("header");
+      cmd = str_rtabs;
+    }
+  else
+    {
+      if (str_tabs == NULL)
+       str_tabs = strdup ("header");
+      cmd = str_tabs;
+    }
+  if (strcmp (cmd, NTXT ("none")) == 0)
+    return CMD_OK;
+  Vector <char *> *tokens = split_str (cmd, ':');
+  for (long j = 0, sz = VecSize (tokens); j < sz; j++)
+    {
+      char *tabname = tokens->get (j);
+      // search for this tab command token
+      CmdType c = Command::get_command (tabname, arg_cnt, cparam);
+      if (c == INDXOBJ)
+       {
+         // set the bit for this subtype
+         indx_tab_state->store (cparam, true);
+         indx_tab_order->store (cparam, count++);
+       }
+      else
+       {
+         // search for this tab type in the regular tabs
+         Vec_loop (DispTab*, tab_list, index, dsptab)
+         {
+           if (dsptab->cmdtoken == c)
+             {
+               dsptab->visible = true;
+               dsptab->order = count++;
+               break;
+             }
+         }
+       }
+      free (tabname);
+    }
+  delete tokens;
+  return CMD_OK;
+}
+
+void
+Settings::set_MemTabState (Vector<bool>*selected)
+{
+  if (selected->size () == 0)
+    return;
+  for (int j = 0; j < mem_tab_state->size (); j++)
+    mem_tab_state->store (j, selected->fetch (j));
+}
+
+// define a new memory object type
+
+void
+Settings::mobj_define (MemObjType_t */* mobj */, bool state)
+{
+  if (mem_tab_state->size () == 0)
+    state = true;
+  mem_tab_state->append (state);
+  mem_tab_order->append (-1);
+}
+
+void
+Settings::set_IndxTabState (Vector<bool>*selected)
+{
+  for (int j = 0; j < selected->size (); j++)
+    indx_tab_state->store (j, selected->fetch (j));
+}
+
+// define a new index object type
+void
+Settings::indxobj_define (int type, bool state)
+{
+  indx_tab_state->store (type, state);
+  indx_tab_order->store (type, -1);
+}
+
+void
+Settings::set_pathmaps (Vector<pathmap_t*> *newPathMap)
+{
+  if (pathmaps)
+    {
+      pathmaps->destroy ();
+      delete pathmaps;
+    }
+  pathmaps = newPathMap;
+}
+
+static char *
+get_canonical_name (const char *fname)
+{
+  char *nm = dbe_strdup (fname);
+  for (size_t len = strlen (nm); (len > 0) && (nm[len - 1] == '/'); len--)
+    nm[len - 1] = 0;
+  return nm;
+}
+
+char *
+Settings::add_pathmap (Vector<pathmap_t*> *v, const char *from, const char *to)
+{
+  // Check for errors
+  if (from == NULL || to == NULL)
+    return dbe_strdup (GTXT ("Pathmap can have neither from nor to as NULL\n"));
+  if (strcmp (from, to) == 0)
+    return dbe_strdup (GTXT ("Pathmap from must differ from to\n"));
+  char *old_prefix = get_canonical_name (from);
+  char *new_prefix = get_canonical_name (to);
+
+  // Check the pathmap list
+  for (int i = 0, sz = v->size (); i < sz; i++)
+    {
+      pathmap_t *pmp = v->get (i);
+      if ((strcmp (pmp->old_prefix, old_prefix) == 0) &&(strcmp (pmp->new_prefix, new_prefix) == 0))
+       {
+         char *s = dbe_sprintf (GTXT ("Pathmap from `%s' to `%s' already exists\n"), old_prefix, new_prefix);
+         free (old_prefix);
+         free (new_prefix);
+         return s;
+       }
+    }
+  // construct a map for this pair
+  pathmap_t *thismap = new pathmap_t;
+  thismap->old_prefix = old_prefix;
+  thismap->new_prefix = new_prefix;
+  v->append (thismap);
+  return NULL;
+}
+
+// Set all shared object expands back to .rc file defaults,
+//     as stored in the DbeSession Settings
+bool
+Settings::set_libdefaults ()
+{
+  // See if this is unchanged
+  if (is_loexpand_default == true)
+    return false; // no change
+
+  // replicate the DbeSession's lo_expand vector and default settings
+  lo_expand_t *this_lo_ex;
+  lo_expand_t *new_lo_ex;
+  int index;
+  lo_expand_default = dbeSession->get_settings ()->lo_expand_default;
+  lo_expands = new Vector<lo_expand_t*>;
+  Vec_loop (lo_expand_t*, dbeSession->get_settings ()->lo_expands, index, this_lo_ex)
+  {
+    new_lo_ex = new lo_expand_t;
+    new_lo_ex->libname = dbe_strdup (this_lo_ex->libname);
+    new_lo_ex->expand = this_lo_ex->expand;
+    lo_expands->append (new_lo_ex);
+  }
+  is_loexpand_default = true;
+  return true;
+}
+
+bool
+Settings::set_libexpand (char *cov, enum LibExpand expand, bool rc)
+{
+  int index;
+  lo_expand_t *loe;
+  bool change = false;
+  if (cov == NULL || !strcasecmp (cov, Command::ALL_CMD))
+    { // set all libraries
+      // set the default
+      if (lo_expand_default != expand)
+       {
+         lo_expand_default = expand;
+         change = true;
+         is_loexpand_default = false;
+       }
+
+      // and force any explicit settings to match, too
+      Vec_loop (lo_expand_t*, lo_expands, index, loe)
+      {
+       if (loe->expand != expand)
+         {
+           loe->expand = expand;
+           change = true;
+           is_loexpand_default = false;
+         }
+      }
+
+    }
+  else
+    { // parsing coverage
+      Vector <char *> *tokens = split_str (cov, ',');
+      for (long j = 0, sz = VecSize (tokens); j < sz; j++)
+       {
+         char *lo_name = tokens->get (j);
+         char *newname = get_basename (lo_name);
+         bool found = false;
+         Vec_loop (lo_expand_t*, lo_expands, index, loe)
+         {
+           if (strcmp (loe->libname, newname) == 0)
+             {
+               if (loe->expand != expand)
+                 {
+                   if (rc == false)
+                     {
+                       loe->expand = expand;
+                       change = true;
+                       is_loexpand_default = false;
+                     }
+                 }
+               found = true;
+               break;
+             }
+         }
+
+         if (found == false)
+           {
+             // construct a map for this pair
+             lo_expand_t *thisloe;
+             thisloe = new lo_expand_t;
+             thisloe->libname = dbe_strdup (newname);
+             thisloe->expand = expand;
+             change = true;
+             is_loexpand_default = false;
+
+             // add it to the vector
+             lo_expands->append (thisloe);
+           }
+         free (lo_name);
+       }
+      delete tokens;
+    }
+  return change;
+}
+
+enum LibExpand
+Settings::get_lo_setting (char *name)
+{
+  int index;
+  lo_expand_t *loe;
+  char *lo_name = get_basename (name);
+  Vec_loop (lo_expand_t*, lo_expands, index, loe)
+  {
+    if (strcmp (loe->libname, lo_name) == 0)
+      return loe->expand;
+  }
+  return lo_expand_default;
+}
diff --git a/gprofng/src/Settings.h b/gprofng/src/Settings.h
new file mode 100644 (file)
index 0000000..fc696e8
--- /dev/null
@@ -0,0 +1,425 @@
+/* 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 _SETTINGS_H
+#define _SETTINGS_H
+
+#include <stdio.h>
+#include <regex.h>
+
+#include "gp-defs.h"
+#include "Histable.h"
+#include "MemorySpace.h"
+#include "Metric.h"
+#include "dbe_types.h"
+#include "dbe_structs.h"
+#include "enums.h"
+#include "vec.h"
+
+class Emsgqueue;
+class Application;
+
+struct DispTab;
+
+// Settings object
+
+class Settings
+{
+public:
+  friend class DbeView;
+  friend class DbeSession;
+
+  Settings (Application *_app);
+  Settings (Settings *_settings);
+  virtual ~Settings ();
+  void read_rc (bool ipc_or_rdt_mode);  // read all rc files
+  char *read_rc (char *path);           // read rc file
+  void buildMasterTabList ();       // build list of Tabs that can be invoked
+  void updateTabAvailability ();    // update for datamode, leaklist
+  Cmd_status set_name_format (char *str); // from a string
+
+  Vector<DispTab*> *
+  get_TabList ()        // Get the list of tabs for this view
+  {
+    return tab_list;
+  }
+
+  Vector<bool> *
+  get_MemTabState ()    // Get the list and order of memory tabs for this view
+  {
+    return mem_tab_state;
+  }
+
+  Vector<int> *
+  get_MemTabOrder ()
+  {
+    return mem_tab_order;
+  }
+
+  // Set the list of memory tabs for this view
+  void set_MemTabState (Vector<bool>*sel);
+
+  // add a newly-defined memory object tab
+  void mobj_define (MemObjType_t *, bool state);
+
+  // add a newly-defined index object tab
+  void indxobj_define (int type, bool state);
+
+  Vector<bool> *
+  get_IndxTabState ()   // Get the list and order of index tabs for this view
+  {
+    return indx_tab_state;
+  }
+
+  Vector<int> *
+  get_IndxTabOrder ()
+  {
+    return indx_tab_order;
+  }
+
+  // Set the list of index tabs for this view
+  void set_IndxTabState (Vector<bool>*sel);
+
+  void
+  set_name_format (int fname_fmt, bool soname_fmt)
+  {
+    name_format = Histable::make_fmt (fname_fmt, soname_fmt);
+  }
+
+  Histable::NameFormat
+  get_name_format ()
+  {
+    return name_format;
+  }
+
+  // public methods for setting and accessing the settings
+  Cmd_status set_view_mode (char *str, bool rc); // from a string
+
+  void
+  set_view_mode (VMode mode)
+  {
+    view_mode = mode;
+  }
+
+  VMode
+  get_view_mode ()
+  {
+    return view_mode;
+  }
+
+  // set the en_desc expression/on/off
+  Cmd_status set_en_desc (char *str, bool rc); // from a string
+  // check if the lineage or the target name matches the en_desc expression
+  bool check_en_desc (const char *lineage, const char *targname);
+
+  char *set_limit (char *str, bool rc); // from a string
+
+  char *
+  set_limit (int _limit)
+  {
+    limit = _limit;
+    return NULL;
+  }
+
+  int
+  get_limit ()
+  {
+    return limit;
+  }
+
+  char *set_printmode (char *_pmode);
+
+  // processing compiler commentary visibility bits
+  Cmd_status proc_compcom (const char *cmd, bool isSrc, bool rc);
+
+  // return any error string from processing visibility settings
+  char *get_compcom_errstr (Cmd_status status, const char *cmd);
+
+  // methods for setting and getting strings, and individual settings
+
+  char *
+  get_str_scompcom ()
+  {
+    return str_scompcom;
+  }
+
+  char *
+  get_str_dcompcom ()
+  {
+    return str_dcompcom;
+  }
+
+  int
+  get_src_compcom ()
+  {
+    return src_compcom;
+  }
+
+  int
+  get_dis_compcom ()
+  {
+    return dis_compcom;
+  }
+
+  void
+  set_cmpline_visible (bool v)
+  {
+    cmpline_visible = v;
+  }
+
+  void
+  set_funcline_visible (bool v)
+  {
+    funcline_visible = v;
+  }
+
+  void
+  set_src_visible (int v)
+  {
+    src_visible = v;
+  }
+
+  int
+  get_src_visible ()
+  {
+    return src_visible;
+  }
+
+  void
+  set_srcmetric_visible (bool v)
+  {
+    srcmetric_visible = v;
+  }
+
+  bool
+  get_srcmetric_visible ()
+  {
+    return srcmetric_visible;
+  }
+
+  void
+  set_hex_visible (bool v)
+  {
+    hex_visible = v;
+  }
+
+  bool
+  get_hex_visible ()
+  {
+    return hex_visible;
+  }
+
+  // processing and accessing the threshold settings
+  Cmd_status proc_thresh (char *cmd, bool isSrc, bool rc);
+
+  int
+  get_thresh_src ()
+  {
+    return threshold_src;
+  }
+
+  int
+  get_thresh_dis ()
+  {
+    return threshold_dis;
+  }
+
+  // process a tlmode setting
+  Cmd_status proc_tlmode (char *cmd, bool rc);
+
+  void
+  set_tlmode (int _tlmode)
+  {
+    tlmode = _tlmode;
+  }
+
+  int
+  get_tlmode ()
+  {
+    return tlmode;
+  }
+
+  void
+  set_stack_align (int _stack_align)
+  {
+    stack_align = _stack_align;
+  }
+
+  int
+  get_stack_align ()
+  {
+    return stack_align;
+  }
+
+  void
+  set_stack_depth (int _stack_depth)
+  {
+    stack_depth = _stack_depth;
+  }
+
+  int
+  get_stack_depth ()
+  {
+    return stack_depth;
+  }
+
+  // process a tabs setting: called when the tab list is requested
+  Cmd_status proc_tabs (bool _rdtMode);
+
+  Cmd_status proc_tldata (const char *cmd, bool rc); // process a tldata setting
+  void set_tldata (const char* tldata_string);
+  char *get_tldata ();
+
+  char *
+  get_default_metrics ()
+  {
+    return str_dmetrics;
+  }
+
+  char *
+  get_default_sort ()
+  {
+    return str_dsort;
+  }
+
+  void
+  set_ignore_no_xhwcprof (bool v)   // ignore no xhwcprof errors for dataspace
+  {
+    ignore_no_xhwcprof = v;
+  }
+
+  bool
+  get_ignore_no_xhwcprof ()
+  {
+    return ignore_no_xhwcprof;
+  }
+
+  void
+  set_ignore_fs_warn (bool v)   // ignore filesystem warnings in experiments
+  {
+    ignore_fs_warn = v;
+  }
+
+  bool
+  get_ignore_fs_warn ()
+  {
+    return ignore_fs_warn;
+  }
+
+  // add a pathmap
+  static char *add_pathmap (Vector<pathmap_t*> *v, const char *from, const char *to);
+  void set_pathmaps (Vector<pathmap_t*> *newPathMap);
+
+  // add a LoadObject expansion setting
+  bool set_libexpand (char *, enum LibExpand, bool);
+  enum LibExpand get_lo_setting (char *);
+
+  // set LoadObject expansion defaults back to .rc specifications
+  bool set_libdefaults ();
+
+  void
+  set_compare_mode (int mode)
+  {
+    compare_mode = mode;
+  }
+
+  int
+  get_compare_mode ()
+  {
+    return compare_mode;
+  }
+
+  char *
+  get_machinemodel ()
+  {
+    return dbe_strdup (machinemodel);
+  }
+
+  char *preload_libdirs;
+
+protected: // data
+  Application *app;
+
+  // default strings from .rc file
+  char *str_vmode;
+  char *str_en_desc;
+  char *str_datamode;
+  char *str_scompcom;
+  char *str_sthresh;
+  char *str_dcompcom;
+  char *str_dthresh;
+  char *str_dmetrics;
+  char *str_dsort;
+  char *str_tlmode;
+  char *str_tldata;
+  char *str_tabs;
+  char *str_rtabs;
+  char *str_search_path;
+  char *str_name_format;
+  char *str_limit;
+  char *str_printmode;
+  char *str_compare;
+
+  bool tabs_processed;
+
+  // Processed settings
+  bool en_desc;             // controls for reading descendant processes
+  char * en_desc_usr;       // selective descendants: user specificaton
+  regex_t * en_desc_cmp;    // selective descendants: compiled specification
+  Histable::NameFormat name_format; // long/short/mangled naming for C++/Java
+  VMode view_mode;          // Java mode
+  int src_compcom;          // compiler commentary visibility for anno-src
+  int dis_compcom;          // compiler commentary visibility for anno-dis
+  int threshold_src;        // threshold for anno-src
+  int threshold_dis;        // threshold for anno-dis
+  int cmpline_visible;      // show compile-line flags
+  int funcline_visible;     // show compile-line flags
+  int src_visible;          // show source in disasm
+  bool srcmetric_visible;   // show metrics for source in disasm
+  bool hex_visible;         // show hex code in disasm
+  char* tldata;             // timeline data type string
+  int tlmode;               // timeline mode for bars
+  int stack_align;          // timeline stack alignment
+  int stack_depth;          // timeline stack depth
+  int limit;                // print limit
+  enum PrintMode print_mode;// print mode
+  char print_delim;         // the delimiter, if print mode = PM_DELIM_SEP_LIST
+  int compare_mode;         // compare mode
+
+  char *machinemodel; // machine model for Memory Objects
+
+  bool ignore_no_xhwcprof; // ignore no -xhwcprof data in dataspace
+  bool ignore_fs_warn; // ignore file-system recording warning
+
+  void set_rc (const char *path, bool msg, Emsgqueue *commentq,
+              bool override, bool ipc_or_rdt_mode = false);
+
+  Vector<DispTab*> *tab_list;
+  Vector<pathmap_t*> *pathmaps;
+  Vector<lo_expand_t*> *lo_expands;
+  enum LibExpand lo_expand_default;
+  bool is_loexpand_default;
+  Vector<bool> *mem_tab_state;
+  Vector<int> *mem_tab_order;
+  Vector<bool> *indx_tab_state;
+  Vector<int> *indx_tab_order;
+};
+
+#endif /* ! _SETTINGS_H */
diff --git a/gprofng/src/SourceFile.cc b/gprofng/src/SourceFile.cc
new file mode 100644 (file)
index 0000000..bd0a1f1
--- /dev/null
@@ -0,0 +1,229 @@
+/* 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 <unistd.h>
+
+#include "util.h"
+#include "DbeSession.h"
+#include "Function.h"
+#include "SourceFile.h"
+#include "DefaultMap.h"
+#include "DbeFile.h"
+#include "LoadObject.h"
+#include "Module.h"
+
+int SourceFile::curId = 0;
+
+SourceFile::SourceFile (const char *file_name)
+{
+  status = OS_NOTREAD;
+  srcLines = NULL;
+  srcInode = -1;
+  lines = NULL;
+  dbeLines = NULL;
+  functions = new DefaultMap<Function *, Function *>();
+  dbeFile = new DbeFile (file_name);
+  dbeFile->filetype |= DbeFile::F_SOURCE | DbeFile::F_FILE;
+  set_name ((char *) file_name);
+  srcMTime = (time_t) 0;
+  isTmpFile = false;
+  flags = 0;
+  read_stabs = false;
+  id = (uint64_t) ((Histable::SOURCEFILE << 24) + curId) << 32;
+  curId++;
+}
+
+SourceFile::~SourceFile ()
+{
+  destroy_map (DbeLine *, dbeLines);
+  delete functions;
+  delete dbeFile;
+  if (lines)
+    {
+      lines->destroy ();
+      delete lines;
+    }
+  if (srcLines)
+    {
+      free (srcLines->get (0));
+      delete srcLines;
+    }
+  if (isTmpFile)
+    unlink (name);
+}
+
+void
+SourceFile::set_name (char* _name)
+{
+  name = dbe_strdup (_name);
+}
+
+char*
+SourceFile::get_name (NameFormat)
+{
+  return name;
+}
+
+bool
+SourceFile::readSource ()
+{
+  if (srcLines)
+    return true;
+  status = OS_NOSRC;
+  char *location = dbeFile->get_location ();
+  if (location == NULL)
+    return false;
+  if (!isTmpFile)
+    srcMTime = dbeFile->sbuf.st_mtime;
+  srcInode = dbeFile->sbuf.st_ino;
+  size_t srcLen = dbeFile->sbuf.st_size;
+  int fd = open64 (location, O_RDONLY);
+  if (fd == -1)
+    {
+      status = OS_NOSRC;
+      return false;
+    }
+  char *srcMap = (char *) malloc (srcLen + 1);
+  int64_t sz = read_from_file (fd, srcMap, srcLen);
+  if (sz != (int64_t) srcLen)
+    append_msg (CMSG_ERROR, GTXT ("%s: Can read only %lld bytes instead %lld"),
+               location, (long long) sz, (long long) srcLen);
+  srcMap[sz] = 0;
+  close (fd);
+
+  // Count the number of lines in the file, converting <nl> to zero
+  srcLines = new Vector<char*>();
+  srcLines->append (srcMap);
+  for (int64_t i = 0; i < sz; i++)
+    {
+      if (srcMap[i] == '\r')
+       { // Window style
+         srcMap[i] = 0;
+         if (i + 1 < sz && srcMap[i + 1] != '\n')
+           srcLines->append (srcMap + i + 1);
+       }
+      else if (srcMap[i] == '\n')
+       {
+         srcMap[i] = '\0';
+         if (i + 1 < sz)
+           srcLines->append (srcMap + i + 1);
+       }
+    }
+  if (dbeLines)
+    {
+      Vector<DbeLine *> *v = dbeLines->values ();
+      for (long i = 0, sz1 = v ? v->size () : 0; i < sz1; i++)
+       {
+         DbeLine *p = v->get (i);
+         if (p->lineno >= srcLines->size ())
+           append_msg (CMSG_ERROR, GTXT ("Wrong line number %d. '%s' has only %d lines"),
+                       p->lineno, dbeFile->get_location (), srcLines->size ());
+       }
+      delete v;
+    }
+  status = OS_OK;
+  return true;
+}
+
+char *
+SourceFile::getLine (int lineno)
+{
+  assert (srcLines != NULL);
+  if (lineno > 0 && lineno <= srcLines->size ())
+    return srcLines->get (lineno - 1);
+  return NTXT ("");
+}
+
+DbeLine *
+SourceFile::find_dbeline (Function *func, int lineno)
+{
+  if (lineno < 0 || (lineno == 0 && func == NULL))
+    return NULL;
+  DbeLine *dbeLine = NULL;
+  if (lines)
+    { // the source is available
+      if (lineno > lines->size ())
+       {
+         if (dbeLines)
+           dbeLine = dbeLines->get (lineno);
+         if (dbeLine == NULL)
+           append_msg (CMSG_ERROR,
+                       GTXT ("Wrong line number %d. '%s' has only %d lines"),
+                       lineno, dbeFile->get_location (), lines->size ());
+       }
+      else
+       {
+         dbeLine = lines->fetch (lineno);
+         if (dbeLine == NULL)
+           {
+             dbeLine = new DbeLine (NULL, this, lineno);
+             lines->store (lineno, dbeLine);
+           }
+       }
+    }
+  if (dbeLine == NULL)
+    { // the source is not yet read or lineno is wrong
+      if (dbeLines == NULL)
+       dbeLines = new DefaultMap<int, DbeLine *>();
+      dbeLine = dbeLines->get (lineno);
+      if (dbeLine == NULL)
+       {
+         dbeLine = new DbeLine (NULL, this, lineno);
+         dbeLines->put (lineno, dbeLine);
+       }
+    }
+
+  for (DbeLine *last = dbeLine;; last = last->dbeline_func_next)
+    {
+      if (last->func == func)
+       return last;
+      if (last->dbeline_func_next == NULL)
+       {
+         DbeLine *dl = new DbeLine (func, this, lineno);
+         if (functions->get (func) == NULL)
+           functions->put (func, func);
+         last->dbeline_func_next = dl;
+         dl->dbeline_base = dbeLine;
+         return dl;
+       }
+    }
+}
+
+Vector<Function *> *
+SourceFile::get_functions ()
+{
+  if (!read_stabs)
+    {
+      // Create all DbeLines for this Source
+      read_stabs = true;
+      Vector<LoadObject *> *lobjs = dbeSession->get_LoadObjects ();
+      for (long i = 0, sz = VecSize (lobjs); i < sz; i++)
+       {
+         LoadObject *lo = lobjs->get (i);
+         for (long i1 = 0, sz1 = VecSize (lo->seg_modules); i1 < sz1; i1++)
+           {
+             Module *mod = lo->seg_modules->get (i1);
+             mod->read_stabs ();
+           }
+       }
+    }
+  return functions->keySet ();
+}
diff --git a/gprofng/src/SourceFile.h b/gprofng/src/SourceFile.h
new file mode 100644 (file)
index 0000000..8e90682
--- /dev/null
@@ -0,0 +1,117 @@
+/* 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 _SOURCEFILE_H
+#define _SOURCEFILE_H
+
+#include "Histable.h"
+#include "Map.h"
+
+template <typename Key_t, typename Value_t> class Map;
+
+#define SOURCE_FLAG_UNKNOWN 0x01
+
+class SourceFile : public HistableFile
+{
+public:
+
+  enum OpenStatus
+  {
+    OS_OK,
+    OS_NOTREAD,
+    OS_NOSRC,
+    OS_TIMESRC
+  };
+
+  SourceFile (const char *file_name);
+  virtual ~SourceFile ();
+  virtual void set_name (char *);
+  virtual char *get_name (NameFormat = NA);
+
+  bool readSource ();
+  Vector<Function *> *get_functions ();
+  DbeLine *find_dbeline (Function *func, int lineno);
+  char *getLine (int lineno);
+
+  int
+  getLineCount ()
+  {
+    return srcLines ? srcLines->size () : 0;
+  }
+
+  ino64_t
+  getInode ()
+  {
+    return srcInode;
+  }
+
+  time_t
+  getMTime ()
+  {
+    return srcMTime;
+  }
+
+  void
+  setMTime (time_t tm)
+  {
+    srcMTime = tm;
+  }
+
+  bool
+  isTmp ()
+  {
+    return isTmpFile;
+  }
+
+  void
+  setTmp (bool set)
+  {
+    isTmpFile = set;
+  }
+
+  Histable_type
+  get_type ()
+  {
+    return SOURCEFILE;
+  }
+
+  DbeLine *
+  find_dbeline (int lineno)
+  {
+    return find_dbeline (NULL, lineno);
+  }
+
+  unsigned int flags;
+
+private:
+  static int curId;         // object id
+  OpenStatus status;
+  ino64_t srcInode;         // Inode number of source file
+  time_t srcMTime;          // Creating time for source
+  Vector<char *> *srcLines; // array of pointers to lines in source
+  bool isTmpFile;           // Temporary src file to be deleted
+
+  Vector<DbeLine*> *lines;
+  Map<int, DbeLine*> *dbeLines;
+  Map<Function *, Function *> *functions;
+  bool read_stabs;
+};
+
+#endif
diff --git a/gprofng/src/Stabs.cc b/gprofng/src/Stabs.cc
new file mode 100644 (file)
index 0000000..9f1247d
--- /dev/null
@@ -0,0 +1,2650 @@
+/* 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/param.h>
+
+#include "util.h"
+#include "Elf.h"
+#include "Dwarf.h"
+#include "stab.h"
+#include "DbeSession.h"
+#include "CompCom.h"
+#include "Stabs.h"
+#include "LoadObject.h"
+#include "Module.h"
+#include "Function.h"
+#include "info.h"
+#include "StringBuilder.h"
+#include "DbeFile.h"
+#include "StringMap.h"
+
+#define DISASM_REL_NONE     0     /* symtab search only */
+#define DISASM_REL_ONLY     1     /* relocation search only */
+#define DISASM_REL_TARG     2     /* relocatoin then symtab */
+
+///////////////////////////////////////////////////////////////////////////////
+// class StabReader
+class StabReader
+{
+public:
+  StabReader (Elf *_elf, Platform_t platform, int StabSec, int StabStrSec);
+  ~StabReader () { };
+  char *get_type_name (int t);
+  char *get_stab (struct stab *np, bool comdat);
+  void parse_N_OPT (Module *mod, char *str);
+  int stabCnt;
+  int stabNum;
+
+private:
+  Elf *elf;
+  char *StabData;
+  char *StabStrtab;
+  char *StabStrtabEnd;
+  int StrTabSize;
+  int StabEntSize;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// class Symbol
+
+class Symbol
+{
+public:
+  Symbol (Vector<Symbol*> *vec = NULL);
+
+  ~Symbol ()
+  {
+    free (name);
+  }
+
+  inline Symbol *
+  cardinal ()
+  {
+    return alias ? alias : this;
+  }
+
+  static void dump (Vector<Symbol*> *vec, char*msg);
+
+  Function *func;
+  Sp_lang_code lang_code;
+  uint64_t value; // st_value used in sym_name()
+  uint64_t save;
+  int64_t size;
+  uint64_t img_offset; // image offset in the ELF file
+  char *name;
+  Symbol *alias;
+  int local_ind;
+  int flags;
+  bool defined;
+};
+
+Symbol::Symbol (Vector<Symbol*> *vec)
+{
+  func = NULL;
+  lang_code = Sp_lang_unknown;
+  value = 0;
+  save = 0;
+  size = 0;
+  img_offset = 0;
+  name = NULL;
+  alias = NULL;
+  local_ind = -1;
+  flags = 0;
+  defined = false;
+  if (vec)
+    vec->append (this);
+}
+
+void
+Symbol::dump (Vector<Symbol*> *vec, char*msg)
+{
+  if (!DUMP_ELF_SYM || vec == NULL || vec->size () == 0)
+    return;
+  printf (NTXT ("======= Symbol::dump: %s =========\n"
+               "         value |    img_offset     | flags|local_ind|\n"), msg);
+  for (int i = 0; i < vec->size (); i++)
+    {
+      Symbol *sp = vec->fetch (i);
+      printf (NTXT ("  %3d %8lld |0x%016llx |%5d |%8d |%s\n"),
+             i, (long long) sp->value, (long long) sp->img_offset, sp->flags,
+             sp->local_ind, sp->name ? sp->name : NTXT ("NULL"));
+    }
+  printf (NTXT ("\n===== END of Symbol::dump: %s =========\n\n"), msg);
+}
+
+// end of class Symbol
+///////////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+// class Reloc
+class Reloc
+{
+public:
+  Reloc ();
+  ~Reloc ();
+  uint64_t type;
+  uint64_t value;
+  uint64_t addend;
+  char *name;
+};
+
+Reloc::Reloc ()
+{
+  type = 0;
+  value = 0;
+  addend = 0;
+  name = NULL;
+}
+
+Reloc::~Reloc ()
+{
+  free (name);
+}
+// end of class Reloc
+///////////////////////////////////////////////////////////////////////////////
+
+enum
+{
+  SYM_PLT       = 1 << 0,
+  SYM_UNDEF     = 1 << 1
+};
+
+enum Section_type
+{
+  COMM1_SEC = 0x10000000,
+  COMM_SEC  = 0x20000000,
+  INFO_SEC  = 0x30000000,
+  LOOP_SEC  = 0x40000000
+};
+
+struct cpf_stabs_t
+{
+  uint32_t type;    // Archive::AnalyzerInfoType
+  uint32_t offset;  // offset in .__analyzer_info
+  Module *module;   // table for appropriate Module
+};
+
+static char *get_info_com (int type, int32_t copy_inout);
+static char *get_lp_com (unsigned hints, int parallel, char *dep);
+static int ComCmp (const void *a, const void *b);
+static ino64_t _src_inode = 0;
+static char *_src_name;
+
+// Comparing name
+static int
+SymNameCmp (const void *a, const void *b)
+{
+  Symbol *item1 = *((Symbol **) a);
+  Symbol *item2 = *((Symbol **) b);
+  return (item1->name == NULL) ? -1 :
+         (item2->name == NULL) ? 1 : strcmp (item1->name, item2->name);
+}
+
+// Comparing value: for sorting
+static int
+SymValueCmp (const void *a, const void *b)
+{
+  Symbol *item1 = *((Symbol **) a);
+  Symbol *item2 = *((Symbol **) b);
+  return (item1->value > item2->value) ? 1 :
+         (item1->value == item2->value) ? SymNameCmp (a, b) : -1;
+}
+
+// Comparing value: for searching (source name is always NULL)
+static int
+SymFindCmp (const void *a, const void *b)
+{
+  Symbol *item1 = *((Symbol **) a);
+  Symbol *item2 = *((Symbol **) b);
+  if (item1->value < item2->value)
+    return -1;
+  if (item1->value < item2->value + item2->size
+      || item1->value == item2->value) // item2->size == 0
+    return 0;
+  return 1;
+}
+
+// Comparing value for sorting. It is used only for searching aliases.
+static int
+SymImgOffsetCmp (const void *a, const void *b)
+{
+  Symbol *item1 = *((Symbol **) a);
+  Symbol *item2 = *((Symbol **) b);
+  return (item1->img_offset > item2->img_offset) ? 1 :
+         (item1->img_offset == item2->img_offset) ? SymNameCmp (a, b) : -1;
+}
+
+static int
+RelValueCmp (const void *a, const void *b)
+{
+  Reloc *item1 = *((Reloc **) a);
+  Reloc *item2 = *((Reloc **) b);
+  return (item1->value > item2->value) ? 1 :
+         (item1->value == item2->value) ? 0 : -1;
+}
+
+Stabs *
+Stabs::NewStabs (char *_path, char *lo_name)
+{
+  Stabs *stabs = new Stabs (_path, lo_name);
+  if (stabs->status != Stabs::DBGD_ERR_NONE)
+    {
+      delete stabs;
+      return NULL;
+    }
+  return stabs;
+}
+
+Stabs::Stabs (char *_path, char *_lo_name)
+{
+  path = dbe_strdup (_path);
+  lo_name = dbe_strdup (_lo_name);
+  SymLstByName = NULL;
+  pltSym = NULL;
+  SymLst = new Vector<Symbol*>;
+  RelLst = new Vector<Reloc*>;
+  RelPLTLst = new Vector<Reloc*>;
+  LocalLst = new Vector<Symbol*>;
+  LocalFile = new Vector<char*>;
+  LocalFileIdx = new Vector<int>;
+  last_PC_to_sym = NULL;
+  dwarf = NULL;
+  elfDbg = NULL;
+  elfDis = NULL;
+  stabsModules = NULL;
+  textsz = 0;
+  wsize = Wnone;
+  st_check_symtab = st_check_relocs = false;
+  status = DBGD_ERR_NONE;
+
+  if (openElf (false) == NULL)
+    return;
+  switch (elfDis->elf_getclass ())
+    {
+    case ELFCLASS32:
+      wsize = W32;
+      break;
+    case ELFCLASS64:
+      wsize = W64;
+      break;
+    }
+  isRelocatable = elfDis->elf_getehdr ()->e_type == ET_REL;
+  for (unsigned int pnum = 0; pnum < elfDis->elf_getehdr ()->e_phnum; pnum++)
+    {
+      Elf_Internal_Phdr *phdr = elfDis->get_phdr (pnum);
+      if (phdr->p_type == PT_LOAD && phdr->p_flags == (PF_R | PF_X))
+       {
+         if (textsz == 0)
+           textsz = phdr->p_memsz;
+         else
+           {
+             textsz = 0;
+             break;
+           }
+       }
+    }
+}
+
+Stabs::~Stabs ()
+{
+  delete pltSym;
+  delete SymLstByName;
+  Destroy (SymLst);
+  Destroy (RelLst);
+  Destroy (RelPLTLst);
+  Destroy (LocalFile);
+  delete elfDis;
+  delete dwarf;
+  delete LocalLst;
+  delete LocalFileIdx;
+  delete stabsModules;
+  free (path);
+  free (lo_name);
+}
+
+Elf *
+Stabs::openElf (char *fname, Stab_status &st)
+{
+  Elf::Elf_status elf_status;
+  Elf *elf = Elf::elf_begin (fname, &elf_status);
+  if (elf == NULL)
+    {
+      switch (elf_status)
+       {
+       case Elf::ELF_ERR_CANT_OPEN_FILE:
+       case Elf::ELF_ERR_CANT_MMAP:
+       case Elf::ELF_ERR_BIG_FILE:
+         st = DBGD_ERR_CANT_OPEN_FILE;
+         break;
+       case Elf::ELF_ERR_BAD_ELF_FORMAT:
+       default:
+         st = DBGD_ERR_BAD_ELF_FORMAT;
+         break;
+       }
+      return NULL;
+    }
+  if (elf->elf_version (EV_CURRENT) == EV_NONE)
+    {
+      // ELF library out of date
+      delete elf;
+      st = DBGD_ERR_BAD_ELF_LIB;
+      return NULL;
+    }
+
+  Elf_Internal_Ehdr *ehdrp = elf->elf_getehdr ();
+  if (ehdrp == NULL)
+    {
+      // check machine
+      delete elf;
+      st = DBGD_ERR_BAD_ELF_FORMAT;
+      return NULL;
+    }
+  switch (ehdrp->e_machine)
+    {
+    case EM_SPARC:
+      platform = Sparc;
+      break;
+    case EM_SPARC32PLUS:
+      platform = Sparcv8plus;
+      break;
+    case EM_SPARCV9:
+      platform = Sparcv9;
+      break;
+    case EM_386:
+      //    case EM_486:
+      platform = Intel;
+      break;
+    case EM_X86_64:
+      platform = Amd64;
+      break;
+    case EM_AARCH64:
+      platform = Aarch64;
+      break;
+    default:
+      platform = Unknown;
+      break;
+    }
+  return elf;
+}
+
+Elf *
+Stabs::openElf (bool dbg_info)
+{
+  if (status != DBGD_ERR_NONE)
+    return NULL;
+  if (elfDis == NULL)
+    {
+      elfDis = openElf (path, status);
+      if (elfDis == NULL)
+       return NULL;
+    }
+  if (!dbg_info)
+    return elfDis;
+  if (elfDbg == NULL)
+    {
+      elfDbg = elfDis->find_ancillary_files (lo_name);
+      if (elfDbg == NULL)
+       elfDbg = elfDis;
+    }
+  return elfDbg;
+}
+
+bool
+Stabs::read_symbols (Vector<Function*> *functions)
+{
+  if (openElf (true) == NULL)
+    return false;
+  check_Symtab ();
+  check_Relocs ();
+  if (functions)
+    {
+      Function *fp;
+      int index;
+      Vec_loop (Function*, functions, index, fp)
+      {
+       fp->img_fname = path;
+      }
+    }
+  return true;
+}
+
+char *
+Stabs::sym_name (uint64_t target, uint64_t instr, int flag)
+{
+  long index;
+  if (flag == DISASM_REL_ONLY || flag == DISASM_REL_TARG)
+    {
+      Reloc *relptr = new Reloc;
+      relptr->value = instr;
+      index = RelLst->bisearch (0, -1, &relptr, RelValueCmp);
+      if (index >= 0)
+       {
+         delete relptr;
+         return RelLst->fetch (index)->name;
+       }
+      if (!is_relocatable ())
+       {
+         relptr->value = target;
+         index = RelPLTLst->bisearch (0, -1, &relptr, RelValueCmp);
+         if (index >= 0)
+           {
+             delete relptr;
+             return RelPLTLst->fetch (index)->name;
+           }
+       }
+      delete relptr;
+    }
+  if (flag == DISASM_REL_NONE || flag == DISASM_REL_TARG || !is_relocatable ())
+    {
+      Symbol *sptr;
+      sptr = map_PC_to_sym (target);
+      if (sptr && sptr->value == target)
+       return sptr->name;
+    }
+  return NULL;
+}
+
+Symbol *
+Stabs::map_PC_to_sym (uint64_t pc)
+{
+  if (pc == 0)
+    return NULL;
+  if (last_PC_to_sym && last_PC_to_sym->value <= pc
+      && last_PC_to_sym->value + last_PC_to_sym->size > pc)
+    return last_PC_to_sym;
+  Symbol *sym = new Symbol;
+  sym->value = pc;
+  long index = SymLst->bisearch (0, -1, &sym, SymFindCmp);
+  delete sym;
+  if (index >= 0)
+    {
+      last_PC_to_sym = SymLst->fetch (index)->cardinal ();
+      return last_PC_to_sym;
+    }
+  return NULL;
+}
+
+Function *
+Stabs::map_PC_to_func (uint64_t pc, uint64_t &low_pc, Vector<Function*> *functions)
+{
+  int index;
+  Function *func;
+  Symbol *sptr = map_PC_to_sym (pc);
+  if (sptr == NULL)
+    return NULL;
+  if (sptr->func)
+    {
+      low_pc = sptr->value;
+      return sptr->func;
+    }
+  if (functions)
+    {
+      Vec_loop (Function*, functions, index, func)
+      {
+       if (func->img_offset == sptr->img_offset)
+         {
+           sptr->func = func->cardinal ();
+           low_pc = sptr->value;
+           return sptr->func;
+         }
+      }
+    }
+  return NULL;
+}
+
+Stabs::Stab_status
+Stabs::read_stabs (ino64_t srcInode, Module *module, Vector<ComC*> *comComs,
+                  bool readDwarf)
+{
+  if (module)
+    module->setIncludeFile (NULL);
+
+  if (openElf (true) == NULL)
+    return status;
+  check_Symtab ();
+
+  // read compiler commentary from .compcom1, .compcom,
+  // .info, .loops, and .loopview sections
+  if (comComs)
+    {
+      _src_inode = srcInode;
+      _src_name = module && module->file_name ? get_basename (module->file_name) : NULL;
+      if (!check_Comm (comComs))
+       // .loops, and .loopview are now in .compcom
+       check_Loop (comComs);
+
+      // should not read it after .info goes into .compcom
+      check_Info (comComs);
+      comComs->sort (ComCmp);
+    }
+
+  // get stabs info
+  Stab_status statusStabs = DBGD_ERR_NO_STABS;
+#define SRC_LINE_STABS(sec, secStr, comdat) \
+    if ((elfDbg->sec)  && (elfDbg->secStr) && \
+       srcline_Stabs(module, elfDbg->sec, elfDbg->secStr, comdat) == DBGD_ERR_NONE) \
+       statusStabs = DBGD_ERR_NONE
+
+  SRC_LINE_STABS (stabExcl, stabExclStr, false);
+  SRC_LINE_STABS (stab, stabStr, false);
+  SRC_LINE_STABS (stabIndex, stabIndexStr, true);
+
+  // read Dwarf, if any sections found
+  if (elfDbg->dwarf && readDwarf)
+    {
+      openDwarf ()->srcline_Dwarf (module);
+      if (dwarf && dwarf->status == DBGD_ERR_NONE)
+       return DBGD_ERR_NONE;
+    }
+  return statusStabs;
+}
+
+static int
+ComCmp (const void *a, const void *b)
+{
+  ComC *item1 = *((ComC **) a);
+  ComC *item2 = *((ComC **) b);
+  return (item1->line > item2->line) ? 1 :
+         (item1->line < item2->line) ? -1 :
+         (item1->sec > item2->sec) ? 1 :
+         (item1->sec < item2->sec) ? -1 : 0;
+}
+
+static int
+check_src_name (char *srcName)
+{
+  if (_src_name && srcName && streq (_src_name, get_basename (srcName)))
+    return 1;
+  if (_src_inode == (ino64_t) - 1)
+    return 0;
+  DbeFile *dbeFile = dbeSession->getDbeFile (srcName, DbeFile::F_SOURCE);
+  char *path = dbeFile->get_location ();
+  return (path == NULL || dbeFile->sbuf.st_ino != _src_inode) ? 0 : 1;
+}
+
+bool
+Stabs::check_Comm (Vector<ComC*> *comComs)
+{
+  int sz = comComs->size ();
+  Elf *elf = openElf (true);
+  if (elf == NULL)
+    return false;
+
+  for (unsigned int sec = 1; sec < elf->elf_getehdr ()->e_shnum; sec++)
+    {
+      char *name = elf->get_sec_name (sec);
+      if (name == NULL)
+       continue;
+      Section_type sec_type;
+      if (streq (name, NTXT (".compcom")))
+       sec_type = COMM_SEC;
+      else if (streq (name, NTXT (".compcom1")))
+       sec_type = COMM1_SEC;
+      else
+       continue;
+
+      // find header, set messages id & visibility if succeed
+      CompComment *cc = new CompComment (elf, sec);
+      int cnt = cc->compcom_open ((CheckSrcName) check_src_name);
+      // process messages
+      for (int index = 0; index < cnt; index++)
+       {
+         int visible;
+         compmsg msg;
+         char *str = cc->compcom_format (index, &msg, visible);
+         if (str)
+           {
+             ComC *citem = new ComC;
+             citem->sec = sec_type + index;
+             citem->type = msg.msg_type;
+             citem->visible = visible;
+             citem->line = (msg.lineno < 1) ? 1 : msg.lineno;
+             citem->com_str = str;
+             comComs->append (citem);
+           }
+       }
+      delete cc;
+    }
+  return (sz != comComs->size ());
+}
+
+static int
+targetOffsetCmp (const void *a, const void *b)
+{
+  uint32_t o1 = ((target_info_t *) a)->offset;
+  uint32_t o2 = ((target_info_t *) b)->offset;
+  return (o1 >= o2);
+}
+
+void
+Stabs::check_AnalyzerInfo ()
+{
+  Elf *elf = openElf (true);
+  if ((elf == NULL) || (elf->analyzerInfo == 0))
+    {
+      Dprintf (DEBUG_STABS, NTXT ("Stabs::check_AnalyzerInfo: Null AnalyzerInfo section\n"));
+      return; // inappropriate, but ignored anyway
+    }
+  Elf_Data *data = elf->elf_getdata (elf->analyzerInfo);
+  int InfoSize = (int) data->d_size;
+  char *InfoData = (char *) data->d_buf;
+  int InfoAlign = (int) data->d_align;
+  AnalyzerInfoHdr h;
+  unsigned infoHdr_sz = sizeof (AnalyzerInfoHdr);
+  int table, entry;
+  int read = 0;
+  Module *mitem;
+  int index = 0;
+  if (InfoSize <= 0)
+    return;
+  uint64_t baseAddr = elf->get_baseAddr ();
+  Dprintf (DEBUG_STABS, NTXT ("Stabs::check_AnalyzerInfo size=%d @0x%lx (align=%d) base=0x%llx\n"),
+          InfoSize, (ul_t) InfoData, InfoAlign, (long long) baseAddr);
+  Dprintf (DEBUG_STABS, NTXT ("analyzerInfoMap has %lld entries\n"), (long long) analyzerInfoMap.size ());
+  if (analyzerInfoMap.size () == 0)
+    {
+      Dprintf (DEBUG_STABS, NTXT ("No analyzerInfoMap available!\n"));
+      return;
+    }
+
+  // verify integrity of analyzerInfoMap before reading analyzerInfo
+  unsigned count = 0;
+  Module *lastmod = NULL;
+  for (index = 0; index < analyzerInfoMap.size (); index++)
+    {
+      cpf_stabs_t map = analyzerInfoMap.fetch (index);
+      if (map.type > 3)
+       {
+         Dprintf (DEBUG_STABS, NTXT ("analyzerInfo contains table of unknown type %d for %s\n"),
+                  map.type, map.module->get_name ());
+         return;
+       }
+      if (map.module != lastmod)
+       {
+         if (lastmod != NULL)
+           Dprintf (DEBUG_STABS, "analyzerInfo contains %d 0x0 offset tables for %s\n",
+                    count, lastmod->get_name ());
+         count = 0;
+       }
+      count += (map.offset == 0x0); // only check for 0x0 tables for now
+      if (count > 4)
+       {
+         Dprintf (DEBUG_STABS, NTXT ("analyzerInfo contains too many 0x0 offset tables for %s\n"),
+                  map.module->get_name ());
+         return;
+       }
+      lastmod = map.module;
+    }
+
+  index = 0;
+  while ((index < analyzerInfoMap.size ()) && (read < InfoSize))
+    {
+      for (table = 0; table < 3; table++)
+       { // memory operations (ld, st, prefetch)
+         // read the table header
+         memcpy ((void *) &h, (const void *) InfoData, infoHdr_sz);
+         InfoData += infoHdr_sz;
+         read += infoHdr_sz;
+
+         // use map for appropriate module
+         cpf_stabs_t map = analyzerInfoMap.fetch (index);
+         index++;
+         mitem = map.module;
+         Dprintf (DEBUG_STABS, "Table %d offset=0x%04x "
+                  "text_labelref=0x%08llx entries=%d version=%d\n"
+                  "itype %d offset=0x%04x module=%s\n", table, read,
+                  (long long) (h.text_labelref - baseAddr), h.entries,
+                  h.version, map.type, map.offset, map.module->get_name ());
+         // read the table entries
+         for (entry = 0; entry < h.entries; entry++)
+           {
+             memop_info_t *m = new memop_info_t;
+             unsigned memop_info_sz = sizeof (memop_info_t);
+             memcpy ((void *) m, (const void *) InfoData, memop_info_sz);
+             InfoData += memop_info_sz;
+             read += memop_info_sz;
+             m->offset += (uint32_t) (h.text_labelref - baseAddr);
+             Dprintf (DEBUG_STABS, NTXT ("%4d(%d): offset=0x%04x id=0x%08x sig=0x%08x dtid=0x%08x\n"),
+                      entry, table, m->offset, m->id, m->signature, m->datatype_id);
+             switch (table)
+               {
+               case CPF_INSTR_TYPE_LD:
+                 mitem->ldMemops.append (m);
+                 break;
+               case CPF_INSTR_TYPE_ST:
+                 mitem->stMemops.append (m);
+                 break;
+               case CPF_INSTR_TYPE_PREFETCH:
+                 mitem->pfMemops.append (m);
+                 break;
+               }
+           }
+         // following re-alignment should be redundant
+         //InfoData+=(read%InfoAlign); read+=(read%InfoAlign); // re-align
+       }
+      for (table = 3; table < 4; table++)
+       { // branch targets
+         memcpy ((void *) &h, (const void *) InfoData, infoHdr_sz);
+         InfoData += infoHdr_sz;
+         read += infoHdr_sz;
+
+         // use map for appropriate module
+         cpf_stabs_t map = analyzerInfoMap.fetch (index);
+         index++;
+         mitem = map.module;
+         Dprintf (DEBUG_STABS, "Table %d offset=0x%04x "
+                  "text_labelref=0x%08llx entries=%d version=%d\n"
+                  "itype %d offset=0x%04x module=%s\n", table, read,
+                  (long long) (h.text_labelref - baseAddr), h.entries,
+                  h.version, map.type, map.offset, map.module->get_name ());
+         for (entry = 0; entry < h.entries; entry++)
+           {
+             target_info_t *t = new target_info_t;
+             unsigned target_info_sz = sizeof (target_info_t);
+             memcpy ((void *) t, (const void *) InfoData, target_info_sz);
+             InfoData += target_info_sz;
+             read += target_info_sz;
+             t->offset += (uint32_t) (h.text_labelref - baseAddr);
+             Dprintf (DEBUG_STABS, NTXT ("%4d(%d): offset=0x%04x\n"), entry,
+                      table, t->offset);
+             // the list of branch targets needs to be in offset sorted order
+             // and doing it here before archiving avoids the need to do it
+             // each time the archive is read.
+             mitem->bTargets.incorporate (t, targetOffsetCmp);
+           }
+         Dprintf (DEBUG_STABS, NTXT ("bTargets for %s has %lld items (last=0x%04x)\n"),
+                  mitem->get_name (), (long long) mitem->bTargets.size (),
+                  (mitem->bTargets.fetch (mitem->bTargets.size () - 1))->offset);
+         Dprintf (DEBUG_STABS, "read=%d at end of bTargets (InfoData=0x%lx)\n",
+                  read, (ul_t) InfoData);
+         InfoData += (read % InfoAlign);
+         read += (read % InfoAlign); // re-align
+         Dprintf (DEBUG_STABS, "read=%d at end of bTargets (InfoData=0x%lx)\n",
+                  read, (ul_t) InfoData);
+       }
+      Dprintf (DEBUG_STABS, "Stabs::check_AnalyzerInfo bytes read=%lld (index=%lld/%lld)\n",
+              (long long) read, (long long) index,
+              (long long) analyzerInfoMap.size ());
+    }
+}
+
+void
+Stabs::check_Info (Vector<ComC*> *comComs)
+{
+  Elf *elf = openElf (true);
+  if (elf == NULL || elf->info == 0)
+    return;
+  Elf_Data *data = elf->elf_getdata (elf->info);
+  uint64_t InfoSize = data->d_size;
+  char *InfoData = (char *) data->d_buf;
+  bool get_src = false;
+  for (int h_num = 0; InfoSize; h_num++)
+    {
+      if (InfoSize < sizeof (struct info_header))
+       return;
+      struct info_header *h = (struct info_header*) InfoData;
+      if (h->endian != '\0' || h->magic[0] != 'S' || h->magic[1] != 'U'
+         || h->magic[2] != 'N')
+       return;
+      if (h->len < InfoSize || h->len < sizeof (struct info_header) || (h->len & 3))
+       return;
+
+      char *fname = InfoData + sizeof (struct info_header);
+      InfoData += h->len;
+      InfoSize -= h->len;
+      get_src = check_src_name (fname);
+      for (uint32_t e_num = 0; e_num < h->cnt; ++e_num)
+       {
+         if (InfoSize < sizeof (struct entry_header))
+           return;
+         struct entry_header *e = (struct entry_header*) InfoData;
+         if (InfoSize < e->len)
+           return;
+         int32_t copy_inout = 0;
+         if (e->len > sizeof (struct entry_header))
+           if (e->type == F95_COPYINOUT)
+             copy_inout = *(int32_t*) (InfoData + sizeof (struct entry_header));
+         InfoData += e->len;
+         InfoSize -= e->len;
+         if (get_src)
+           {
+             ComC *citem = new ComC;
+             citem->sec = INFO_SEC + h_num;
+             citem->type = e->msgnum & 0xFFFFFF;
+             citem->visible = CCMV_ALL;
+             citem->line = e->line;
+             citem->com_str = get_info_com (citem->type, copy_inout);
+             comComs->append (citem);
+           }
+       }
+      if (get_src)
+       break;
+    }
+}
+
+static char *
+get_info_com (int type, int32_t copy_inout)
+{
+  switch (type)
+    {
+    case 1:
+      return dbe_sprintf (GTXT ("In the call below, parameter number %d caused a copy-in -- loop(s) inserted"),
+                         copy_inout);
+    case 2:
+      return dbe_sprintf (GTXT ("In the call below, parameter number %d caused a copy-out -- loop(s) inserted"),
+                         copy_inout);
+    case 3:
+      return dbe_sprintf (GTXT ("In the call below, parameter number %d caused a copy-in and a copy-out -- loops inserted"),
+                         copy_inout);
+    case 4:
+      return dbe_strdup (GTXT ("Alignment of variables in common block may cause performance degradation"));
+    case 5:
+      return dbe_strdup (GTXT ("DO statement bounds lead to no executions of the loop"));
+    default:
+      return dbe_strdup (NTXT (""));
+    }
+}
+
+void
+Stabs::check_Loop (Vector<ComC*> *comComs)
+{
+  Elf *elf = openElf (true);
+  if (elf == NULL)
+    return;
+
+  StringBuilder sb;
+  for (unsigned int sec = 1; sec < elf->elf_getehdr ()->e_shnum; sec++)
+    {
+      char *name = elf->get_sec_name (sec);
+      if (name == NULL)
+       continue;
+      if (!streq (name, NTXT (".loops")) && !streq (name, NTXT (".loopview")))
+       continue;
+
+      Elf_Data *data = elf->elf_getdata (sec);
+      size_t LoopSize = (size_t) data->d_size, len;
+      char *LoopData = (char *) data->d_buf;
+      int remainder, i;
+      char src[2 * MAXPATHLEN], buf1[MAXPATHLEN], buf2[MAXPATHLEN];
+      char **dep_str = NULL;
+      bool get_src = false;
+      while ((LoopSize > 0) && !get_src &&
+            (strncmp (LoopData, NTXT ("Source:"), 7) == 0))
+       {
+         // The first three items in a .loops subsection are three strings.
+         //    Source: ...
+         //    Version: ...
+         //    Number of loops: ...
+         sscanf (LoopData, NTXT ("%*s%s"), src);
+         len = strlen (LoopData) + 1;
+         LoopData += len;
+         LoopSize -= len;
+         sscanf (LoopData, NTXT ("%*s%*s%s"), buf1);
+         //    double version   = atof(buf1);
+         len = strlen (LoopData) + 1;
+         LoopData += len;
+         LoopSize -= len;
+         get_src = check_src_name (src);
+         sscanf (LoopData, NTXT ("%*s%*s%*s%s%s"), buf1, buf2);
+         int n_loop = atoi (buf1);
+         int n_depend = atoi (buf2);
+         len = strlen (LoopData) + 1;
+         LoopData += len;
+         LoopSize -= len;
+         if (get_src && (n_loop > 0))
+           {
+             dep_str = new char*[n_loop];
+             for (i = 0; i < n_loop; i++)
+               dep_str[i] = NULL;
+           }
+
+         // printf("Source: %s\nVersion: %f\nLoop#: %d\nDepend#: %d\n",
+         //    src, version, n_loop, n_depend);
+
+         // Read in the strings that contain the list of variables that cause
+         // data dependencies inside of loops. Not every loop has such a list
+         // of variables.
+         //
+         //    Example: if loop #54 has data dependencies caused by the
+         //    variables named i, j and foo, then the string that represents
+         //    this in the .loops section looks like this:
+         //
+         //    .asciz "54:i.j.foo"
+         //
+         //    The variable names are delimited with .
+         //
+         //    For now, store these strings in an array, and add them into
+         //    the loop structure when we read in the numeric loop info
+         //    (that's what we read in next.)
+         //
+         // printf("\tDependenncies:\n");
+         for (i = 0; i < n_depend; i++)
+           {
+             len = strlen (LoopData) + 1;
+             LoopData += len;
+             LoopSize -= len;
+             if (dep_str != NULL)
+               {
+                 char *dep_buf1 = dbe_strdup (LoopData);
+                 char *ptr = strtok (dep_buf1, NTXT (":"));
+                 if (ptr != NULL)
+                   {
+                     int index = atoi (ptr);
+                     bool dep_first = true;
+                     sb.setLength (0);
+                     while ((ptr = strtok (NULL, NTXT (", "))) != NULL)
+                       {
+                         if (dep_first)
+                           dep_first = false;
+                         else
+                           sb.append (NTXT (", "));
+                         sb.append (ptr);
+                       }
+                     if (sb.length () > 0 && index < n_loop)
+                       dep_str[index] = sb.toString ();
+                   }
+                 free (dep_buf1);
+               }
+           }
+
+         // Adjust Data pointer so that it is word aligned.
+         remainder = (int) (((unsigned long) LoopData) % 4);
+         if (remainder != 0)
+           {
+             len = 4 - remainder;
+             LoopData += len;
+             LoopSize -= len;
+           }
+
+         // Read in the loop info, one loop at a time.
+         for (i = 0; i < n_loop; i++)
+           {
+             int loopid = *((int *) LoopData);
+             LoopData += 4;
+             int line_no = *((int *) LoopData);
+             if (line_no < 1) // compiler has trouble on this
+               line_no = 1;
+             LoopData += 4;
+             //            int nest = *((int *) LoopData);
+             LoopData += 4;
+             int parallel = *((int *) LoopData);
+             LoopData += 4;
+             unsigned hints = *((unsigned *) LoopData);
+             LoopData += 4;
+             //            int count = *((int *) LoopData);
+             LoopData += 4;
+             LoopSize -= 24;
+             if (!get_src || (loopid >= n_loop))
+               continue;
+             ComC *citem = new ComC;
+             citem->sec = LOOP_SEC + i;
+             citem->type = hints;
+             citem->visible = CCMV_ALL;
+             citem->line = line_no;
+             citem->com_str = get_lp_com (hints, parallel, dep_str[loopid]);
+             comComs->append (citem);
+           }
+         if (dep_str)
+           {
+             for (i = 0; i < n_loop; i++)
+               free (dep_str[i]);
+             delete[] dep_str;
+             dep_str = NULL;
+           }
+       }
+    }
+}
+
+static char *
+get_lp_com (unsigned hints, int parallel, char *dep)
+{
+  StringBuilder sb;
+  if (parallel == -1)
+    sb.append (GTXT ("Loop below is serial, but parallelizable: "));
+  else if (parallel == 0)
+    sb.append (GTXT ("Loop below is not parallelized: "));
+  else
+    sb.append (GTXT ("Loop below is parallelized: "));
+  switch (hints)
+    {
+    case 0:
+      // No loop mesg will print
+      // strcat(com, GTXT("no hint available"));
+      break;
+    case 1:
+      sb.append (GTXT ("loop contains procedure call"));
+      break;
+    case 2:
+      sb.append (GTXT ("compiler generated two versions of this loop"));
+      break;
+    case 3:
+      {
+       StringBuilder sb_tmp;
+       sb_tmp.sprintf (GTXT ("the variable(s) \"%s\" cause a data dependency in this loop"),
+                       dep ? dep : GTXT ("<Unknown>"));
+       sb.append (&sb_tmp);
+      }
+      break;
+    case 4:
+      sb.append (GTXT ("loop was significantly transformed during optimization"));
+      break;
+    case 5:
+      sb.append (GTXT ("loop may or may not hold enough work to be profitably parallelized"));
+      break;
+    case 6:
+      sb.append (GTXT ("loop was marked by user-inserted pragma"));
+      break;
+    case 7:
+      sb.append (GTXT ("loop contains multiple exits"));
+      break;
+    case 8:
+      sb.append (GTXT ("loop contains I/O, or other function calls, that are not MT safe"));
+      break;
+    case 9:
+      sb.append (GTXT ("loop contains backward flow of control"));
+      break;
+    case 10:
+      sb.append (GTXT ("loop may have been distributed"));
+      break;
+    case 11:
+      sb.append (GTXT ("two loops or more may have been fused"));
+      break;
+    case 12:
+      sb.append (GTXT ("two or more loops may have been interchanged"));
+      break;
+    default:
+      break;
+    }
+  return sb.toString ();
+}
+
+StabReader::StabReader (Elf *_elf, Platform_t platform, int StabSec, int StabStrSec)
+{
+  stabCnt = -1;
+  stabNum = 0;
+  if (_elf == NULL)
+    return;
+  elf = _elf;
+
+  // Get ELF data
+  Elf_Data *data = elf->elf_getdata (StabSec);
+  if (data == NULL)
+    return;
+  uint64_t stabSize = data->d_size;
+  StabData = (char *) data->d_buf;
+  Elf_Internal_Shdr *shdr = elf->get_shdr (StabSec);
+  if (shdr == NULL)
+    return;
+
+  // GCC bug: sh_entsize is 20 for 64 apps on Linux
+  StabEntSize = (platform == Amd64 || platform == Sparcv9) ? 12 : (unsigned) shdr->sh_entsize;
+  if (stabSize == 0 || StabEntSize == 0)
+    return;
+  data = elf->elf_getdata (StabStrSec);
+  if (data == NULL)
+    return;
+  shdr = elf->get_shdr (StabStrSec);
+  if (shdr == NULL)
+    return;
+  StabStrtab = (char *) data->d_buf;
+  StabStrtabEnd = StabStrtab + shdr->sh_size;
+  StrTabSize = 0;
+  stabCnt = (int) (stabSize / StabEntSize);
+}
+
+char *
+StabReader::get_stab (struct stab *np, bool comdat)
+{
+  struct stab *stbp = (struct stab *) (StabData + stabNum * StabEntSize);
+  stabNum++;
+  *np = *stbp;
+  np->n_desc = elf->decode (stbp->n_desc);
+  np->n_strx = elf->decode (stbp->n_strx);
+  np->n_value = elf->decode (stbp->n_value);
+  switch (np->n_type)
+    {
+    case N_UNDF:
+    case N_ILDPAD:
+      // Start of new stab section (or padding)
+      StabStrtab += StrTabSize;
+      StrTabSize = np->n_value;
+    }
+
+  char *str = NULL;
+  if (np->n_strx)
+    {
+      if (comdat && np->n_type == N_FUN && np->n_other == 1)
+       {
+         if (np->n_strx == 1)
+           StrTabSize++;
+         str = StabStrtab + StrTabSize;
+         // Each COMDAT string must be sized to find the next string:
+         StrTabSize += strlen (str) + 1;
+       }
+      else
+       str = StabStrtab + np->n_strx;
+      if (str >= StabStrtabEnd)
+       str = NULL;
+    }
+  if (DEBUG_STABS)
+    {
+      char buf[128];
+      char *s = get_type_name (np->n_type);
+      if (s == NULL)
+       {
+         snprintf (buf, sizeof (buf), NTXT ("n_type=%d"), np->n_type);
+         s = buf;
+       }
+      if (str)
+       {
+         Dprintf (DEBUG_STABS, NTXT ("%4d:  .stabs \"%s\",%s,0x%x,0x%x,0x%x\n"),
+                  stabNum - 1, str, s, (int) np->n_other, (int) np->n_desc,
+                  (int) np->n_value);
+       }
+      else
+       Dprintf (DEBUG_STABS, NTXT ("%4d:  .stabn %s,0x%x,0x%x,0x%x\n"),
+                stabNum - 1, s, (int) np->n_other, (int) np->n_desc,
+                (int) np->n_value);
+    }
+  return str;
+}
+
+void
+StabReader::parse_N_OPT (Module *mod, char *str)
+{
+  if (mod == NULL || str == NULL)
+      return;
+  for (char *s = str; 1; s++)
+    {
+      switch (*s)
+       {
+       case 'd':
+         if (s[1] == 'i' && s[2] == ';')
+           {
+             delete mod->dot_o_file;
+             mod->dot_o_file = NULL;
+           }
+         break;
+       case 's':
+         if ((s[1] == 'i' || s[1] == 'n') && s[2] == ';')
+           {
+             delete mod->dot_o_file;
+             mod->dot_o_file = NULL;
+           }
+         break;
+       }
+      s = strchr (s, ';');
+      if (s == NULL)
+       break;
+    }
+}
+
+Stabs::Stab_status
+Stabs::srcline_Stabs (Module *module, unsigned int StabSec,
+                     unsigned int StabStrSec, bool comdat)
+{
+  StabReader *stabReader = new StabReader (openElf (true), platform, StabSec, StabStrSec);
+  int tot = stabReader->stabCnt;
+  if (tot < 0)
+    {
+      delete stabReader;
+      return DBGD_ERR_NO_STABS;
+    }
+  int n, lineno;
+  char *sbase, *n_so = NTXT (""), curr_src[2 * MAXPATHLEN];
+  Function *newFunc;
+  Sp_lang_code _lang_code = module->lang_code;
+  Vector<Function*> *functions = module->functions;
+  bool no_stabs = true;
+  *curr_src = '\0';
+  Function *func = NULL;
+  int phase = 0;
+  int stabs_level = 0;
+  int xline = 0;
+
+  // Find module
+  for (n = 0; n < tot; n++)
+    {
+      struct stab stb;
+      char *str = stabReader->get_stab (&stb, comdat);
+      if (stb.n_type == N_UNDF)
+       phase = 0;
+      else if (stb.n_type == N_SO)
+       {
+         if (str == NULL || *str == '\0')
+           continue;
+         if (phase == 0)
+           {
+             phase = 1;
+             n_so = str;
+             continue;
+           }
+         phase = 0;
+         sbase = str;
+         if (*str == '/')
+           {
+             if (streq (sbase, module->file_name))
+               break;
+           }
+         else
+           {
+             size_t last = strlen (n_so);
+             if (n_so[last - 1] == '/')
+               last--;
+             if (strncmp (n_so, module->file_name, last) == 0 &&
+                 module->file_name[last] == '/' &&
+                 streq (sbase, module->file_name + last + 1))
+               break;
+           }
+       }
+    }
+  if (n >= tot)
+    {
+      delete stabReader;
+      return DBGD_ERR_NO_STABS;
+    }
+
+  Include *includes = new Include;
+  includes->new_src_file (module->getMainSrc (), 0, NULL);
+  module->hasStabs = true;
+  *curr_src = '\0';
+  phase = 0;
+  for (n++; n < tot; n++)
+    {
+      struct stab stb;
+      char *str = stabReader->get_stab (&stb, comdat);
+      int n_desc = (int) ((unsigned short) stb.n_desc);
+      switch (stb.n_type)
+       {
+       case N_UNDF:
+       case N_SO:
+       case N_ENDM:
+         n = tot;
+         break;
+       case N_ALIAS:
+         if (str == NULL)
+           break;
+         if (is_fortran (_lang_code))
+           {
+             char *p = strchr (str, ':');
+             if (p && streq (p + 1, NTXT ("FMAIN")))
+               {
+                 Function *afunc = find_func (NTXT ("MAIN"), functions, true);
+                 if (afunc)
+                   afunc->set_match_name (dbe_strndup (str, p - str));
+                 break;
+               }
+           }
+       case N_FUN:
+       case N_OUTL:
+         if (str == NULL)
+           break;
+         if (*str == '@')
+           {
+             str++;
+             if (*str == '>' || *str == '<')
+               str++;
+           }
+         if (stabs_level != 0)
+           break;
+
+         // find address of the enclosed function
+         newFunc = find_func (str, functions, is_fortran (_lang_code));
+         if (newFunc == NULL)
+           break;
+         if (func)
+           while (func->popSrcFile ())
+             ;
+         func = newFunc;
+
+         // First line info to cover function from the beginning
+         lineno = xline + n_desc;
+         if (lineno > 0)
+           {
+             // Set the chain of includes for the new function
+             includes->push_src_files (func);
+             func->add_PC_info (0, lineno);
+             no_stabs = false;
+           }
+         break;
+       case N_ENTRY:
+         break;
+       case N_CMDLINE:
+         if (str && !module->comp_flags)
+           {
+             char *comp_flags = strchr (str, ';');
+             if (comp_flags)
+               {
+                 module->comp_flags = dbe_strdup (comp_flags + 1);
+                 module->comp_dir = dbe_strndup (str, comp_flags - str);
+               }
+           }
+         break;
+       case N_LBRAC:
+         stabs_level++;
+         break;
+       case N_RBRAC:
+         stabs_level--;
+         break;
+       case N_XLINE:
+         xline = n_desc << 16;
+         break;
+       case N_SLINE:
+         if (func == NULL)
+           break;
+         no_stabs = false;
+         lineno = xline + n_desc;
+         if (func->line_first <= 0)
+           {
+             // Set the chain of includes for the new function
+             includes->push_src_files (func);
+             func->add_PC_info (0, lineno);
+             break;
+           }
+         if (func->curr_srcfile == NULL)
+           includes->push_src_files (func);
+         if (func->line_first != lineno ||
+             !streq (curr_src, func->getDefSrc ()->get_name ()))
+           func->add_PC_info (stb.n_value, lineno);
+         break;
+       case N_OPT:
+         if ((str != NULL) && streq (str, NTXT ("gcc2_compiled.")))
+           _lang_code = Sp_lang_gcc;
+         switch (elfDbg->elf_getehdr ()->e_type)
+           {
+           case ET_EXEC:
+           case ET_DYN:
+             // set the real object timestamp from the executable's N_OPT stab
+             // due to bug #4796329
+             module->real_timestamp = stb.n_value;
+             break;
+           default:
+             module->curr_timestamp = stb.n_value;
+             break;
+           }
+         break;
+       case N_GSYM:
+         if ((str == NULL) || strncmp (str, NTXT ("__KAI_K"), 7))
+           break;
+         str += 7;
+         if (!strncmp (str, NTXT ("CC_"), 3))
+           _lang_code = Sp_lang_KAI_KCC;
+         else if (!strncmp (str, NTXT ("cc_"), 3))
+           _lang_code = Sp_lang_KAI_Kcc;
+         else if (!strncmp (str, NTXT ("PTS_"), 4) &&
+                  (_lang_code != Sp_lang_KAI_KCC) &&
+                  (_lang_code != Sp_lang_KAI_Kcc))
+           _lang_code = Sp_lang_KAI_KPTS;
+         break;
+       case N_BINCL:
+         includes->new_include_file (module->setIncludeFile (str), func);
+         break;
+       case N_EINCL:
+         includes->end_include_file (func);
+         break;
+       case N_SOL:
+         if (str == NULL)
+           break;
+         lineno = xline + n_desc;
+         if (lineno > 0 && func && func->line_first <= 0)
+           {
+             includes->push_src_files (func);
+             func->add_PC_info (0, lineno);
+             no_stabs = false;
+           }
+         if (streq (sbase, str))
+           {
+             module->setIncludeFile (NULL);
+             snprintf (curr_src, sizeof (curr_src), NTXT ("%s"), module->file_name);
+             includes->new_src_file (module->getMainSrc (), lineno, func);
+           }
+         else
+           {
+             if (streq (sbase, get_basename (str)))
+               {
+                 module->setIncludeFile (NULL);
+                 snprintf (curr_src, sizeof (curr_src), NTXT ("%s"), module->file_name);
+                 includes->new_src_file (module->setIncludeFile (curr_src), lineno, func);
+               }
+             else
+               {
+                 if (*str == '/')
+                   snprintf (curr_src, sizeof (curr_src), NTXT ("%s"), str);
+                 else
+                   {
+                     size_t last = strlen (n_so);
+                     if (last == 0 || n_so[last - 1] != '/')
+                       snprintf (curr_src, sizeof (curr_src), NTXT ("%s/%s"), n_so, str);
+                     else
+                       snprintf (curr_src, sizeof (curr_src), NTXT ("%s%s"), n_so, str);
+                   }
+                 includes->new_src_file (module->setIncludeFile (curr_src), lineno, func);
+               }
+           }
+         break;
+       }
+    }
+  delete includes;
+  delete stabReader;
+  return no_stabs ? DBGD_ERR_NO_STABS : DBGD_ERR_NONE;
+}//srcline_Stabs
+
+static bool
+cmp_func_name (char *fname, size_t len, char *name, bool fortran)
+{
+  return (strncmp (name, fname, len) == 0
+         && (name[len] == 0
+             || (fortran && name[len] == '_' && name[len + 1] == 0)));
+}
+
+Function *
+Stabs::find_func (char *fname, Vector<Function*> *functions, bool fortran, bool inner_names)
+{
+  char *arg, *name;
+  Function *item;
+  int index;
+  size_t len;
+
+  len = strlen (fname);
+  arg = strchr (fname, ':');
+  if (arg != NULL)
+    {
+      if (arg[1] == 'P') // Prototype for function
+       return NULL;
+      len -= strlen (arg);
+    }
+
+  Vec_loop (Function*, functions, index, item)
+  {
+    name = item->get_mangled_name ();
+    if (cmp_func_name (fname, len, name, fortran))
+      return item->cardinal ();
+  }
+
+  if (inner_names)
+    {
+      // Dwarf subprograms may only have plain (non-linker) names
+      // Retry with inner names only
+
+      Vec_loop (Function*, functions, index, item)
+      {
+       name = strrchr (item->get_mangled_name (), '.');
+       if (!name) continue;
+       name++;
+       if (cmp_func_name (fname, len, name, fortran))
+         return item->cardinal ();
+      }
+    }
+  return NULL;
+}
+
+Map<const char*, Symbol*> *
+Stabs::get_elf_symbols ()
+{
+  Elf *elf = openElf (false);
+  if (elf->elfSymbols == NULL)
+    {
+      Map<const char*, Symbol*> *elfSymbols = new StringMap<Symbol*>(128, 128);
+      elf->elfSymbols = elfSymbols;
+      for (int i = 0, sz = SymLst ? SymLst->size () : 0; i < sz; i++)
+       {
+         Symbol *sym = SymLst->fetch (i);
+         elfSymbols->put (sym->name, sym);
+       }
+    }
+  return elf->elfSymbols;
+}
+
+void
+Stabs::read_dwarf_from_dot_o (Module *mod)
+{
+  Dprintf (DEBUG_STABS, NTXT ("stabsModules: %s\n"), STR (mod->get_name ()));
+  Vector<Module*> *mods = mod->dot_o_file->seg_modules;
+  char *bname = get_basename (mod->get_name ());
+  for (int i1 = 0, sz1 = mods ? mods->size () : 0; i1 < sz1; i1++)
+    {
+      Module *m = mods->fetch (i1);
+      Dprintf (DEBUG_STABS, NTXT ("  MOD: %s\n"), STR (m->get_name ()));
+      if (dbe_strcmp (bname, get_basename (m->get_name ())) == 0)
+       {
+         mod->indexStabsLink = m;
+         m->indexStabsLink = mod;
+         break;
+       }
+    }
+  if (mod->indexStabsLink)
+    {
+      mod->dot_o_file->objStabs->openDwarf ()->srcline_Dwarf (mod->indexStabsLink);
+      Map<const char*, Symbol*> *elfSymbols = get_elf_symbols ();
+      Vector<Function*> *funcs = mod->indexStabsLink->functions;
+      for (int i1 = 0, sz1 = funcs ? funcs->size () : 0; i1 < sz1; i1++)
+       {
+         Function *f1 = funcs->fetch (i1);
+         Symbol *sym = elfSymbols->get (f1->get_mangled_name ());
+         if (sym == NULL)
+           continue;
+         Dprintf (DEBUG_STABS, NTXT ("  Symbol: %s func=%p\n"), STR (sym->name), sym->func);
+         Function *f = sym->func;
+         if (f->indexStabsLink)
+           continue;
+         f->indexStabsLink = f1;
+         f1->indexStabsLink = f;
+         f->copy_PCInfo (f1);
+       }
+    }
+}
+
+Stabs::Stab_status
+Stabs::read_archive (LoadObject *lo)
+{
+  if (openElf (true) == NULL)
+    return status;
+  check_Symtab ();
+  if (elfDbg->dwarf)
+    openDwarf ()->archive_Dwarf (lo);
+
+  // get Module/Function lists from stabs info
+  Stab_status statusStabs = DBGD_ERR_NO_STABS;
+#define ARCHIVE_STABS(sec, secStr, comdat) \
+    if ((elfDbg->sec) != 0  && (elfDbg->secStr) != 0 && \
+       archive_Stabs(lo, elfDbg->sec, elfDbg->secStr, comdat) == DBGD_ERR_NONE) \
+       statusStabs = DBGD_ERR_NONE
+
+  // prefer index stabs (where they exist) since they're most appropriate
+  // for loadobjects and might have N_CPROF stabs for ABS/CPF
+  ARCHIVE_STABS (stabIndex, stabIndexStr, true);
+  ARCHIVE_STABS (stabExcl, stabExclStr, false);
+  ARCHIVE_STABS (stab, stabStr, false);
+
+  // Add all unassigned functions to the <unknown> module
+  Symbol *sitem, *alias;
+  int index;
+  Vec_loop (Symbol*, SymLst, index, sitem)
+  {
+    if (sitem->func || (sitem->size == 0) || (sitem->flags & SYM_UNDEF))
+      continue;
+    alias = sitem->alias;
+    if (alias)
+      {
+       if (alias->func == NULL)
+         {
+           alias->func = createFunction (lo, lo->noname, alias);
+           alias->func->alias = alias->func;
+         }
+       if (alias != sitem)
+         {
+           sitem->func = createFunction (lo, alias->func->module, sitem);
+           sitem->func->alias = alias->func;
+         }
+      }
+    else
+      sitem->func = createFunction (lo, lo->noname, sitem);
+  }
+  if (pltSym)
+    {
+      pltSym->func = createFunction (lo, lo->noname, pltSym);
+      pltSym->func->flags |= FUNC_FLAG_PLT;
+    }
+
+  // need Module association, so this must be done after handling Modules
+  check_AnalyzerInfo ();
+
+  if (dwarf && dwarf->status == DBGD_ERR_NONE)
+    return DBGD_ERR_NONE;
+  return statusStabs;
+}//read_archive
+
+Function *
+Stabs::createFunction (LoadObject *lo, Module *module, Symbol *sym)
+{
+  Function *func = dbeSession->createFunction ();
+  func->module = module;
+  func->img_fname = path;
+  func->img_offset = (off_t) sym->img_offset;
+  func->save_addr = sym->save;
+  func->size = (uint32_t) sym->size;
+  func->set_name (sym->name);
+  func->elfSym = sym;
+  module->functions->append (func);
+  lo->functions->append (func);
+  return func;
+}
+
+void
+Stabs::fixSymtabAlias ()
+{
+  int ind, i, k;
+  Symbol *sym, *bestAlias;
+  SymLst->sort (SymImgOffsetCmp);
+  ind = SymLst->size () - 1;
+  for (i = 0; i < ind; i++)
+    {
+      bestAlias = SymLst->fetch (i);
+      if (bestAlias->img_offset == 0) // Ignore this bad symbol
+       continue;
+      sym = SymLst->fetch (i + 1);
+      if (bestAlias->img_offset != sym->img_offset)
+       {
+         if ((bestAlias->size == 0) ||
+             (sym->img_offset < bestAlias->img_offset + bestAlias->size))
+           bestAlias->size = sym->img_offset - bestAlias->img_offset;
+         continue;
+       }
+
+      // Find a "best" alias
+      size_t bestLen = strlen (bestAlias->name);
+      int64_t maxSize = bestAlias->size;
+      for (k = i + 1; k <= ind; k++)
+       {
+         sym = SymLst->fetch (k);
+         if (bestAlias->img_offset != sym->img_offset)
+           { // no more aliases
+             if ((maxSize == 0) ||
+                 (sym->img_offset < bestAlias->img_offset + maxSize))
+               maxSize = sym->img_offset - bestAlias->img_offset;
+             break;
+           }
+         if (maxSize < sym->size)
+           maxSize = sym->size;
+         size_t len = strlen (sym->name);
+         if (len < bestLen)
+           {
+             bestAlias = sym;
+             bestLen = len;
+           }
+       }
+      for (; i < k; i++)
+       {
+         sym = SymLst->fetch (i);
+         sym->alias = bestAlias;
+         sym->size = maxSize;
+       }
+      i--;
+    }
+}
+
+void
+Stabs::check_Symtab ()
+{
+  if (st_check_symtab)
+    return;
+  st_check_symtab = true;
+
+  Elf *elf = openElf (true);
+  if (elf == NULL)
+    return;
+  if (elfDis->plt != 0)
+    {
+      Elf_Internal_Shdr *shdr = elfDis->get_shdr (elfDis->plt);
+      if (shdr)
+       {
+         pltSym = new Symbol ();
+         pltSym->value = shdr->sh_addr;
+         pltSym->size = shdr->sh_size;
+         pltSym->img_offset = shdr->sh_offset;
+         pltSym->name = dbe_strdup (NTXT ("@plt"));
+         pltSym->flags |= SYM_PLT;
+       }
+    }
+  if (elf->symtab)
+    readSymSec (elf->symtab, elf);
+  else
+    {
+      readSymSec (elf->SUNW_ldynsym, elf);
+      readSymSec (elf->dynsym, elf);
+    }
+}
+
+void
+Stabs::readSymSec (unsigned int sec, Elf *elf)
+{
+  Symbol *sitem;
+  Sp_lang_code local_lcode;
+  if (sec == 0)
+    return;
+  // Get ELF data
+  Elf_Data *data = elf->elf_getdata (sec);
+  if (data == NULL)
+    return;
+  uint64_t SymtabSize = data->d_size;
+  Elf_Internal_Shdr *shdr = elf->get_shdr (sec);
+
+  if ((SymtabSize == 0) || (shdr->sh_entsize == 0))
+    return;
+  Elf_Data *data_str = elf->elf_getdata (shdr->sh_link);
+  if (data_str == NULL)
+    return;
+  char *Strtab = (char *) data_str->d_buf;
+
+  // read func symbolic table
+  for (unsigned int n = 0, tot = SymtabSize / shdr->sh_entsize; n < tot; n++)
+    {
+      Elf_Internal_Sym Sym;
+      elf->elf_getsym (data, n, &Sym);
+      const char *st_name = Sym.st_name < data_str->d_size ?
+         (Strtab + Sym.st_name) : NTXT ("no_name");
+      switch (GELF_ST_TYPE (Sym.st_info))
+       {
+       case STT_FUNC:
+         // Skip UNDEF symbols (bug 4817083)
+         if (Sym.st_shndx == 0)
+           {
+             if (Sym.st_value == 0)
+               break;
+             sitem = new Symbol (SymLst);
+             sitem->flags |= SYM_UNDEF;
+             if (pltSym)
+               sitem->img_offset = (uint32_t) (pltSym->img_offset +
+                                               Sym.st_value - pltSym->value);
+           }
+         else
+           {
+             Elf_Internal_Shdr *shdrp = elfDis->get_shdr (Sym.st_shndx);
+             if (shdrp == NULL)
+               break;
+             sitem = new Symbol (SymLst);
+             sitem->img_offset = (uint32_t) (shdrp->sh_offset +
+                                             Sym.st_value - shdrp->sh_addr);
+           }
+         sitem->size = Sym.st_size;
+         sitem->name = dbe_strdup (st_name);
+         sitem->value = is_relocatable () ? sitem->img_offset : Sym.st_value;
+         if (GELF_ST_BIND (Sym.st_info) == STB_LOCAL)
+           {
+             sitem->local_ind = LocalFile->size () - 1;
+             LocalLst->append (sitem);
+           }
+         break;
+       case STT_NOTYPE:
+         if (streq (st_name, NTXT ("gcc2_compiled.")))
+           {
+             sitem = new Symbol (SymLst);
+             sitem->lang_code = Sp_lang_gcc;
+             sitem->name = dbe_strdup (st_name);
+             sitem->local_ind = LocalFile->size () - 1;
+             LocalLst->append (sitem);
+           }
+         break;
+       case STT_OBJECT:
+         if (!strncmp (st_name, NTXT ("__KAI_KPTS_"), 11))
+           local_lcode = Sp_lang_KAI_KPTS;
+         else if (!strncmp (st_name, NTXT ("__KAI_KCC_"), 10))
+           local_lcode = Sp_lang_KAI_KCC;
+         else if (!strncmp (st_name, NTXT ("__KAI_Kcc_"), 10))
+           local_lcode = Sp_lang_KAI_Kcc;
+         else
+           break;
+         sitem = new Symbol (LocalLst);
+         sitem->lang_code = local_lcode;
+         sitem->name = dbe_strdup (st_name);
+         break;
+       case STT_FILE:
+         {
+           int last = LocalFile->size () - 1;
+           if (last >= 0 && LocalFileIdx->fetch (last) == LocalLst->size ())
+             {
+               // There were no local functions in the latest file.
+               free (LocalFile->get (last));
+               LocalFile->store (last, dbe_strdup (st_name));
+             }
+           else
+             {
+               LocalFile->append (dbe_strdup (st_name));
+               LocalFileIdx->append (LocalLst->size ());
+             }
+           break;
+         }
+       }
+    }
+  fixSymtabAlias ();
+  SymLst->sort (SymValueCmp);
+  get_save_addr (elf->need_swap_endian);
+  dump ();
+}//check_Symtab
+
+void
+Stabs::check_Relocs ()
+{
+  // We may have many relocation tables to process: .rela.text%foo,
+  // rela.text%bar, etc. On Intel, compilers generate .rel.text sections
+  // which have to be processed as well. A lot of rework is needed here.
+  Symbol *sptr = NULL;
+  if (st_check_relocs)
+    return;
+  st_check_relocs = true;
+
+  Elf *elf = openElf (false);
+  if (elf == NULL)
+    return;
+  for (unsigned int sec = 1; sec < elf->elf_getehdr ()->e_shnum; sec++)
+    {
+      bool use_rela, use_PLT;
+      char *name = elf->get_sec_name (sec);
+      if (name == NULL)
+       continue;
+      if (strncmp (name, NTXT (".rela.text"), 10) == 0)
+       {
+         use_rela = true;
+         use_PLT = false;
+       }
+      else if (streq (name, NTXT (".rela.plt")))
+       {
+         use_rela = true;
+         use_PLT = true;
+       }
+      else if (strncmp (name, NTXT (".rel.text"), 9) == 0)
+       {
+         use_rela = false;
+         use_PLT = false;
+       }
+      else if (streq (name, NTXT (".rel.plt")))
+       {
+         use_rela = false;
+         use_PLT = true;
+       }
+      else
+       continue;
+
+      Elf_Internal_Shdr *shdr = elf->get_shdr (sec);
+      if (shdr == NULL)
+       continue;
+
+      // Get ELF data
+      Elf_Data *data = elf->elf_getdata (sec);
+      if (data == NULL)
+       continue;
+      uint64_t ScnSize = data->d_size;
+      uint64_t EntSize = shdr->sh_entsize;
+      if ((ScnSize == 0) || (EntSize == 0))
+       continue;
+      int tot = (int) (ScnSize / EntSize);
+
+      // Get corresponding text section
+      Elf_Internal_Shdr *shdr_txt = elf->get_shdr (shdr->sh_info);
+      if (shdr_txt == NULL)
+       continue;
+      if (!(shdr_txt->sh_flags & SHF_EXECINSTR))
+       continue;
+
+      // Get corresponding symbol table section
+      Elf_Internal_Shdr *shdr_sym = elf->get_shdr (shdr->sh_link);
+      if (shdr_sym == NULL)
+       continue;
+      Elf_Data *data_sym = elf->elf_getdata (shdr->sh_link);
+
+      // Get corresponding string table section
+      Elf_Data *data_str = elf->elf_getdata (shdr_sym->sh_link);
+      if (data_str == NULL)
+       continue;
+      char *Strtab = (char*) data_str->d_buf;
+      for (int n = 0; n < tot; n++)
+       {
+         Elf_Internal_Sym sym;
+         Elf_Internal_Rela rela;
+         char *symName;
+         if (use_rela)
+           elf->elf_getrela (data, n, &rela);
+         else
+           {
+             // GElf_Rela is extended GElf_Rel
+             elf->elf_getrel (data, n, &rela);
+             rela.r_addend = 0;
+           }
+
+         int ndx = (int) GELF_R_SYM (rela.r_info);
+         elf->elf_getsym (data_sym, ndx, &sym);
+         switch (GELF_ST_TYPE (sym.st_info))
+           {
+           case STT_FUNC:
+           case STT_OBJECT:
+           case STT_NOTYPE:
+             if (sym.st_name == 0 || sym.st_name >= data_str->d_size)
+               continue;
+             symName = Strtab + sym.st_name;
+             break;
+           case STT_SECTION:
+             {
+               Elf_Internal_Shdr *secHdr = elf->get_shdr (sym.st_shndx);
+               if (secHdr == NULL)
+                 continue;
+               if (sptr == NULL)
+                 sptr = new Symbol;
+               sptr->value = secHdr->sh_offset + rela.r_addend;
+               long index = SymLst->bisearch (0, -1, &sptr, SymFindCmp);
+               if (index == -1)
+                 continue;
+               Symbol *sp = SymLst->fetch (index);
+               if (sptr->value != sp->value)
+                 continue;
+               symName = sp->name;
+               break;
+             }
+           default:
+             continue;
+           }
+         Reloc *reloc = new Reloc;
+         reloc->name = dbe_strdup (symName);
+         reloc->type = GELF_R_TYPE (rela.r_info);
+         reloc->value = use_PLT ? rela.r_offset
+                 : rela.r_offset + shdr_txt->sh_offset;
+         reloc->addend = rela.r_addend;
+         if (use_PLT)
+           RelPLTLst->append (reloc);
+         else
+           RelLst->append (reloc);
+       }
+    }
+  delete sptr;
+  RelLst->sort (RelValueCmp);
+} //check_Relocs
+
+void
+Stabs::get_save_addr (bool need_swap_endian)
+{
+  if (elfDis->is_Intel ())
+    {
+      for (int j = 0, sz = SymLst ? SymLst->size () : 0; j < sz; j++)
+       {
+         Symbol *sitem = SymLst->fetch (j);
+         sitem->save = 0;
+       }
+      return;
+    }
+  for (int j = 0, sz = SymLst ? SymLst->size () : 0; j < sz; j++)
+    {
+      Symbol *sitem = SymLst->fetch (j);
+      sitem->save = FUNC_NO_SAVE;
+
+      // If an image offset is not known skip it.
+      // Works for artificial symbols like '@plt' as well.
+      if (sitem->img_offset == 0)
+       continue;
+
+      bool is_o7_moved = false;
+      int64_t off = sitem->img_offset;
+      for (int i = 0; i < sitem->size; i += 4)
+       {
+         unsigned int cmd;
+         if (elfDis->get_data (off, sizeof (cmd), &cmd) == NULL)
+           break;
+         if (need_swap_endian)
+           SWAP_ENDIAN (cmd);
+         off += sizeof (cmd);
+         if ((cmd & 0xffffc000) == 0x9de38000)
+           { // save %sp, ??, %sp
+             sitem->save = i;
+             break;
+           }
+         else if ((cmd & 0xc0000000) == 0x40000000 || // call ??
+        (cmd & 0xfff80000) == 0xbfc00000)
+           { // jmpl ??, %o7
+             if (!is_o7_moved)
+               {
+                 sitem->save = FUNC_ROOT;
+                 break;
+               }
+           }
+         else if ((cmd & 0xc1ffe01f) == 0x8010000f)    // or %g0,%o7,??
+           is_o7_moved = true;
+       }
+    }
+}
+
+uint64_t
+Stabs::mapOffsetToAddress (uint64_t img_offset)
+{
+  Elf *elf = openElf (false);
+  if (elf == NULL)
+    return 0;
+  if (is_relocatable ())
+    return img_offset;
+  for (unsigned int sec = 1; sec < elf->elf_getehdr ()->e_shnum; sec++)
+    {
+      Elf_Internal_Shdr *shdr = elf->get_shdr (sec);
+      if (shdr == NULL)
+       continue;
+      if (img_offset >= (uint64_t) shdr->sh_offset
+         && img_offset < (uint64_t) (shdr->sh_offset + shdr->sh_size))
+       return shdr->sh_addr + (img_offset - shdr->sh_offset);
+    }
+  return 0;
+}
+
+Stabs::Stab_status
+Stabs::archive_Stabs (LoadObject *lo, unsigned int StabSec,
+                     unsigned int StabStrSec, bool comdat)
+{
+  StabReader *stabReader = new StabReader (openElf (true), platform, StabSec, StabStrSec);
+  int tot = stabReader->stabCnt;
+  if (tot < 0)
+    {
+      delete stabReader;
+      return DBGD_ERR_NO_STABS;
+    }
+
+  char *sbase = NTXT (""), *arg, *fname, sname[2 * MAXPATHLEN];
+  int lastMod, phase, stabs_level, modCnt = 0;
+  Function *func = NULL;
+  Module *mod;
+#define INIT_MOD    phase = 0; stabs_level = 0; *sname = '\0'; mod = NULL
+
+  bool updateStabsMod = false;
+  if (comdat && ((elfDbg->elf_getehdr ()->e_type == ET_EXEC) || (elfDbg->elf_getehdr ()->e_type == ET_DYN)))
+    {
+      if (stabsModules == NULL)
+       stabsModules = new Vector<Module*>();
+      updateStabsMod = true;
+    }
+  INIT_MOD;
+  lastMod = lo->seg_modules->size ();
+
+  for (int n = 0; n < tot; n++)
+    {
+      struct stab stb;
+      char *str = stabReader->get_stab (&stb, comdat);
+      switch (stb.n_type)
+       {
+       case N_FUN:
+         // Ignore a COMDAT function, if there are two or more modules in 'lo'
+         if (comdat && stb.n_other == 1 && modCnt > 1)
+           break;
+       case N_OUTL:
+       case N_ALIAS:
+       case N_ENTRY:
+         if (mod == NULL || str == NULL
+             || (stb.n_type != N_ENTRY && stabs_level != 0))
+           break;
+         if (*str == '@')
+           {
+             str++;
+             if (*str == '>' || *str == '<')
+               str++;
+           }
+
+         fname = dbe_strdup (str);
+         arg = strchr (fname, ':');
+         if (arg != NULL)
+           {
+             if (!strncmp (arg, NTXT (":P"), 2))
+               { // just prototype
+                 free (fname);
+                 break;
+               }
+             *arg = '\0';
+           }
+
+         func = append_Function (mod, fname);
+         free (fname);
+         break;
+       case N_CMDLINE:
+         if (str && mod)
+           {
+             char *comp_flags = strchr (str, ';');
+             if (comp_flags)
+               {
+                 mod->comp_flags = dbe_strdup (comp_flags + 1);
+                 mod->comp_dir = dbe_strndup (str, comp_flags - str);
+               }
+           }
+         break;
+       case N_LBRAC:
+         stabs_level++;
+         break;
+       case N_RBRAC:
+         stabs_level--;
+         break;
+       case N_UNDF:
+         INIT_MOD;
+         break;
+       case N_ENDM:
+         INIT_MOD;
+         break;
+       case N_OPT:
+         stabReader->parse_N_OPT (mod, str);
+         if (mod && (str != NULL) && streq (str, NTXT ("gcc2_compiled.")))
+           // Is it anachronism ?
+           mod->lang_code = Sp_lang_gcc;
+         break;
+       case N_GSYM:
+         if (mod && (str != NULL))
+           {
+             if (strncmp (str, NTXT ("__KAI_K"), 7))
+               break;
+             str += 7;
+             if (!strncmp (str, NTXT ("CC_"), 3))
+               mod->lang_code = Sp_lang_KAI_KCC;
+             else if (!strncmp (str, NTXT ("cc_"), 3))
+               mod->lang_code = Sp_lang_KAI_Kcc;
+             else if (!strncmp (str, NTXT ("PTS_"), 4) &&
+                      (mod->lang_code != Sp_lang_KAI_KCC) &&
+                      (mod->lang_code != Sp_lang_KAI_Kcc))
+               mod->lang_code = Sp_lang_KAI_KPTS;
+           }
+         break;
+       case N_SO:
+         if (str == NULL || *str == '\0')
+           {
+             INIT_MOD;
+             break;
+           }
+         if (phase == 0)
+           {
+             phase = 1;
+             sbase = str;
+           }
+         else
+           {
+             if (*str == '/')
+               sbase = str;
+             else
+               {
+                 size_t last = strlen (sbase);
+                 if (last == 0 || sbase[last - 1] != '/')
+                   snprintf (sname, sizeof (sname), NTXT ("%s/%s"), sbase, str);
+                 else
+                   snprintf (sname, sizeof (sname), NTXT ("%s%s"), sbase, str);
+                 sbase = sname;
+               }
+             mod = append_Module (lo, sbase, lastMod);
+             if (updateStabsMod)
+               stabsModules->append (mod);
+             mod->hasStabs = true;
+             modCnt++;
+             if ((mod->lang_code != Sp_lang_gcc) &&
+                 (mod->lang_code != Sp_lang_KAI_KPTS) &&
+                 (mod->lang_code != Sp_lang_KAI_KCC) &&
+                 (mod->lang_code != Sp_lang_KAI_Kcc))
+               mod->lang_code = (Sp_lang_code) stb.n_desc;
+             *sname = '\0';
+             phase = 0;
+           }
+         break;
+       case N_OBJ:
+         if (str == NULL)
+           break;
+         if (phase == 0)
+           {
+             phase = 1;
+             sbase = str;
+           }
+         else
+           {
+             if (*str == '/')
+               sbase = str;
+             else
+               {
+                 size_t last = strlen (sbase);
+                 if (last == 0 || sbase[last - 1] != '/')
+                   snprintf (sname, sizeof (sname), NTXT ("%s/%s"), sbase, str);
+                 else
+                   snprintf (sname, sizeof (sname), NTXT ("%s%s"), sbase, str);
+                 sbase = sname;
+               }
+             if (mod && (mod->dot_o_file == NULL))
+               {
+                 if (strcmp (sbase, NTXT ("/")) == 0)
+                   mod->set_name (dbe_strdup (path));
+                 else
+                   {
+                     mod->set_name (dbe_strdup (sbase));
+                     mod->dot_o_file = mod->createLoadObject (sbase);
+                   }
+               }
+             *sname = '\0';
+             phase = 0;
+           }
+         break;
+       case N_CPROF:
+         cpf_stabs_t map;
+         Dprintf (DEBUG_STABS, NTXT ("N_CPROF n_desc=%x n_value=0x%04x mod=%s\n"),
+                  stb.n_desc, stb.n_value, (mod == NULL) ? NTXT ("???") : mod->get_name ());
+         map.type = stb.n_desc;
+         map.offset = stb.n_value;
+         map.module = mod;
+         analyzerInfoMap.append (map);
+         break;
+       }
+    }
+  delete stabReader;
+  return func ? DBGD_ERR_NONE : DBGD_ERR_NO_STABS;
+}
+
+Module *
+Stabs::append_Module (LoadObject *lo, char *name, int lastMod)
+{
+  Module *module;
+  int size;
+  Symbol *sitem;
+
+  if (lo->seg_modules != NULL)
+    {
+      size = lo->seg_modules->size ();
+      if (size < lastMod)
+       lastMod = size;
+      for (int i = 0; i < lastMod; i++)
+       {
+         module = lo->seg_modules->fetch (i);
+         if (module->linkerStabName && streq (module->linkerStabName, name))
+           return module;
+       }
+    }
+  module = dbeSession->createModule (lo, NULL);
+  module->set_file_name (dbe_strdup (name));
+  module->linkerStabName = dbe_strdup (module->file_name);
+
+  // Append all functions with 'local_ind == -1' to the module.
+  if (LocalLst->size () > 0)
+    {
+      sitem = LocalLst->fetch (0);
+      if (!sitem->defined && sitem->local_ind == -1)
+       // Append all functions with 'local_ind == -1' to the module.
+       append_local_funcs (module, 0);
+    }
+
+  // Append local func
+  char *basename = get_basename (name);
+  size = LocalFile->size ();
+  for (int i = 0; i < size; i++)
+    {
+      if (streq (basename, LocalFile->fetch (i)))
+       {
+         int local_ind = LocalFileIdx->fetch (i);
+         if (local_ind >= LocalLst->size ())
+           break;
+         sitem = LocalLst->fetch (local_ind);
+         if (!sitem->defined)
+           {
+             append_local_funcs (module, local_ind);
+             break;
+           }
+       }
+    }
+  return module;
+}
+
+void
+Stabs::append_local_funcs (Module *module, int first_ind)
+{
+  Symbol *sitem = LocalLst->fetch (first_ind);
+  int local_ind = sitem->local_ind;
+  int size = LocalLst->size ();
+  for (int i = first_ind; i < size; i++)
+    {
+      sitem = LocalLst->fetch (i);
+      if (sitem->local_ind != local_ind)
+       break;
+      sitem->defined = true;
+
+      // 3rd party compiled. e.g., Gcc or KAI compiled
+      if (sitem->lang_code != Sp_lang_unknown)
+       {
+         if (module->lang_code == Sp_lang_unknown)
+           module->lang_code = sitem->lang_code;
+         continue;
+       }
+      if (sitem->func)
+       continue;
+      Function *func = dbeSession->createFunction ();
+      sitem->func = func;
+      func->img_fname = path;
+      func->img_offset = (off_t) sitem->img_offset;
+      func->save_addr = (uint32_t) sitem->save;
+      func->size = (uint32_t) sitem->size;
+      func->module = module;
+      func->set_name (sitem->name);
+      module->functions->append (func);
+      module->loadobject->functions->append (func);
+    }
+}
+
+Function *
+Stabs::append_Function (Module *module, char *fname)
+{
+  Symbol *sitem, *sptr;
+  Function *func;
+  long sid, index;
+  char *name;
+  if (SymLstByName == NULL)
+    {
+      SymLstByName = SymLst->copy ();
+      SymLstByName->sort (SymNameCmp);
+    }
+  sptr = new Symbol;
+  if (module->lang_code == N_SO_FORTRAN || module->lang_code == N_SO_FORTRAN90)
+    {
+      char *fortran = dbe_sprintf (NTXT ("%s_"), fname); // FORTRAN name
+      sptr->name = fortran;
+      sid = SymLstByName->bisearch (0, -1, &sptr, SymNameCmp);
+      if (sid == -1)
+       {
+         free (fortran);
+         sptr->name = fname;
+         sid = SymLstByName->bisearch (0, -1, &sptr, SymNameCmp);
+       }
+      else
+       fname = fortran;
+    }
+  else
+    {
+      sptr->name = fname;
+      sid = SymLstByName->bisearch (0, -1, &sptr, SymNameCmp);
+    }
+  sptr->name = NULL;
+  delete sptr;
+
+  if (sid == -1)
+    {
+      Vec_loop (Symbol*, SymLstByName, index, sitem)
+      {
+       if (strncmp (sitem->name, NTXT ("$X"), 2) == 0
+           || strncmp (sitem->name, NTXT (".X"), 2) == 0)
+         {
+           char *n = strchr (((sitem->name) + 2), (int) '.');
+           if (n != NULL)
+             name = n + 1;
+           else
+             name = sitem->name;
+         }
+       else
+         name = sitem->name;
+       if (name != NULL && fname != NULL && (strcmp (name, fname) == 0))
+         {
+           sid = index;
+           break;
+         }
+      }
+    }
+  if (sid != -1)
+    {
+      sitem = SymLstByName->fetch (sid);
+      if (sitem->alias)
+       sitem = sitem->alias;
+      if (sitem->func)
+       return sitem->func;
+      sitem->func = func = dbeSession->createFunction ();
+      func->img_fname = path;
+      func->img_offset = (off_t) sitem->img_offset;
+      func->save_addr = (uint32_t) sitem->save;
+      func->size = (uint32_t) sitem->size;
+    }
+  else
+    func = dbeSession->createFunction ();
+
+  func->module = module;
+  func->set_name (fname);
+  module->functions->append (func);
+  module->loadobject->functions->append (func);
+  return func;
+}
+
+Function *
+Stabs::append_Function (Module *module, char *linkerName, uint64_t pc)
+{
+  Dprintf (DEBUG_STABS, NTXT ("Stabs::append_Function: module=%s linkerName=%s pc=0x%llx\n"),
+          STR (module->get_name ()), STR (linkerName), (unsigned long long) pc);
+  long i;
+  Symbol *sitem = NULL, *sp;
+  Function *func;
+  sp = new Symbol;
+  if (pc)
+    {
+      sp->value = pc;
+      i = SymLst->bisearch (0, -1, &sp, SymFindCmp);
+      if (i != -1)
+       sitem = SymLst->fetch (i);
+    }
+
+  if (!sitem && linkerName)
+    {
+      if (SymLstByName == NULL)
+       {
+         SymLstByName = SymLst->copy ();
+         SymLstByName->sort (SymNameCmp);
+       }
+      sp->name = linkerName;
+      i = SymLstByName->bisearch (0, -1, &sp, SymNameCmp);
+      sp->name = NULL;
+      if (i != -1)
+       sitem = SymLstByName->fetch (i);
+    }
+  delete sp;
+
+  if (!sitem)
+    return NULL;
+  if (sitem->alias)
+    sitem = sitem->alias;
+  if (sitem->func)
+    return sitem->func;
+
+  sitem->func = func = dbeSession->createFunction ();
+  func->img_fname = path;
+  func->img_offset = (off_t) sitem->img_offset;
+  func->save_addr = (uint32_t) sitem->save;
+  func->size = (uint32_t) sitem->size;
+  func->module = module;
+  func->set_name (sitem->name); //XXXX ?? Now call it to set obj->name
+  module->functions->append (func);
+  module->loadobject->functions->append (func);
+  return func;
+}// Stabs::append_Function
+
+Dwarf *
+Stabs::openDwarf ()
+{
+  if (dwarf == NULL)
+    {
+      dwarf = new Dwarf (this);
+      check_Symtab ();
+    }
+  return dwarf;
+}
+
+void
+Stabs::read_hwcprof_info (Module *module)
+{
+  openDwarf ()->read_hwcprof_info (module);
+}
+
+void
+Stabs::dump ()
+{
+  if (!DUMP_ELF_SYM)
+    return;
+  printf (NTXT ("\n======= Stabs::dump: %s =========\n"), path ? path : NTXT ("NULL"));
+  int i, sz;
+  if (LocalFile)
+    {
+      sz = LocalFile->size ();
+      for (i = 0; i < sz; i++)
+       printf ("  %3d: %5d '%s'\n", i, LocalFileIdx->fetch (i),
+               LocalFile->fetch (i));
+    }
+  Symbol::dump (SymLst, NTXT ("SymLst"));
+  Symbol::dump (LocalLst, NTXT ("LocalLst"));
+  printf (NTXT ("\n===== END of Stabs::dump: %s =========\n\n"),
+  path ? path : NTXT ("NULL"));
+}
+
+///////////////////////////////////////////////////////////////////////////////
+//  Class Include
+Include::Include ()
+{
+  stack = new Vector<SrcFileInfo*>;
+}
+
+Include::~Include ()
+{
+  Destroy (stack);
+}
+
+void
+Include::new_src_file (SourceFile *source, int lineno, Function *func)
+{
+  for (int index = stack->size () - 1; index >= 0; index--)
+    {
+      if (source == stack->fetch (index)->srcfile)
+       {
+         for (int i = stack->size () - 1; i > index; i--)
+           {
+             delete stack->remove (i);
+             if (func && func->line_first > 0)
+               func->popSrcFile ();
+           }
+         return;
+       }
+    }
+  if (func && func->line_first > 0)
+    func->pushSrcFile (source, lineno);
+
+  SrcFileInfo *sfinfo = new SrcFileInfo;
+  sfinfo->srcfile = source;
+  sfinfo->lineno = lineno;
+  stack->append (sfinfo);
+}
+
+void
+Include::push_src_files (Function *func)
+{
+  int index;
+  SrcFileInfo *sfinfo;
+
+  if (func->line_first <= 0 && stack->size () > 0)
+    {
+      sfinfo = stack->fetch (stack->size () - 1);
+      func->setDefSrc (sfinfo->srcfile);
+    }
+  Vec_loop (SrcFileInfo*, stack, index, sfinfo)
+  {
+    func->pushSrcFile (sfinfo->srcfile, sfinfo->lineno);
+  }
+}
+
+void
+Include::new_include_file (SourceFile *source, Function *func)
+{
+  if (stack->size () == 1 && stack->fetch (0)->srcfile == source)
+    // workaroud for gcc; gcc creates 'N_BINCL' stab for main source
+    return;
+  if (func && func->line_first > 0)
+    func->pushSrcFile (source, 0);
+
+  SrcFileInfo *sfinfo = new SrcFileInfo;
+  sfinfo->srcfile = source;
+  sfinfo->lineno = 0;
+  stack->append (sfinfo);
+}
+
+void
+Include::end_include_file (Function *func)
+{
+  int index = stack->size () - 1;
+  if (index > 0)
+    {
+      delete stack->remove (index);
+      if (func && func->line_first > 0)
+       func->popSrcFile ();
+    }
+}
+
+#define RET_S(x)   if (t == x) return (char *) #x
+char *
+StabReader::get_type_name (int t)
+{
+  RET_S (N_UNDF);
+  RET_S (N_ABS);
+  RET_S (N_TEXT);
+  RET_S (N_DATA);
+  RET_S (N_BSS);
+  RET_S (N_COMM);
+  RET_S (N_FN);
+  RET_S (N_EXT);
+  RET_S (N_TYPE);
+  RET_S (N_GSYM);
+  RET_S (N_FNAME);
+  RET_S (N_FUN);
+  RET_S (N_OUTL);
+  RET_S (N_STSYM);
+  RET_S (N_TSTSYM);
+  RET_S (N_LCSYM);
+  RET_S (N_TLCSYM);
+  RET_S (N_MAIN);
+  RET_S (N_ROSYM);
+  RET_S (N_FLSYM);
+  RET_S (N_TFLSYM);
+  RET_S (N_PC);
+  RET_S (N_CMDLINE);
+  RET_S (N_OBJ);
+  RET_S (N_OPT);
+  RET_S (N_RSYM);
+  RET_S (N_SLINE);
+  RET_S (N_XLINE);
+  RET_S (N_ILDPAD);
+  RET_S (N_SSYM);
+  RET_S (N_ENDM);
+  RET_S (N_SO);
+  RET_S (N_MOD);
+  RET_S (N_EMOD);
+  RET_S (N_READ_MOD);
+  RET_S (N_ALIAS);
+  RET_S (N_LSYM);
+  RET_S (N_BINCL);
+  RET_S (N_SOL);
+  RET_S (N_PSYM);
+  RET_S (N_EINCL);
+  RET_S (N_ENTRY);
+  RET_S (N_SINCL);
+  RET_S (N_LBRAC);
+  RET_S (N_EXCL);
+  RET_S (N_USING);
+  RET_S (N_ISYM);
+  RET_S (N_ESYM);
+  RET_S (N_PATCH);
+  RET_S (N_CONSTRUCT);
+  RET_S (N_DESTRUCT);
+  RET_S (N_CODETAG);
+  RET_S (N_FUN_CHILD);
+  RET_S (N_RBRAC);
+  RET_S (N_BCOMM);
+  RET_S (N_TCOMM);
+  RET_S (N_ECOMM);
+  RET_S (N_XCOMM);
+  RET_S (N_ECOML);
+  RET_S (N_WITH);
+  RET_S (N_LENG);
+  RET_S (N_CPROF);
+  RET_S (N_BROWS);
+  RET_S (N_FUN_PURE);
+  RET_S (N_FUN_ELEMENTAL);
+  RET_S (N_FUN_RECURSIVE);
+  RET_S (N_FUN_AMD64_PARMDUMP);
+  RET_S (N_SYM_OMP_TLS);
+  RET_S (N_SO_AS);
+  RET_S (N_SO_C);
+  RET_S (N_SO_ANSI_C);
+  RET_S (N_SO_CC);
+  RET_S (N_SO_FORTRAN);
+  RET_S (N_SO_FORTRAN77);
+  RET_S (N_SO_PASCAL);
+  RET_S (N_SO_FORTRAN90);
+  RET_S (N_SO_JAVA);
+  RET_S (N_SO_C99);
+  return NULL;
+}
diff --git a/gprofng/src/Stabs.h b/gprofng/src/Stabs.h
new file mode 100644 (file)
index 0000000..1a7443a
--- /dev/null
@@ -0,0 +1,160 @@
+/* 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 _STABS_H
+#define _STABS_H
+
+#include "dbe_structs.h"
+#include "vec.h"
+
+enum cpf_instr_type_t {
+    CPF_INSTR_TYPE_LD = 0,              // profiled load instruction
+    CPF_INSTR_TYPE_ST,                  // profiled store instruction
+    CPF_INSTR_TYPE_PREFETCH,            // profiled prefetch instruction
+    CPF_INSTR_TYPE_BRTARGET,            // branch target
+    CPF_INSTR_TYPE_UNKNOWN,             // unidentified instruction
+    CPF_INSTR_TYPE_NTYPES               // total # of instr types
+};
+
+class Function;
+class LoadObject;
+class Module;
+class ComC;
+class Elf;
+class Dwarf;
+class Symbol;
+class Reloc;
+struct cpf_stabs_t;
+class SourceFile;
+template <typename Key_t, typename Value_t> class Map;
+
+class Include {
+  public:
+    typedef struct {
+       SourceFile  *srcfile;
+       int         lineno;
+    } SrcFileInfo;
+    Include();
+    ~Include();
+    void    new_src_file(SourceFile *source, int lineno, Function *func = NULL);
+    void    new_include_file(SourceFile *source, Function *func);
+    void    end_include_file(Function *func);
+    void    push_src_files(Function *func);
+
+  private:
+    Vector<SrcFileInfo*> *stack;
+};
+
+// Stabs object
+class Stabs {
+  public:
+
+    enum Stab_status {
+       DBGD_ERR_NONE,
+       DBGD_ERR_CANT_OPEN_FILE,
+       DBGD_ERR_BAD_ELF_LIB,
+       DBGD_ERR_BAD_ELF_FORMAT,
+       DBGD_ERR_NO_STABS,
+       DBGD_ERR_BAD_STABS,
+       DBGD_ERR_NO_DWARF,
+       DBGD_ERR_CHK_SUM
+    };
+
+    static Stabs *NewStabs(char *_path, char *lo_name);
+    Stabs(char *_path, char *_lo_name);
+    ~Stabs();
+
+    bool       is_relocatable(){ return isRelocatable; }
+    long long  get_textsz()    { return textsz; }
+    Platform_t get_platform()  { return platform; }
+    WSize_t    get_class()     { return wsize;}
+    Stab_status        get_status()    { return status;}
+
+    Stab_status        read_stabs(ino64_t srcInode, Module *module, Vector<ComC*> *comComs, bool readDwarf = false);
+    Stab_status        read_archive(LoadObject *lo);
+    bool       read_symbols(Vector<Function*> *functions);
+    uint64_t   mapOffsetToAddress(uint64_t img_offset);
+    char       *sym_name(uint64_t target, uint64_t instr, int flag);
+  Elf *openElf (bool dbg_info = false);
+    void        read_hwcprof_info(Module *module);
+    void        dump();
+    void        read_dwarf_from_dot_o(Module *mod);
+
+    static bool is_fortran(Sp_lang_code lc) { return (lc == Sp_lang_fortran) || (lc == Sp_lang_fortran90); }
+    static Function *find_func(char *fname, Vector<Function*> *functions, bool fortran, bool inner_names=false);
+    Module     *append_Module(LoadObject *lo, char *name, int lastMod = 0);
+    Function   *append_Function(Module *module, char *fname);
+    Function   *append_Function(Module *module, char *linkerName, uint64_t pc);
+    Function   *map_PC_to_func(uint64_t pc, uint64_t &low_pc, Vector<Function*> *functions);
+    char               *path;                  // path to the object file
+    char                *lo_name;       // User name of load object
+
+  private:
+  Elf *elfDbg; // ELF with debug info
+  Elf *elfDis; // ELF for disasm
+    Stab_status                status;                 // current stabs status
+
+    long long          textsz;                 // text segment size
+    Platform_t         platform;               // Sparc, Sparcv9, Intel
+    WSize_t            wsize;                  // word size: 32 or 64
+    bool               isRelocatable;
+    Symbol              *last_PC_to_sym;
+
+    Vector<cpf_stabs_t> analyzerInfoMap;        // stabs->section mapping
+
+    bool               check_Comm(Vector<ComC*> *comComs);
+    void               check_Info(Vector<ComC*> *comComs);
+    void               check_Loop(Vector<ComC*> *comComs);
+    void                check_AnalyzerInfo();
+    void                append_local_funcs(Module *module, int first_ind);
+  Stab_status srcline_Stabs (Module *module, unsigned int StabSec, unsigned int StabStrSec, bool comdat);
+  Stab_status archive_Stabs (LoadObject *lo, unsigned int StabSec, unsigned int StabStrSec, bool comdat);
+
+    // Interface with Elf Symbol Table
+    void                check_Symtab();
+    void                readSymSec(unsigned int sec, Elf *elf);
+    void                check_Relocs();
+    void                get_save_addr(bool need_swap_endian);
+    Symbol              *map_PC_to_sym(uint64_t pc);
+    Symbol              *pltSym;
+    Vector<Symbol*>    *SymLst;                // list of func symbols
+    Vector<Symbol*>    *SymLstByName;          // list of func symbols sorted by Name
+    Vector<Reloc*>     *RelLst;                // list of text relocations
+    Vector<Reloc*>     *RelPLTLst;             // list of PLT relocations
+    Vector<Symbol*>    *LocalLst;              // list of local func symbols
+    Vector<char*>      *LocalFile;             // list of local files
+    Vector<int>                *LocalFileIdx;          // start index in LocalLst
+
+    Elf         *openElf(char *fname, Stab_status &st);
+    Map<const char*, Symbol*> *get_elf_symbols();
+    Dwarf       *dwarf;
+
+    bool        st_check_symtab, st_check_relocs;
+    Function   *createFunction(LoadObject *lo, Module *module, Symbol *sym);
+    void        fixSymtabAlias();
+
+    // Interface with dwarf
+    Dwarf       *openDwarf();
+
+    Vector<Module*> *stabsModules;
+    static char *get_type_name(int t);
+};
+
+#endif  /* _STABS_H */
diff --git a/gprofng/src/Stats_data.cc b/gprofng/src/Stats_data.cc
new file mode 100644 (file)
index 0000000..2595bc7
--- /dev/null
@@ -0,0 +1,203 @@
+/* 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 <search.h>     //  For the tsearch stuff
+#include <assert.h>
+//#include <stdlib.h>
+#include "Table.h"
+#include "Sample.h"
+#include "Stats_data.h"
+#include "util.h"
+#include "i18n.h"
+
+//XXX: The fundamental problem with this package of routines is that
+//XXX: they should look a lot more like overview data. The result
+//XXX: is that it is not possible to share as much code as would
+//XXX: otherwise be possible.
+
+int
+Stats_data::size ()
+{
+  // Return the number of Stats_item values associated with "this".
+  if (stats_items == NULL)
+    return 0;
+  return stats_items->size ();
+}
+
+Stats_data::Stats_item
+Stats_data::fetch (int index)
+{
+  // Routine will return the "index"'th Stats_item associated with "this".
+  assert (index >= 0 && index < stats_items->size ());
+  return *(stats_items->fetch (index));
+}
+
+Stats_data::Stats_data ()
+{
+  // this constructor for use with sum()
+  packets = NULL;
+  stats_items = NULL;
+}
+
+Stats_data::Stats_data (DataView *_packets)
+{
+  packets = _packets;
+  stats_items = NULL;
+  compute_data ();  // reads all data
+}
+
+Stats_data::~Stats_data ()
+{
+  if (stats_items)
+    {
+      stats_items->destroy ();
+      delete stats_items;
+    }
+}
+
+void
+Stats_data::sum (Stats_data *data)
+{
+  int index;
+  Stats_item *stats_item, *data_item;
+  if (stats_items == NULL)
+    {
+      stats_items = new Vector<Stats_item*>;
+      Vec_loop (Stats_item*, data->stats_items, index, data_item)
+      {
+       stats_item = create_stats_item (data_item->value.ll, data_item->label);
+       stats_items->append (stats_item);
+      }
+    }
+  else
+    {
+      Vec_loop (Stats_item*, data->stats_items, index, data_item)
+      {
+       stats_items->fetch (index)->value.ll += data_item->value.ll;
+      }
+    }
+}
+
+Stats_data::Stats_item *
+Stats_data::create_stats_item (long long v, char *l)
+{
+  Stats_data::Stats_item *st_it;
+  st_it = new Stats_data::Stats_item;
+  st_it->label = l;
+  st_it->value.sign = false;
+  st_it->value.ll = v;
+  st_it->value.tag = VT_LLONG;
+  return st_it;
+}
+
+PrUsage *
+Stats_data::fetchPrUsage (long index)
+{
+  // Return the data values corresponding to the "index"'th sample.
+  PrUsage *prusage;
+  if (packets->getSize () > 0)
+    {
+      Sample* sample = (Sample*) packets->getObjValue (PROP_SMPLOBJ, index);
+      prusage = sample->get_usage ();
+      if (prusage != NULL)
+       return prusage;
+    }
+  return new PrUsage;
+}
+
+void
+Stats_data::compute_data ()
+{
+  Stats_data::Stats_item *stats_item;
+  PrUsage *tots, *temp;
+  stats_items = new Vector<Stats_data::Stats_item*>;
+
+  // Precomputation is needed.
+  long size = packets->getSize ();
+  tots = new PrUsage ();
+  for (long index = 0; index < size; index++)
+    {
+      temp = fetchPrUsage (index);
+      tots->pr_tstamp += temp->pr_tstamp;
+      tots->pr_create += temp->pr_create;
+      tots->pr_term += temp->pr_term;
+      tots->pr_rtime += temp->pr_rtime;
+      tots->pr_utime += temp->pr_utime;
+      tots->pr_stime += temp->pr_stime;
+      tots->pr_ttime += temp->pr_ttime;
+      tots->pr_tftime += temp->pr_tftime;
+      tots->pr_dftime += temp->pr_dftime;
+      tots->pr_kftime += temp->pr_kftime;
+      tots->pr_slptime += temp->pr_slptime;
+      tots->pr_ltime += temp->pr_ltime;
+      tots->pr_wtime += temp->pr_wtime;
+      tots->pr_stoptime += temp->pr_stoptime;
+      tots->pr_minf += temp->pr_minf;
+      tots->pr_majf += temp->pr_majf;
+      tots->pr_nswap += temp->pr_nswap;
+      tots->pr_inblk += temp->pr_inblk;
+      tots->pr_oublk += temp->pr_oublk;
+      tots->pr_msnd += temp->pr_msnd;
+      tots->pr_mrcv += temp->pr_mrcv;
+      tots->pr_sigs += temp->pr_sigs;
+      tots->pr_vctx += temp->pr_vctx;
+      tots->pr_ictx += temp->pr_ictx;
+      tots->pr_sysc += temp->pr_sysc;
+      tots->pr_ioch += temp->pr_ioch;
+    }
+  stats_item = create_stats_item ((long long) tots->pr_minf,
+                                 GTXT ("Minor Page Faults"));
+  stats_items->append (stats_item);
+  stats_item = create_stats_item ((long long) tots->pr_majf,
+                                 GTXT ("Major Page Faults"));
+  stats_items->append (stats_item);
+  stats_item = create_stats_item ((long long) tots->pr_nswap,
+                                 GTXT ("Process swaps"));
+  stats_items->append (stats_item);
+  stats_item = create_stats_item ((long long) tots->pr_inblk,
+                                 GTXT ("Input blocks"));
+  stats_items->append (stats_item);
+  stats_item = create_stats_item ((long long) tots->pr_oublk,
+                                 GTXT ("Output blocks"));
+  stats_items->append (stats_item);
+  stats_item = create_stats_item ((long long) tots->pr_msnd,
+                                 GTXT ("Messages sent"));
+  stats_items->append (stats_item);
+  stats_item = create_stats_item ((long long) tots->pr_mrcv,
+                                 GTXT ("Messages received"));
+  stats_items->append (stats_item);
+  stats_item = create_stats_item ((long long) tots->pr_sigs,
+                                 GTXT ("Signals handled"));
+  stats_items->append (stats_item);
+  stats_item = create_stats_item ((long long) tots->pr_vctx,
+                                 GTXT ("Voluntary context switches"));
+  stats_items->append (stats_item);
+  stats_item = create_stats_item ((long long) tots->pr_ictx,
+                                 GTXT ("Involuntary context switches"));
+  stats_items->append (stats_item);
+  stats_item = create_stats_item ((long long) tots->pr_sysc,
+                                 GTXT ("System calls"));
+  stats_items->append (stats_item);
+  stats_item = create_stats_item ((long long) tots->pr_ioch,
+                                 GTXT ("Characters of I/O"));
+  stats_items->append (stats_item);
+  delete tots;
+}
diff --git a/gprofng/src/Stats_data.h b/gprofng/src/Stats_data.h
new file mode 100644 (file)
index 0000000..2f6b6a7
--- /dev/null
@@ -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 _STATS_DATA_H
+#define _STATS_DATA_H
+
+// A Stats_data object is used to obtain the data needed to display
+// a statistics display.
+
+#include "vec.h"
+#include "Exp_Layout.h"
+
+class DataView;
+
+class Stats_data
+{
+public:
+
+  struct Stats_item
+  {
+    char *label;    // statistic label
+    TValue value;   // statistic value
+  };
+
+  Stats_data ();
+  Stats_data (DataView *packets);
+  ~Stats_data ();
+  int size ();      // Return the total number of items.
+  Stats_item fetch (int index);
+  void sum (Stats_data *data);
+
+private:
+
+  PrUsage * fetchPrUsage (long index);
+  void compute_data ();             // Perform any initial computation.
+  Stats_data::Stats_item *create_stats_item (long long, char *);
+
+  Vector<Stats_item*> *stats_items; // Actual statistics values
+  DataView *packets;
+};
+
+#endif /* _STATS_DATA_H  */
diff --git a/gprofng/src/StringBuilder.cc b/gprofng/src/StringBuilder.cc
new file mode 100644 (file)
index 0000000..a9656d9
--- /dev/null
@@ -0,0 +1,585 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <values.h>
+#include <stdarg.h>
+
+#include "gp-defs.h"
+#include "StringBuilder.h"
+#include "i18n.h"
+
+StringBuilder::StringBuilder ()
+{
+  count = 0;
+  maxCapacity = 16;
+  value = (char *) malloc (maxCapacity);
+  memset (value, 0, maxCapacity);
+}
+
+StringBuilder::StringBuilder (int capacity)
+{
+  count = 0;
+  maxCapacity = capacity;
+  value = (char *) malloc (maxCapacity);
+  memset (value, 0, maxCapacity);
+}
+
+StringBuilder::~StringBuilder ()
+{
+  free (value);
+}
+
+void
+StringBuilder::ensureCapacity (int minimumCapacity)
+{
+  if (minimumCapacity > maxCapacity)
+    expandCapacity (minimumCapacity);
+}
+
+void
+StringBuilder::expandCapacity (int minimumCapacity)
+{
+  int newCapacity = (maxCapacity + 1) * 2;
+  if (newCapacity < 0)
+    newCapacity = MAXINT;
+  else if (minimumCapacity > newCapacity)
+    newCapacity = minimumCapacity;
+  char *newValue = (char *) malloc (newCapacity);
+  maxCapacity = newCapacity;
+  memcpy (newValue, value, count);
+  memset (newValue + count, 0, maxCapacity - count);
+  free (value);
+  value = newValue;
+}
+
+void
+StringBuilder::trimToSize ()
+{
+  if (count < maxCapacity)
+    {
+      char *newValue = (char *) malloc (count);
+      maxCapacity = count;
+      memcpy (newValue, value, count);
+      free (value);
+      value = newValue;
+    }
+}
+
+void
+StringBuilder::trim ()
+{
+  while (count > 0)
+    {
+      if (value[count - 1] != ' ')
+       break;
+      count--;
+    }
+}
+
+void
+StringBuilder::setLength (int newLength)
+{
+  if (newLength < 0)
+    return;
+  if (newLength > maxCapacity)
+    expandCapacity (newLength);
+  if (count < newLength)
+    {
+      for (; count < newLength; count++)
+       value[count] = '\0';
+    }
+  else
+    count = newLength;
+}
+
+char
+StringBuilder::charAt (int index)
+{
+  if (index < 0 || index >= count)
+    return 0;
+  return value[index];
+}
+
+void
+StringBuilder::getChars (int srcBegin, int srcEnd, char dst[], int dstBegin)
+{
+  if (srcBegin < 0)
+    return;
+  if (srcEnd < 0 || srcEnd > count)
+    return;
+  if (srcBegin > srcEnd)
+    return;
+  memcpy (dst + dstBegin, value + srcBegin, srcEnd - srcBegin);
+}
+
+void
+StringBuilder::setCharAt (int index, char ch)
+{
+  if (index < 0 || index >= count)
+    return;
+  value[index] = ch;
+}
+
+StringBuilder *
+StringBuilder::append (StringBuilder *sb)
+{
+  if (sb == NULL)
+    return append (NTXT ("null"));
+  int len = sb->count;
+  int newcount = count + len;
+  if (newcount > maxCapacity)
+    expandCapacity (newcount);
+  sb->getChars (0, len, value, count);
+  count = newcount;
+  return this;
+}
+
+StringBuilder *
+StringBuilder::append (const char str[])
+{
+  int len = (int) strlen (str);
+  int newCount = count + len;
+  if (newCount > maxCapacity)
+    expandCapacity (newCount);
+  memcpy (value + count, str, len);
+  count = newCount;
+  return this;
+}
+
+StringBuilder *
+StringBuilder::append (const char str[], int offset, int len)
+{
+  int newCount = count + len;
+  if (newCount > maxCapacity)
+    expandCapacity (newCount);
+  memcpy (value + count, str + offset, len);
+  count = newCount;
+  return this;
+}
+
+StringBuilder *
+StringBuilder::append (bool b)
+{
+  if (b)
+    append (NTXT ("true"));
+  else
+    append (NTXT ("false"));
+  return this;
+}
+
+StringBuilder *
+StringBuilder::append (char c)
+{
+  int newCount = count + 1;
+  if (newCount > maxCapacity)
+    {
+      expandCapacity (newCount);
+    }
+  value[count++] = c;
+  return this;
+}
+
+StringBuilder *
+StringBuilder::append (int i)
+{
+  char buf[16];
+  snprintf (buf, sizeof (buf), NTXT ("%d"), i);
+  append (buf);
+  return this;
+}
+
+StringBuilder *
+StringBuilder::append (unsigned int i)
+{
+  char buf[16];
+  snprintf (buf, sizeof (buf), NTXT ("%u"), i);
+  append (buf);
+  return this;
+}
+
+StringBuilder *
+StringBuilder::append (long lng)
+{
+  char buf[32];
+  snprintf (buf, sizeof (buf), NTXT ("%ld"), lng);
+  append (buf);
+  return this;
+}
+
+StringBuilder *
+StringBuilder::append (unsigned long lng)
+{
+  char buf[32];
+  snprintf (buf, sizeof (buf), NTXT ("%lu"), lng);
+  append (buf);
+  return this;
+}
+
+StringBuilder *
+StringBuilder::append (long long lng)
+{
+  char buf[32];
+  snprintf (buf, sizeof (buf), NTXT ("%lld"), lng);
+  append (buf);
+  return this;
+}
+
+StringBuilder *
+StringBuilder::append (unsigned long long lng)
+{
+  char buf[32];
+  snprintf (buf, sizeof (buf), NTXT ("%llu"), lng);
+  append (buf);
+  return this;
+}
+
+StringBuilder *
+StringBuilder::append (float f)
+{
+  char buf[32];
+  snprintf (buf, sizeof (buf), NTXT ("%f"), (double) f);
+  append (buf);
+  return this;
+}
+
+StringBuilder *
+StringBuilder::append (double d)
+{
+  char buf[32];
+  snprintf (buf, sizeof (buf), NTXT ("%f"), d);
+  append (buf);
+  return this;
+}
+
+StringBuilder *
+StringBuilder::_delete (int start, int end)
+{
+  if (start < 0)
+    return this;
+  if (end > count)
+    end = count;
+  if (start > end)
+    return this;
+  int len = end - start;
+  if (len > 0)
+    {
+      memcpy (value + start, value + start + len, count - end);
+      count -= len;
+    }
+  return this;
+}
+
+StringBuilder *
+StringBuilder::deleteCharAt (int index)
+{
+  if (index < 0 || index >= count)
+    return this;
+  memcpy (value + index, value + index + 1, count - index - 1);
+  count--;
+  return this;
+}
+
+bool
+StringBuilder::endsWith (const char str[])
+{
+  if (str == NULL)
+    {
+      if (count == 0)
+       return true;
+      return false;
+    }
+  int len = (int) strlen (str);
+  if (len == 0)
+    return true;
+  int start = count - len;
+  if (start < 0)
+    return false;
+  int res = strncmp ((const char *) (value + start), str, len);
+  if (res != 0)
+    return false;
+  return true;
+}
+
+StringBuilder *
+StringBuilder::insert (int index, const char str[], int offset, int len)
+{
+  if (index < 0 || index > count)
+    return this;
+  if (offset < 0 || len < 0 || offset > ((int) strlen (str)) - len)
+    return this;
+  int newCount = count + len;
+  if (newCount > maxCapacity)
+    expandCapacity (newCount);
+  memcpy (value + index + len, value + index, count - index);
+  memcpy (value + index, str + offset, len);
+  count = newCount;
+  return this;
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, const char str[])
+{
+  if (offset < 0 || offset > count)
+    return this;
+  int len = (int) strlen (str);
+  int newCount = count + len;
+  if (newCount > maxCapacity)
+    expandCapacity (newCount);
+  memcpy (value + offset + len, value + offset, count - offset);
+  memcpy (value + offset, str, len);
+  count = newCount;
+  return this;
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, bool b)
+{
+  return insert (offset, b ? NTXT ("true") : NTXT ("false"));
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, char c)
+{
+  int newCount = count + 1;
+  if (newCount > maxCapacity)
+    expandCapacity (newCount);
+  memcpy (value + offset + 1, value + offset, count - offset);
+  value[offset] = c;
+  count = newCount;
+  return this;
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, int i)
+{
+  char buf[16];
+  snprintf (buf, sizeof (buf), NTXT ("%d"), i);
+  insert (offset, buf);
+  return this;
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, long l)
+{
+  char buf[32];
+  snprintf (buf, sizeof (buf), NTXT ("%ld"), l);
+  insert (offset, buf);
+  return this;
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, float f)
+{
+  char buf[32];
+  snprintf (buf, sizeof (buf), NTXT ("%f"), (double) f);
+  insert (offset, buf);
+  return this;
+}
+
+StringBuilder *
+StringBuilder::insert (int offset, double d)
+{
+  char buf[32];
+  snprintf (buf, sizeof (buf), NTXT ("%f"), d);
+  insert (offset, buf);
+  return this;
+}
+
+StringBuilder *
+StringBuilder::reverse ()
+{
+  int n = count - 1;
+  for (int j = (n - 1) >> 1; j >= 0; --j)
+    {
+      char temp = value[j];
+      char temp2 = value[n - j];
+      value[j] = temp2;
+      value[n - j] = temp;
+    }
+  return this;
+}
+
+//String *StringBuilder::toString();
+char *
+StringBuilder::toString ()
+{
+  char *str = (char *) malloc (count + 1);
+  memcpy (str, value, count);
+  str[count] = '\0';
+  return str;
+}
+
+void
+StringBuilder::toFile (FILE *fp)
+{
+  append ('\0');
+  count--;
+  fprintf (fp, NTXT ("%s"), value);
+}
+
+void
+StringBuilder::toFileLn (FILE *fp)
+{
+  trim ();
+  append ('\0');
+  count--;
+  fprintf (fp, NTXT ("%s\n"), value);
+}
+
+StringBuilder *
+StringBuilder::sprintf (const char *fmt, ...)
+{
+  int cnt;
+  setLength (0);
+
+  va_list vp;
+  va_start (vp, fmt);
+  cnt = vsnprintf (value, maxCapacity, fmt, vp);
+  va_end (vp);
+  if (cnt < maxCapacity)
+    {
+      count = cnt;
+      return this;
+    }
+
+  // Have to count the trailing zero
+  ensureCapacity (cnt + 1);
+  va_start (vp, fmt);
+  count = vsnprintf (value, maxCapacity, fmt, vp);
+  va_end (vp);
+  return this;
+}
+
+StringBuilder *
+StringBuilder::appendf (const char *fmt, ...)
+{
+  va_list vp;
+  va_start (vp, fmt);
+  int cnt = vsnprintf (value + count, maxCapacity - count, fmt, vp);
+  va_end (vp);
+  if (cnt + count < maxCapacity)
+    {
+      count += cnt;
+      return this;
+    }
+
+  // Have to count the trailing zero
+  ensureCapacity (count + cnt + 1);
+  va_start (vp, fmt);
+  count += vsnprintf (value + count, maxCapacity - count, fmt, vp);
+  va_end (vp);
+  return this;
+}
+
+int
+StringBuilder::indexOf (const char str[])
+{
+  return indexOf (str, 0);
+}
+
+int
+StringBuilder::indexOf (const char str[], int fromIndex)
+{
+  int len = (int) strlen (str);
+  if (fromIndex >= count)
+    return len == 0 ? count : -1;
+  if (fromIndex < 0)
+    fromIndex = 0;
+  if (len == 0)
+    return fromIndex;
+
+  char first = str[0];
+  int max = (count - len);
+
+  for (int i = fromIndex; i <= max; i++)
+    {
+      /* Look for first character. */
+      if (value[i] != first)
+       while (++i <= max && value[i] != first)
+         ;
+      /* Found first character, now look at the rest of v2 */
+      if (i <= max)
+       {
+         int j = i + 1;
+         int end = j + len - 1;
+         for (int k = 1; j < end && value[j] == str[k]; j++, k++)
+           ;
+         if (j == end)     /* Found whole string. */
+           return i;
+       }
+    }
+  return -1;
+}
+
+int
+StringBuilder::lastIndexOf (const char str[])
+{
+  return lastIndexOf (str, count);
+}
+
+int
+StringBuilder::lastIndexOf (const char str[], int fromIndex)
+{
+  /*
+   * Check arguments; return immediately where possible. For
+   * consistency, don't check for null str.
+   */
+  int len = (int) strlen (str);
+  int rightIndex = count - len;
+  if (fromIndex < 0)
+    return -1;
+  if (fromIndex > rightIndex)
+    fromIndex = rightIndex;
+  /* Empty string always matches. */
+  if (len == 0)
+    return fromIndex;
+
+  int strLastIndex = len - 1;
+  char strLastChar = str[strLastIndex];
+  int min = len - 1;
+  int i = min + fromIndex;
+
+  while (true)
+    {
+      while (i >= min && value[i] != strLastChar)
+       i--;
+      if (i < min)
+       return -1;
+
+      int j = i - 1;
+      int start = j - (len - 1);
+      int k = strLastIndex - 1;
+      while (j > start)
+       {
+         if (value[j--] != str[k--])
+           {
+             i--;
+             break;
+           }
+       }
+      if (j == start)
+       return start + 1;
+    }
+}
+
diff --git a/gprofng/src/StringBuilder.h b/gprofng/src/StringBuilder.h
new file mode 100644 (file)
index 0000000..5fe1a51
--- /dev/null
@@ -0,0 +1,101 @@
+/* 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.  */
+
+/*
+ *     java/lang/StringBuilder
+ *
+ *     Based on JavaTM 2 Platform Standard Ed. 5.0
+ */
+
+#ifndef _StringBuilder_h
+#define _StringBuilder_h
+
+class StringBuilder
+{
+public:
+  StringBuilder ();
+  StringBuilder (int capacity);
+  virtual ~StringBuilder ();
+
+  int
+  length ()
+  {
+    return count;
+  }
+
+  int
+  capacity ()
+  {
+    return maxCapacity;
+  }
+
+  bool endsWith (const char str[]);
+  void ensureCapacity (int minimumCapacity);
+  void expandCapacity (int minimumCapacity);
+  void trimToSize ();
+  void trim ();
+  void setLength (int newLength);
+  char charAt (int index);
+  void getChars (int srcBegin, int srcEnd, char dst[], int dstBegin);
+  void setCharAt (int index, char ch);
+  StringBuilder *append (StringBuilder *sb);
+  StringBuilder *append (const char str[]);
+  StringBuilder *append (const char str[], int offset, int len);
+  StringBuilder *append (bool b);
+  StringBuilder *append (char c);
+  StringBuilder *append (int i);
+  StringBuilder *append (unsigned int i);
+  StringBuilder *append (long lng);
+  StringBuilder *append (unsigned long i);
+  StringBuilder *append (long long lng);
+  StringBuilder *append (unsigned long long lng);
+  StringBuilder *append (float f);
+  StringBuilder *append (double d);
+  StringBuilder *_delete (int start, int end);
+  StringBuilder *deleteCharAt (int index);
+  StringBuilder *insert (int index, const char str[], int offset, int len);
+  StringBuilder *insert (int offset, const char str[]);
+  StringBuilder *insert (int offset, bool b);
+  StringBuilder *insert (int offset, char c);
+  StringBuilder *insert (int offset, int i);
+  StringBuilder *insert (int offset, long l);
+  StringBuilder *insert (int offset, float f);
+  StringBuilder *insert (int offset, double d);
+  StringBuilder *reverse ();
+  char *toString ();
+  void toFile (FILE *fp);
+  void toFileLn (FILE *fp);
+
+  // Not in Java
+  StringBuilder *appendf (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+  StringBuilder *sprintf (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+  int indexOf (const char str[]);
+  int indexOf (const char str[], int fromIndex);
+  int lastIndexOf (const char str[]);
+  int lastIndexOf (const char str[], int fromIndex);
+
+private:
+  char *value;
+  int count;
+  int maxCapacity;
+};
+
+#endif /* _StringBuilder_h */
diff --git a/gprofng/src/StringMap.h b/gprofng/src/StringMap.h
new file mode 100644 (file)
index 0000000..31898f4
--- /dev/null
@@ -0,0 +1,238 @@
+/* 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.  */
+
+/*
+ *     String Map implementation.
+ */
+
+#ifndef _DBE_STRINGMAP_H
+#define _DBE_STRINGMAP_H
+
+#include <assert.h>
+#include <vec.h>
+#include <Map.h>
+#include <util.h>
+
+template <typename Value_t>
+class StringMap : public Map<const char*, Value_t>
+{
+public:
+
+  StringMap (int htable_size = 1024, int chunk_size = 16384);
+  ~StringMap ();
+  void clear ();
+  void put (const char *key, Value_t val);
+  Value_t get (const char *key);
+  Value_t get (const char *key, typename Map<const char*, Value_t>::Relation rel);
+  Value_t remove (const char*);
+  Vector<const char*> *keySet ();
+  Vector<Value_t> *values ();
+
+private:
+
+  static unsigned
+  hash (const char *key)
+  {
+    return (unsigned) crc64 (key, strlen (key));
+  }
+
+  struct Entry
+  {
+    char *key;
+    Value_t val;
+  };
+
+  int CHUNK_SIZE, HTABLE_SIZE;
+  int entries;
+  int nchunks;
+  Entry **chunks;
+  Vector<Entry*> *index;
+  Entry **hashTable;
+};
+
+template <typename Value_t>
+StringMap<Value_t>::StringMap (int htable_size, int chunk_size)
+{
+  HTABLE_SIZE = htable_size;
+  CHUNK_SIZE = chunk_size;
+  entries = 0;
+  nchunks = 0;
+  chunks = NULL;
+  index = new Vector<Entry*>;
+  hashTable = new Entry*[HTABLE_SIZE];
+  for (int i = 0; i < HTABLE_SIZE; i++)
+    hashTable[i] = NULL;
+}
+
+template <typename Value_t>
+StringMap<Value_t>::~StringMap ()
+{
+  for (int i = 0; i < entries; ++i)
+    {
+      Entry *entry = index->fetch (i);
+      free (entry->key);
+    }
+  for (int i = 0; i < nchunks; i++)
+    delete[] chunks[i];
+  delete[] chunks;
+  delete index;
+  delete[] hashTable;
+}
+
+template <typename Value_t>
+void
+StringMap<Value_t>::clear ()
+{
+  for (int i = 0; i < entries; ++i)
+    {
+      Entry *entry = index->fetch (i);
+      free (entry->key);
+    }
+  entries = 0;
+  index->reset ();
+  for (int i = 0; i < HTABLE_SIZE; i++)
+    hashTable[i] = NULL;
+}
+
+template <typename Value_t>
+void
+StringMap<Value_t>::put (const char *key, Value_t val)
+{
+  unsigned idx = hash (key) % HTABLE_SIZE;
+  Entry *entry = hashTable[idx];
+  if (entry && strcmp (entry->key, key) == 0)
+    {
+      entry->val = val;
+      return;
+    }
+  int lo = 0;
+  int hi = entries - 1;
+  while (lo <= hi)
+    {
+      int md = (lo + hi) / 2;
+      entry = index->fetch (md);
+      int cmp = strcmp (entry->key, key);
+      if (cmp < 0)
+       lo = md + 1;
+      else if (cmp > 0)
+       hi = md - 1;
+      else
+       {
+         entry->val = val;
+         return;
+       }
+    }
+  if (entries >= nchunks * CHUNK_SIZE)
+    {
+      nchunks++;
+
+      // Reallocate Entry chunk array
+      Entry **new_chunks = new Entry*[nchunks];
+      for (int i = 0; i < nchunks - 1; i++)
+       new_chunks[i] = chunks[i];
+      delete[] chunks;
+      chunks = new_chunks;
+
+      // Allocate new chunk for entries.
+      chunks[nchunks - 1] = new Entry[CHUNK_SIZE];
+    }
+  entry = &chunks[entries / CHUNK_SIZE][entries % CHUNK_SIZE];
+  entry->key = strdup (key);
+  entry->val = val;
+  index->insert (lo, entry);
+  hashTable[idx] = entry;
+  entries++;
+}
+
+template <typename Value_t>
+Value_t
+StringMap<Value_t>::get (const char *key)
+{
+  unsigned idx = hash (key) % HTABLE_SIZE;
+  Entry *entry = hashTable[idx];
+  if (entry && strcmp (entry->key, key) == 0)
+    return entry->val;
+  int lo = 0;
+  int hi = entries - 1;
+  while (lo <= hi)
+    {
+      int md = (lo + hi) / 2;
+      entry = index->fetch (md);
+      int cmp = strcmp (entry->key, key);
+      if (cmp < 0)
+       lo = md + 1;
+      else if (cmp > 0)
+       hi = md - 1;
+      else
+       {
+         hashTable[idx] = entry;
+         return entry->val;
+       }
+    }
+  return (Value_t) 0;
+}
+
+template <typename Value_t>
+Value_t
+StringMap<Value_t>::get (const char *key, typename Map<const char*,
+                        Value_t>::Relation rel)
+{
+  if (rel != Map<const char*, Value_t>::REL_EQ)
+    return (Value_t) 0;
+  return get (key);
+}
+
+template <typename Value_t>
+Value_t
+StringMap<Value_t>::remove (const char*)
+{
+  // Not implemented
+  if (1)
+    assert (0);
+  return (Value_t) 0;
+}
+
+template <typename Value_t>
+Vector<Value_t> *
+StringMap<Value_t>::values ()
+{
+  Vector<Value_t> *vals = new Vector<Value_t>(entries);
+  for (int i = 0; i < entries; ++i)
+    {
+      Entry *entry = index->fetch (i);
+      vals->append (entry->val);
+    }
+  return vals;
+}
+
+template <typename Value_t>
+Vector<const char*> *
+StringMap<Value_t>::keySet ()
+{
+  Vector<const char*> *keys = new Vector<const char*>(entries);
+  for (int i = 0; i < entries; ++i)
+    {
+      Entry *entry = index->fetch (i);
+      keys->append (entry->key);
+    }
+  return keys;
+}
+
+#endif
diff --git a/gprofng/src/Table.cc b/gprofng/src/Table.cc
new file mode 100644 (file)
index 0000000..afe44bd
--- /dev/null
@@ -0,0 +1,1687 @@
+/* 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 <stdio.h>
+
+#include "IndexMap2D.h"
+#include "DbeSession.h"
+#include "FilterExp.h"
+#include "Table.h"
+#include "util.h"
+#include "i18n.h"
+
+char *
+get_prof_data_type_name (int t)
+{
+  switch (t)
+    {
+    case DATA_SAMPLE:   return NTXT("PROFDATA_TYPE_SAMPLE");
+    case DATA_GCEVENT:  return NTXT("PROFDATA_TYPE_GCEVENT");
+    case DATA_HEAPSZ:   return NTXT("PROFDATA_TYPE_HEAPSZ");
+    case DATA_CLOCK:    return NTXT("PROFDATA_TYPE_CLOCK");
+    case DATA_HWC:      return NTXT("PROFDATA_TYPE_HWC");
+    case DATA_SYNCH:    return NTXT("PROFDATA_TYPE_SYNCH");
+    case DATA_HEAP:     return NTXT("PROFDATA_TYPE_HEAP");
+    case DATA_OMP:      return NTXT("PROFDATA_TYPE_OMP");
+    case DATA_OMP2:     return NTXT("PROFDATA_TYPE_OMP2");
+    case DATA_OMP3:     return NTXT("PROFDATA_TYPE_OMP3");
+    case DATA_OMP4:     return NTXT("PROFDATA_TYPE_OMP4");
+    case DATA_OMP5:     return NTXT("PROFDATA_TYPE_OMP5");
+    case DATA_IOTRACE:  return NTXT("PROFDATA_TYPE_IOTRACE");
+    default: abort ();
+      return NTXT ("PROFDATA_TYPE_ERROR");
+    }
+}
+
+char *
+get_prof_data_type_uname (int t)
+{
+  switch (t)
+    {
+    case DATA_SAMPLE:   return GTXT("Process-wide Resource Utilization");
+    case DATA_GCEVENT:  return GTXT("Java Garbage Collection Events");
+    case DATA_HEAPSZ:   return GTXT("Heap Size");
+    case DATA_CLOCK:    return GTXT("Clock Profiling");
+    case DATA_HWC:      return GTXT("HW Counter Profiling");
+    case DATA_SYNCH:    return GTXT("Synchronization Tracing");
+    case DATA_HEAP:     return GTXT("Heap Tracing");
+    case DATA_OMP:      return GTXT("OpenMP Profiling");
+    case DATA_OMP2:     return GTXT("OpenMP Profiling");
+    case DATA_OMP3:     return GTXT("OpenMP Profiling");
+    case DATA_OMP4:     return GTXT("OpenMP Profiling");
+    case DATA_OMP5:     return GTXT("OpenMP Profiling");
+    case DATA_IOTRACE:  return GTXT("IO Tracing");
+    default: abort ();
+      return NTXT ("PROFDATA_TYPE_ERROR");
+    }
+}
+
+int assert_level = 0; // set to 1 to bypass problematic asserts
+
+#define ASSERT_SKIP (assert_level)
+
+/*
+ *    class PropDescr
+ */
+
+PropDescr::PropDescr (int _propID, const char *_name)
+{
+  propID = _propID;
+  name = strdup (_name ? _name : NTXT (""));
+  uname = NULL;
+  vtype = TYPE_NONE;
+  flags = 0;
+  stateNames = NULL;
+  stateUNames = NULL;
+}
+
+PropDescr::~PropDescr ()
+{
+  free (name);
+  free (uname);
+  if (stateNames)
+    {
+      stateNames->destroy ();
+      delete stateNames;
+    }
+  if (stateUNames)
+    {
+      stateUNames->destroy ();
+      delete stateUNames;
+    }
+}
+
+void
+PropDescr::addState (int value, const char *stname, const char *stuname)
+{
+  if (value < 0 || stname == NULL)
+    return;
+  if (stateNames == NULL)
+    stateNames = new Vector<char*>;
+  stateNames->store (value, strdup (stname));
+  if (stateUNames == NULL)
+    stateUNames = new Vector<char*>;
+  stateUNames->store (value, strdup (stuname));
+}
+
+char *
+PropDescr::getStateName (int value)
+{
+  if (stateNames && value >= 0 && value < stateNames->size ())
+    return stateNames->fetch (value);
+  return NULL;
+}
+
+char *
+PropDescr::getStateUName (int value)
+{
+  if (stateUNames && value >= 0 && value < stateUNames->size ())
+    return stateUNames->fetch (value);
+  return NULL;
+}
+
+/*
+ *    class FieldDescr
+ */
+
+FieldDescr::FieldDescr (int _propID, const char *_name)
+{
+  propID = _propID;
+  name = _name ? strdup (_name) : NULL;
+  offset = 0;
+  vtype = TYPE_NONE;
+  format = NULL;
+}
+
+FieldDescr::~FieldDescr ()
+{
+  free (name);
+  free (format);
+}
+
+/*
+ *    class PacketDescriptor
+ */
+
+PacketDescriptor::PacketDescriptor (DataDescriptor *_ddscr)
+{
+  ddscr = _ddscr;
+  fields = new Vector<FieldDescr*>;
+}
+
+PacketDescriptor::~PacketDescriptor ()
+{
+  fields->destroy ();
+  delete fields;
+}
+
+void
+PacketDescriptor::addField (FieldDescr *fldDscr)
+{
+  if (fldDscr == NULL)
+    return;
+  fields->append (fldDscr);
+}
+
+/*
+ *    class Data
+ */
+
+/* Check compatibility between Datum and Data */
+static void
+checkCompatibility (VType_type v1, VType_type v2)
+{
+  switch (v1)
+    {
+    case TYPE_NONE:
+    case TYPE_STRING:
+    case TYPE_DOUBLE:
+    case TYPE_OBJ:
+    case TYPE_DATE:
+      assert (v1 == v2);
+      break;
+    case TYPE_INT32:
+    case TYPE_UINT32:
+      assert (v2 == TYPE_INT32 ||
+             v2 == TYPE_UINT32);
+      break;
+    case TYPE_INT64:
+    case TYPE_UINT64:
+      assert (v2 == TYPE_INT64 ||
+             v2 == TYPE_UINT64);
+      break;
+    default:
+      assert (0);
+    }
+}
+
+class DataINT32 : public Data
+{
+public:
+
+  DataINT32 ()
+  {
+    data = new Vector<int32_t>;
+  }
+
+  virtual
+  ~DataINT32 ()
+  {
+    delete data;
+  }
+
+  virtual VType_type
+  type ()
+  {
+    return TYPE_INT32;
+  }
+
+  virtual void
+  reset ()
+  {
+    data->reset ();
+  }
+
+  virtual long
+  getSize ()
+  {
+    return data->size ();
+  }
+
+  virtual int
+  fetchInt (long i)
+  {
+    return (int) data->fetch (i);
+  }
+
+  virtual unsigned long long
+  fetchULong (long i)
+  {
+    return (unsigned long long) data->fetch (i);
+  }
+
+  virtual long long
+  fetchLong (long i)
+  {
+    return (long long) data->fetch (i);
+  }
+
+  virtual char *
+  fetchString (long i)
+  {
+    return dbe_sprintf (NTXT ("%d"), data->fetch (i));
+  }
+
+  virtual double
+  fetchDouble (long i)
+  {
+    return (double) data->fetch (i);
+  }
+
+  virtual void *
+  fetchObject (long)
+  {
+    assert (ASSERT_SKIP);
+    return NULL;
+  }
+
+  virtual void
+  setDatumValue (long idx, const Datum *val)
+  {
+    data->store (idx, val->i);
+  }
+
+  virtual void
+  setValue (long idx, uint64_t val)
+  {
+    data->store (idx, (int32_t) val);
+  }
+
+  virtual void
+  setObjValue (long, void*)
+  {
+    assert (ASSERT_SKIP);
+    return;
+  }
+
+  virtual int
+  cmpValues (long idx1, long idx2)
+  {
+    int32_t i1 = data->fetch (idx1);
+    int32_t i2 = data->fetch (idx2);
+    return i1 < i2 ? -1 : i1 > i2 ? 1 : 0;
+  }
+
+  virtual int
+  cmpDatumValue (long idx, const Datum *val)
+  {
+    int32_t i1 = data->fetch (idx);
+    int32_t i2 = val->i;
+    return i1 < i2 ? -1 : i1 > i2 ? 1 : 0;
+  }
+
+private:
+  Vector<int32_t> *data;
+};
+
+class DataUINT32 : public Data
+{
+public:
+
+  DataUINT32 ()
+  {
+    data = new Vector<uint32_t>;
+  }
+
+  virtual
+  ~DataUINT32 ()
+  {
+    delete data;
+  }
+
+  virtual VType_type
+  type ()
+  {
+    return TYPE_UINT32;
+  }
+
+  virtual void
+  reset ()
+  {
+    data->reset ();
+  }
+
+  virtual long
+  getSize ()
+  {
+    return data->size ();
+  }
+
+  virtual int
+  fetchInt (long i)
+  {
+    return (int) data->fetch (i);
+  }
+
+  virtual unsigned long long
+  fetchULong (long i)
+  {
+    return (unsigned long long) data->fetch (i);
+  }
+
+  virtual long long
+  fetchLong (long i)
+  {
+    return (long long) data->fetch (i);
+  }
+
+  virtual char *
+  fetchString (long i)
+  {
+    return dbe_sprintf (NTXT ("%u"), data->fetch (i));
+  }
+
+  virtual double
+  fetchDouble (long i)
+  {
+    return (double) data->fetch (i);
+  }
+
+  virtual void *
+  fetchObject (long)
+  {
+    assert (ASSERT_SKIP);
+    return NULL;
+  }
+
+  virtual void
+  setDatumValue (long idx, const Datum *val)
+  {
+    data->store (idx, val->i);
+  }
+
+  virtual void
+  setValue (long idx, uint64_t val)
+  {
+    data->store (idx, (uint32_t) val);
+  }
+
+  virtual void
+  setObjValue (long, void*)
+  {
+    assert (ASSERT_SKIP);
+    return;
+  }
+
+  virtual int
+  cmpValues (long idx1, long idx2)
+  {
+    uint32_t u1 = data->fetch (idx1);
+    uint32_t u2 = data->fetch (idx2);
+    return u1 < u2 ? -1 : u1 > u2 ? 1 : 0;
+  }
+
+  virtual int
+  cmpDatumValue (long idx, const Datum *val)
+  {
+    uint32_t u1 = data->fetch (idx);
+    uint32_t u2 = (uint32_t) val->i;
+    return u1 < u2 ? -1 : u1 > u2 ? 1 : 0;
+  }
+
+private:
+  Vector<uint32_t> *data;
+};
+
+class DataINT64 : public Data
+{
+public:
+
+  DataINT64 ()
+  {
+    data = new Vector<int64_t>;
+  }
+
+  virtual
+  ~DataINT64 ()
+  {
+    delete data;
+  }
+
+  virtual VType_type
+  type ()
+  {
+    return TYPE_INT64;
+  }
+
+  virtual void
+  reset ()
+  {
+    data->reset ();
+  }
+
+  virtual long
+  getSize ()
+  {
+    return data->size ();
+  }
+
+  virtual int
+  fetchInt (long i)
+  {
+    return (int) data->fetch (i);
+  }
+
+  virtual unsigned long long
+  fetchULong (long i)
+  {
+    return (unsigned long long) data->fetch (i);
+  }
+
+  virtual long long
+  fetchLong (long i)
+  {
+    return (long long) data->fetch (i);
+  }
+
+  virtual char *
+  fetchString (long i)
+  {
+    return dbe_sprintf (NTXT ("%lld"), (long long) data->fetch (i));
+  }
+
+  virtual double
+  fetchDouble (long i)
+  {
+    return (double) data->fetch (i);
+  }
+
+  virtual void *
+  fetchObject (long)
+  {
+    assert (ASSERT_SKIP);
+    return NULL;
+  }
+
+  virtual void
+  setDatumValue (long idx, const Datum *val)
+  {
+    data->store (idx, val->ll);
+  }
+
+  virtual void
+  setValue (long idx, uint64_t val)
+  {
+    data->store (idx, (int64_t) val);
+  }
+
+  virtual void
+  setObjValue (long, void*)
+  {
+    assert (ASSERT_SKIP);
+    return;
+  }
+
+  virtual int
+  cmpValues (long idx1, long idx2)
+  {
+    int64_t i1 = data->fetch (idx1);
+    int64_t i2 = data->fetch (idx2);
+    return i1 < i2 ? -1 : i1 > i2 ? 1 : 0;
+  }
+
+  virtual int
+  cmpDatumValue (long idx, const Datum *val)
+  {
+    int64_t i1 = data->fetch (idx);
+    int64_t i2 = val->ll;
+    return i1 < i2 ? -1 : i1 > i2 ? 1 : 0;
+  }
+
+private:
+  Vector<int64_t> *data;
+};
+
+class DataUINT64 : public Data
+{
+public:
+
+  DataUINT64 ()
+  {
+    data = new Vector<uint64_t>;
+  }
+
+  virtual
+  ~DataUINT64 ()
+  {
+    delete data;
+  }
+
+  virtual VType_type
+  type ()
+  {
+    return TYPE_UINT64;
+  }
+
+  virtual void
+  reset ()
+  {
+    data->reset ();
+  }
+
+  virtual long
+  getSize ()
+  {
+    return data->size ();
+  }
+
+  virtual int
+  fetchInt (long i)
+  {
+    return (int) data->fetch (i);
+  }
+
+  virtual unsigned long long
+  fetchULong (long i)
+  {
+    return (unsigned long long) data->fetch (i);
+  }
+
+  virtual long long
+  fetchLong (long i)
+  {
+    return (long long) data->fetch (i);
+  }
+
+  virtual char *
+  fetchString (long i)
+  {
+    return dbe_sprintf (NTXT ("%llu"), (long long) data->fetch (i));
+  }
+
+  virtual double
+  fetchDouble (long i)
+  {
+    return (double) data->fetch (i);
+  }
+
+  virtual void *
+  fetchObject (long)
+  {
+    assert (ASSERT_SKIP);
+    return NULL;
+  }
+
+  virtual void
+  setDatumValue (long idx, const Datum *val)
+  {
+    data->store (idx, val->ll);
+  }
+
+  virtual void
+  setValue (long idx, uint64_t val)
+  {
+    data->store (idx, val);
+  }
+
+  virtual void
+  setObjValue (long, void*)
+  {
+    assert (ASSERT_SKIP);
+    return;
+  }
+
+  virtual int
+  cmpValues (long idx1, long idx2)
+  {
+    uint64_t u1 = data->fetch (idx1);
+    uint64_t u2 = data->fetch (idx2);
+    return u1 < u2 ? -1 : u1 > u2 ? 1 : 0;
+  }
+
+  virtual int
+  cmpDatumValue (long idx, const Datum *val)
+  {
+    uint64_t u1 = data->fetch (idx);
+    uint64_t u2 = (uint64_t) val->ll;
+    return u1 < u2 ? -1 : u1 > u2 ? 1 : 0;
+  }
+
+private:
+  Vector<uint64_t> *data;
+};
+
+class DataOBJECT : public Data
+{
+public:
+
+  DataOBJECT ()
+  {
+    dtype = TYPE_OBJ;
+    data = new Vector<void*>;
+  }
+
+  DataOBJECT (VType_type _dtype)
+  {
+    dtype = _dtype;
+    data = new Vector<void*>;
+  }
+
+  virtual
+  ~DataOBJECT ()
+  {
+    delete data;
+  }
+
+  virtual VType_type
+  type ()
+  {
+    return dtype;
+  }
+
+  virtual void
+  reset ()
+  {
+    data->reset ();
+  }
+
+  virtual long
+  getSize ()
+  {
+    return data->size ();
+  }
+
+  virtual int
+  fetchInt (long)
+  {
+    assert (ASSERT_SKIP);
+    return 0;
+  }
+
+  virtual unsigned long long
+  fetchULong (long)
+  {
+    assert (ASSERT_SKIP);
+    return 0LL;
+  }
+
+  virtual long long
+  fetchLong (long)
+  {
+    assert (ASSERT_SKIP);
+    return 0LL;
+  }
+
+  virtual char *
+  fetchString (long i)
+  {
+    return dbe_sprintf (NTXT ("%lu"), (unsigned long) data->fetch (i));
+  }
+
+  virtual double
+  fetchDouble (long)
+  {
+    assert (ASSERT_SKIP);
+    return 0.0;
+  }
+
+  virtual void *
+  fetchObject (long i)
+  {
+    return data->fetch (i);
+  }
+
+  virtual void
+  setDatumValue (long idx, const Datum *val)
+  {
+    data->store (idx, val->p);
+  }
+
+  virtual void
+  setValue (long, uint64_t)
+  {
+    assert (ASSERT_SKIP);
+    return;
+  }
+
+  virtual void
+  setObjValue (long idx, void *p)
+  {
+    data->store (idx, p);
+  }
+
+  virtual int
+  cmpValues (long, long)
+  {
+    return 0;
+  }
+
+  virtual int
+  cmpDatumValue (long, const Datum *)
+  {
+    return 0;
+  }
+
+private:
+  VType_type dtype;
+  Vector<void*> *data;
+};
+
+class DataSTRING : public Data
+{
+public:
+
+  DataSTRING ()
+  {
+    data = new Vector<char*>;
+  }
+
+  virtual
+  ~DataSTRING ()
+  {
+    data->destroy ();
+    delete data;
+  }
+
+  virtual VType_type
+  type ()
+  {
+    return TYPE_STRING;
+  }
+
+  virtual void
+  reset ()
+  {
+    data->reset ();
+  }
+
+  virtual long
+  getSize ()
+  {
+    return data->size ();
+  }
+
+  virtual int
+  fetchInt (long)
+  {
+    return 0;
+  }
+
+  virtual unsigned long long
+  fetchULong (long)
+  {
+    return 0LL;
+  }
+
+  virtual long long
+  fetchLong (long)
+  {
+    return 0LL;
+  }
+
+  virtual char *
+  fetchString (long i)
+  {
+    return strdup (data->fetch (i));
+  }
+
+  virtual double
+  fetchDouble (long)
+  {
+    return 0.0;
+  }
+
+  virtual void *
+  fetchObject (long i)
+  {
+    return data->fetch (i);
+  }
+
+  virtual void
+  setDatumValue (long idx, const Datum *val)
+  {
+    data->store (idx, val->l);
+  }
+
+  virtual void
+  setValue (long, uint64_t)
+  {
+    return;
+  }
+
+  virtual void
+  setObjValue (long idx, void *p)
+  {
+    data->store (idx, (char*) p);
+  }
+
+  virtual int
+  cmpValues (long, long)
+  {
+    return 0;
+  }
+
+  virtual int
+  cmpDatumValue (long, const Datum *)
+  {
+    return 0;
+  }
+
+private:
+  Vector<char*> *data;
+};
+
+class DataDOUBLE : public Data
+{
+public:
+
+  DataDOUBLE ()
+  {
+    data = new Vector<double>;
+  }
+
+  virtual
+  ~DataDOUBLE ()
+  {
+    delete data;
+  }
+
+  virtual VType_type
+  type ()
+  {
+    return TYPE_DOUBLE;
+  }
+
+  virtual void
+  reset ()
+  {
+    data->reset ();
+  }
+
+  virtual long
+  getSize ()
+  {
+    return data->size ();
+  }
+
+  virtual int
+  fetchInt (long i)
+  {
+    return (int) data->fetch (i);
+  }
+
+  virtual unsigned long long
+  fetchULong (long i)
+  {
+    return (unsigned long long) data->fetch (i);
+  }
+
+  virtual long long
+  fetchLong (long i)
+  {
+    return (long long) data->fetch (i);
+  }
+
+  virtual char *
+  fetchString (long i)
+  {
+    return dbe_sprintf (NTXT ("%f"), data->fetch (i));
+  }
+
+  virtual double
+  fetchDouble (long i)
+  {
+    return data->fetch (i);
+  }
+
+  virtual void
+  setDatumValue (long idx, const Datum *val)
+  {
+    data->store (idx, val->d);
+  }
+
+  virtual void
+  setValue (long idx, uint64_t val)
+  {
+    data->store (idx, (double) val);
+  }
+
+  virtual void
+  setObjValue (long, void*)
+  {
+    return;
+  }
+
+  virtual void *
+  fetchObject (long)
+  {
+    return NULL;
+  }
+
+  virtual int
+  cmpValues (long idx1, long idx2)
+  {
+    double d1 = data->fetch (idx1);
+    double d2 = data->fetch (idx2);
+    return d1 < d2 ? -1 : d1 > d2 ? 1 : 0;
+  }
+
+  virtual int
+  cmpDatumValue (long idx, const Datum *val)
+  {
+    double d1 = data->fetch (idx);
+    double d2 = val->d;
+    return d1 < d2 ? -1 : d1 > d2 ? 1 : 0;
+  }
+
+private:
+  Vector<double> *data;
+};
+
+Data *
+Data::newData (VType_type vtype)
+{
+  switch (vtype)
+    {
+    case TYPE_INT32:
+      return new DataINT32;
+    case TYPE_UINT32:
+      return new DataUINT32;
+    case TYPE_INT64:
+      return new DataINT64;
+    case TYPE_UINT64:
+      return new DataUINT64;
+    case TYPE_OBJ:
+      return new DataOBJECT;
+    case TYPE_STRING:
+      return new DataSTRING;
+    case TYPE_DOUBLE:
+      return new DataDOUBLE;
+    default:
+      return NULL;
+    }
+}
+
+/*
+ *    class DataDescriptor
+ */
+DataDescriptor::DataDescriptor (int _id, const char *_name, const char *_uname,
+                               int _flags)
+{
+  isMaster = true;
+  id = _id;
+  name = _name ? strdup (_name) : strdup (NTXT (""));
+  uname = _uname ? strdup (_uname) : strdup (NTXT (""));
+  flags = _flags;
+
+  // master data, shared with reference copies:
+  master_size = 0;
+  master_resolveFrameInfoDone = false;
+  props = new Vector<PropDescr*>;
+  data = new Vector<Data*>;
+  setsTBR = new Vector<Vector<long long>*>;
+
+  // master references point to self:
+  ref_size = &master_size;
+  ref_resolveFrameInfoDone = &master_resolveFrameInfoDone;
+}
+
+DataDescriptor::DataDescriptor (int _id, const char *_name, const char *_uname,
+                               DataDescriptor* dDscr)
+{
+  isMaster = false;
+  id = _id;
+  name = _name ? strdup (_name) : strdup (NTXT (""));
+  uname = _uname ? strdup (_uname) : strdup (NTXT (""));
+  flags = dDscr->flags;
+
+  // references point to master DataDescriptor
+  ref_size = &dDscr->master_size;
+  ref_resolveFrameInfoDone = &dDscr->master_resolveFrameInfoDone;
+  props = dDscr->props;
+  data = dDscr->data;
+  setsTBR = dDscr->setsTBR;
+
+  // data that should never be accessed in reference copy
+  master_size = -1;
+  master_resolveFrameInfoDone = false;
+}
+
+DataDescriptor::~DataDescriptor ()
+{
+  free (name);
+  free (uname);
+  if (!isMaster)
+    return;
+  props->destroy ();
+  delete props;
+  data->destroy ();
+  delete data;
+  setsTBR->destroy ();
+  delete setsTBR;
+}
+
+void
+DataDescriptor::reset ()
+{
+  if (!isMaster)
+    return;
+  for (int i = 0; i < data->size (); i++)
+    {
+      Data *d = data->fetch (i);
+      if (d != NULL)
+       d->reset ();
+      Vector<long long> *set = setsTBR->fetch (i);
+      if (set != NULL)
+       set->reset ();
+    }
+  master_size = 0;
+}
+
+PropDescr *
+DataDescriptor::getProp (int prop_id)
+{
+  for (int i = 0; i < props->size (); i++)
+    {
+      PropDescr *propDscr = props->fetch (i);
+      if (propDscr->propID == prop_id)
+       return propDscr;
+    }
+  return NULL;
+}
+
+Data *
+DataDescriptor::getData (int prop_id)
+{
+  if (prop_id < 0 || prop_id >= data->size ())
+    return NULL;
+  return data->fetch (prop_id);
+}
+
+void
+DataDescriptor::addProperty (PropDescr *propDscr)
+{
+  if (propDscr == NULL)
+    return;
+  if (propDscr->propID < 0)
+    return;
+  PropDescr *oldProp = getProp (propDscr->propID);
+  if (oldProp != NULL)
+    {
+      checkCompatibility (propDscr->vtype, oldProp->vtype); //YXXX depends on experiment correctness
+      delete propDscr;
+      return;
+    }
+  props->append (propDscr);
+  data->store (propDscr->propID, Data::newData (propDscr->vtype));
+  setsTBR->store (propDscr->propID, NULL);
+}
+
+long
+DataDescriptor::addRecord ()
+{
+  if (!isMaster)
+    return -1;
+  return master_size++;
+}
+
+static void
+checkEntity (Vector<long long> *set, long long val)
+{
+  // Binary search
+  int lo = 0;
+  int hi = set->size () - 1;
+  while (lo <= hi)
+    {
+      int md = (lo + hi) / 2;
+      long long ent = set->fetch (md);
+      if (ent < val)
+       lo = md + 1;
+      else if (ent > val)
+       hi = md - 1;
+      else
+       return;
+    }
+  set->insert (lo, val);
+}
+
+void
+DataDescriptor::setDatumValue (int prop_id, long idx, const Datum *val)
+{
+  if (idx >= *ref_size)
+    return;
+  Data *d = getData (prop_id);
+  if (d != NULL)
+    {
+      VType_type datum_type = val->type;
+      VType_type data_type = d->type ();
+      checkCompatibility (datum_type, data_type);
+      d->setDatumValue (idx, val);
+      Vector<long long> *set = setsTBR->fetch (prop_id);
+      if (set != NULL)// Sets are maintained
+       checkEntity (set, d->fetchLong (idx));
+    }
+}
+
+void
+DataDescriptor::setValue (int prop_id, long idx, uint64_t val)
+{
+  if (idx >= *ref_size)
+    return;
+  Data *d = getData (prop_id);
+  if (d != NULL)
+    {
+      d->setValue (idx, val);
+      Vector<long long> *set = setsTBR->fetch (prop_id);
+      if (set != NULL)// Sets are maintained
+       checkEntity (set, d->fetchLong (idx));
+    }
+}
+
+void
+DataDescriptor::setObjValue (int prop_id, long idx, void *val)
+{
+  if (idx >= *ref_size)
+    return;
+  Data *d = getData (prop_id);
+  if (d != NULL)
+    d->setObjValue (idx, val);
+}
+
+DataView *
+DataDescriptor::createView ()
+{
+  return new DataView (this);
+}
+
+DataView *
+DataDescriptor::createImmutableView ()
+{
+  return new DataView (this, DataView::DV_IMMUTABLE);
+}
+
+DataView *
+DataDescriptor::createExtManagedView ()
+{
+  return new DataView (this, DataView::DV_EXT_MANAGED);
+}
+
+int
+DataDescriptor::getIntValue (int prop_id, long idx)
+{
+  Data *d = getData (prop_id);
+  if (d == NULL || idx >= d->getSize ())
+    return 0;
+  return d->fetchInt (idx);
+}
+
+unsigned long long
+DataDescriptor::getULongValue (int prop_id, long idx)
+{
+  Data *d = getData (prop_id);
+  if (d == NULL || idx >= d->getSize ())
+    return 0L;
+  return d->fetchULong (idx);
+}
+
+long long
+DataDescriptor::getLongValue (int prop_id, long idx)
+{
+  Data *d = getData (prop_id);
+  if (d == NULL || idx >= d->getSize ())
+    return 0L;
+  return d->fetchLong (idx);
+}
+
+void *
+DataDescriptor::getObjValue (int prop_id, long idx)
+{
+  Data *d = getData (prop_id);
+  if (d == NULL || idx >= d->getSize ())
+    return NULL;
+  return d->fetchObject (idx);
+}
+
+static int
+pcmp (const void *p1, const void *p2, const void *arg)
+{
+  long idx1 = *(long*) p1; // index1 into Data
+  long idx2 = *(long*) p2; // index2 into Data
+  for (Data **dsorted = (Data**) arg; *dsorted != DATA_SORT_EOL; dsorted++)
+    {
+      Data *data = *dsorted;
+      if (data == NULL)// sort property not in this data, skip this criteria
+       continue;
+      int res = data->cmpValues (idx1, idx2);
+      if (res)
+       return res;
+    }
+  // Provide stable sort
+  return idx1 < idx2 ? -1 : idx1 > idx2 ? 1 : 0;
+}
+
+Vector<long long> *
+DataDescriptor::getSet (int prop_id)
+{
+  if (prop_id < 0 || prop_id >= setsTBR->size ())
+    return NULL;
+  Vector<long long> *set = setsTBR->fetch (prop_id);
+  if (set != NULL)
+    return set;
+
+  Data *d = getData (prop_id);
+  if (d == NULL)
+    return NULL;
+  set = new Vector<long long>;
+  for (long i = 0; i<*ref_size; ++i)
+    checkEntity (set, d->fetchLong (i));
+  setsTBR->store (prop_id, set);
+
+  return set;
+}
+
+/*
+ *    class DataView
+ */
+DataView::DataView (DataDescriptor *_ddscr)
+{
+  init (_ddscr, DV_NORMAL);
+}
+
+DataView::DataView (DataDescriptor *_ddscr, DataViewType _type)
+{
+  init (_ddscr, _type);
+}
+
+void
+DataView::init (DataDescriptor *_ddscr, DataViewType _type)
+{
+  ddscr = _ddscr;
+  type = _type;
+  switch (type)
+    {
+    case DV_IMMUTABLE:
+      ddsize = ddscr->getSize ();
+      index = NULL;
+      break;
+    case DV_NORMAL:
+    case DV_EXT_MANAGED:
+      ddsize = 0;
+      index = new Vector<long>;
+      break;
+    }
+  for (int ii = 0; ii < (MAX_SORT_DIMENSIONS + 1); ii++)
+    sortedBy[ii] = DATA_SORT_EOL;
+  filter = NULL;
+}
+
+DataView::~DataView ()
+{
+  delete filter;
+  delete index;
+}
+
+void
+DataView::appendDataDescriptorId (long pkt_id /* ddscr index */)
+{
+  if (type != DV_EXT_MANAGED)
+    return; // updates allowed only on externally managed DataViews
+  long curr_ddsize = ddscr->getSize ();
+  if (pkt_id < 0 || pkt_id >= curr_ddsize)
+    return; // error!
+  index->append (pkt_id);
+}
+
+void
+DataView::setDataDescriptorValue (int prop_id, long pkt_id, uint64_t val)
+{
+  ddscr->setValue (prop_id, pkt_id, val);
+}
+
+long long
+DataView::getDataDescriptorValue (int prop_id, long pkt_id)
+{
+  return ddscr->getLongValue (prop_id, pkt_id);
+}
+
+Vector<PropDescr*>*
+DataView::getProps ()
+{
+  return ddscr->getProps ();
+};
+
+PropDescr*
+DataView::getProp (int prop_id)
+{
+  return ddscr->getProp (prop_id);
+};
+
+void
+DataView::filter_in_chunks (fltr_dbe_ctx *dctx)
+{
+  Expression::Context *e_ctx = new Expression::Context (dctx->fltr->ctx->dbev, dctx->fltr->ctx->exp);
+  Expression *n_expr = dctx->fltr->expr->copy ();
+  bool noParFilter = dctx->fltr->noParFilter;
+  FilterExp *nFilter = new FilterExp (n_expr, e_ctx, noParFilter);
+  long iter = dctx->begin;
+  long end = dctx->end;
+  long orig_ddsize = dctx->orig_ddsize;
+  while (iter < end)
+    {
+      nFilter->put (dctx->tmpView, iter);
+      if (nFilter->passes ())
+       dctx->idxArr[iter - orig_ddsize] = 1;
+      iter += 1;
+    }
+  delete nFilter;
+}
+
+bool
+DataView::checkUpdate ()
+{
+  long newSize = ddscr->getSize ();
+  if (ddsize == newSize)
+    return false;
+  if (index == NULL)
+    return false;
+  if (type == DV_EXT_MANAGED)
+    return false;
+  bool updated = false;
+  if (filter)
+    {
+      DataView *tmpView = ddscr->createImmutableView ();
+      assert (tmpView->getSize () == newSize);
+      while (ddsize < newSize)
+       {
+         filter->put (tmpView, ddsize);
+         if (filter->passes ())
+           index->append (ddsize);
+         ddsize += 1;
+       }
+      delete tmpView;
+      return updated;
+    }
+  while (ddsize < newSize)
+    {
+      index->append (ddsize);
+      updated = true;
+      ddsize += 1;
+    }
+  return updated;
+}
+
+long
+DataView::getSize ()
+{
+  if (checkUpdate () && sortedBy[0] != DATA_SORT_EOL)
+    // note: after new filter is set, getSize() incurs cost of
+    // sorting even if caller isn't interested in sort
+    index->sort ((CompareFunc) pcmp, sortedBy);
+
+  if (index == NULL)
+    return ddscr->getSize ();
+  return index->size ();
+}
+
+void
+DataView::setDatumValue (int prop_id, long idx, const Datum *val)
+{
+  ddscr->setDatumValue (prop_id, getIdByIdx (idx), val);
+}
+
+void
+DataView::setValue (int prop_id, long idx, uint64_t val)
+{
+  ddscr->setValue (prop_id, getIdByIdx (idx), val);
+}
+
+void
+DataView::setObjValue (int prop_id, long idx, void *val)
+{
+  ddscr->setObjValue (prop_id, getIdByIdx (idx), val);
+}
+
+int
+DataView::getIntValue (int prop_id, long idx)
+{
+  return ddscr->getIntValue (prop_id, getIdByIdx (idx));
+}
+
+unsigned long long
+DataView::getULongValue (int prop_id, long idx)
+{
+  return ddscr->getULongValue (prop_id, getIdByIdx (idx));
+}
+
+long long
+DataView::getLongValue (int prop_id, long idx)
+{
+  return ddscr->getLongValue (prop_id, getIdByIdx (idx));
+}
+
+void *
+DataView::getObjValue (int prop_id, long idx)
+{
+  return ddscr->getObjValue (prop_id, getIdByIdx (idx));
+}
+
+void
+DataView::sort (const int props[], int prop_count)
+{
+  if (index == NULL)
+    {
+      assert (ASSERT_SKIP);
+      return;
+    }
+  assert (prop_count >= 0 && prop_count < MAX_SORT_DIMENSIONS);
+  bool sort_changed = false; // see if sort has changed...
+  for (int ii = 0; ii <= prop_count; ii++)
+    { // sortedBy size is prop_count+1
+      Data *data;
+      if (ii == prop_count)
+       data = DATA_SORT_EOL; // special end of array marker
+      else
+       data = ddscr->getData (props[ii]);
+      if (sortedBy[ii] != data)
+       {
+         sortedBy[ii] = data;
+         sort_changed = true;
+       }
+    }
+  if (!checkUpdate () && !sort_changed)
+    return;
+  index->sort ((CompareFunc) pcmp, sortedBy);
+}
+
+void
+DataView::sort (int prop0)
+{
+  sort (&prop0, 1);
+}
+
+void
+DataView::sort (int prop0, int prop1)
+{
+  int props[2] = {prop0, prop1};
+  sort (props, 2);
+}
+
+void
+DataView::sort (int prop0, int prop1, int prop2)
+{
+  int props[3] = {prop0, prop1, prop2};
+  sort (props, 3);
+}
+
+void
+DataView::setFilter (FilterExp *f)
+{
+  if (index == NULL)
+    {
+      assert (ASSERT_SKIP);
+      return;
+    }
+  delete filter;
+  filter = f;
+  index->reset ();
+  ddsize = 0;
+  checkUpdate ();
+}
+
+long
+DataView::getIdByIdx (long idx)
+{
+  if (index == NULL)
+    return idx;
+  return index->fetch (idx);
+}
+
+static int
+tvalcmp (long data_id, const Datum valColumns[], Data *sortedBy[])
+{
+  for (int ii = 0; ii < MAX_SORT_DIMENSIONS; ii++)
+    {
+      if (sortedBy[ii] == DATA_SORT_EOL)
+       break;
+      Data *d = sortedBy[ii];
+      if (d == NULL)// property doesn't exist in data; compare always matches
+       continue;
+      const Datum *tvalue = &valColumns[ii];
+      int res = d->cmpDatumValue (data_id, tvalue);
+      if (res)
+       return res;
+    }
+  return 0;
+}
+
+static void
+checkSortTypes (const Datum valColumns[], Data *sortedBy[])
+{
+#ifndef NDEBUG
+  for (int ii = 0; ii < MAX_SORT_DIMENSIONS; ii++)
+    {
+      if (sortedBy[ii] == DATA_SORT_EOL)
+       break;
+      Data *d = sortedBy[ii];
+      if (d == NULL)// property doesn't exist in data; compare always matches
+       continue;
+      VType_type datum_type = valColumns[ii].type;
+      VType_type data_type = d->type ();
+      checkCompatibility (datum_type, data_type);
+    }
+#endif
+}
+
+bool
+DataView::idxRootDimensionsMatch (long idx, const Datum valColumns[])
+{
+  // compares idx vs. valColumns[] - If all dimensions match
+  // (except sort leaf), then the leaf value is valid => return true.
+  // Otherwise, return false.
+  checkSortTypes (valColumns, sortedBy);
+  if (idx < 0 || idx >= index->size ()) // fell off end of array
+    return false;
+  long data_id = index->fetch (idx);
+
+  // we will check all dimensions for a match except the "leaf" dimension
+  for (int ii = 0; ii < (MAX_SORT_DIMENSIONS - 1); ii++)
+    {
+      if (sortedBy[ii + 1] == DATA_SORT_EOL)
+       break; // we are at leaf dimension, don't care about it's value
+      if (sortedBy[ii] == DATA_SORT_EOL)
+       break; // end of list
+      Data *d = sortedBy[ii];
+      if (d == NULL) // property doesn't exist in data; compare always matches
+       continue;
+      const Datum *tvalue = &valColumns[ii];
+      int res = d->cmpDatumValue (data_id, tvalue);
+      if (res)
+       return false;
+    }
+  return true;
+}
+
+long
+DataView::getIdxByVals (const Datum valColumns[], Relation rel)
+{
+  // checks sortedBy[] columns for match; relation only used on last column
+  return getIdxByVals (valColumns, rel, -1, -1);
+}
+
+long
+DataView::getIdxByVals (const Datum valColumns[], Relation rel,
+                       long minIdx, long maxIdx)
+{
+  // checks sortedBy[] columns for match; relation only used on last column
+  checkSortTypes (valColumns, sortedBy);
+  if (index == NULL || sortedBy[0] == DATA_SORT_EOL)
+    return -1;
+
+  long lo;
+  if (minIdx < 0)
+    lo = 0;
+  else
+    lo = minIdx;
+
+  long hi;
+  if (maxIdx < 0 || maxIdx >= index->size ())
+    hi = index->size () - 1;
+  else
+    hi = maxIdx;
+
+  long md = -1;
+  while (lo <= hi)
+    {
+      md = (lo + hi) / 2;
+      int cmp = tvalcmp (index->fetch (md), valColumns, sortedBy);
+      if (cmp < 0)
+       {
+         lo = md + 1;
+         continue;
+       }
+      else if (cmp > 0)
+       {
+         hi = md - 1;
+         continue;
+       }
+
+      // cmp == 0, we have an exact match
+      switch (rel)
+       {
+       case REL_LT:
+         hi = md - 1; // continue searching
+         break;
+       case REL_GT:
+         lo = md + 1; // continue searching
+         break;
+       case REL_LTEQ:
+       case REL_GTEQ:
+       case REL_EQ:
+         // note: "md" may not be deterministic if multiple matches exist
+         return md; // a match => done.
+       }
+    }
+
+  // no exact match found
+  switch (rel)
+    {
+    case REL_LT:
+    case REL_LTEQ:
+      md = hi;
+      break;
+    case REL_GT:
+    case REL_GTEQ:
+      md = lo;
+      break;
+    case REL_EQ:
+      return -1;
+    }
+  if (idxRootDimensionsMatch (md, valColumns))
+    return md;
+  return -1;
+}
+
+void
+DataView::removeDbeViewIdx (long idx)
+{
+  index->remove (idx);
+}
+
diff --git a/gprofng/src/Table.h b/gprofng/src/Table.h
new file mode 100644 (file)
index 0000000..48ce06a
--- /dev/null
@@ -0,0 +1,618 @@
+/* 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 _TABLE_H
+#define _TABLE_H
+
+#include "vec.h"
+#include "Map2D.h"
+
+#include "dbe_structs.h"
+
+class FilterExp;
+struct PropDescr;
+struct FieldDescr;
+class PacketDescriptor;
+class DataDescriptor;
+class DataView;
+
+// Note: order must match VTYPE_TYPE_NAMES, below
+
+enum VType_type
+{
+  TYPE_NONE,
+  TYPE_INT32,
+  TYPE_UINT32,
+  TYPE_INT64,
+  TYPE_UINT64,
+  TYPE_STRING,
+  TYPE_DOUBLE,
+  TYPE_OBJ,
+  TYPE_DATE, // Used in FieldDescr only, mapped to TYPE_UINT64 in PropDescr
+  TYPE_BOOL, // Used only to describe filter props
+  TYPE_ENUM, // Used only to describe filter props
+
+  TYPE_LAST
+};
+
+#define VTYPE_TYPE_NAMES \
+{ \
+    NTXT("NONE"), \
+    NTXT("INT32"), \
+    NTXT("UINT32"), \
+    NTXT("INT64"), \
+    NTXT("UINT64"), \
+    NTXT("STRING"), \
+    NTXT("DOUBLE"), \
+    NTXT("OBJECT"), \
+    NTXT("DATE"), \
+    NTXT("BOOL"), \
+    NTXT("ENUM") \
+}
+
+// Note: order must match PROFDATA_TYPE_NAMES and PROFDATA_TYPE_UNAMES, below
+
+enum ProfData_type
+{ // a.k.a "data_id" (not the same as Pckt_type "kind")
+  DATA_SAMPLE,      // Traditional collect "Samples"
+  DATA_GCEVENT,     // Java Garbage Collection events
+  DATA_HEAPSZ,      // heap size tracking based on heap tracing data
+  DATA_CLOCK,       // clock profiling data
+  DATA_HWC,         // hardware counter profiling data
+  DATA_SYNCH,       // synchronization tracing data
+  DATA_HEAP,        // heap tracing data
+  DATA_MPI,         // MPI tracing data
+  DATA_RACE,        // data race detection data
+  DATA_DLCK,        // deadlock detection data
+  DATA_OMP,         // OpenMP profiling data (fork events)
+  DATA_OMP2,        // OpenMP profiling data (enter thread events)
+  DATA_OMP3,        // OpenMP profiling data (enter task events)
+  DATA_OMP4,        // OpenMP profiling data (parreg descriptions)
+  DATA_OMP5,        // OpenMP profiling data (task descriptions)
+  DATA_IOTRACE,     // IO tracing data
+  DATA_LAST
+};
+
+extern char *get_prof_data_type_name (int t);
+extern char *
+get_prof_data_type_uname (int t);
+
+enum Prop_type
+{
+  PROP_NONE,
+  // commonly used properties (libcollector modules, er_print)
+  PROP_ATSTAMP,     // hrtime_t, Filter: system HRT timestamp;
+                   // "Absolute TSTAMP"
+  PROP_ETSTAMP,     // hrtime_t, Filter: nanoseconds from subexperiment start;
+                   // "subExperiment TSTAMP"
+  PROP_TSTAMP,      // hrtime_t, Packet: system HRT timestamp
+                   // Filter: nanoseconds from founder start
+  PROP_THRID,       // mapped to uint32_t by readPacket
+  PROP_LWPID,       // mapped to uint32_t by readPacket
+  PROP_CPUID,       // mapped to uint32_t by readPacket
+  PROP_FRINFO,      // uint64_t        frinfo
+  PROP_EVT_TIME,    // hrtime_t Filter: Time delta
+  // If TSTAMP taken at end of event, EVT_TIME will be positive
+  // If TSTAMP taken at start of event, EVT_TIME will be negative
+  // Note: clock and hwc profile events set EVT_TIME=0
+  //    except Solaris Microstate events where NTICK>1:
+  //    These will use EVT_TIME=(NTICK-1)*<tick duration>
+
+  // DATA_SAMPLE
+  PROP_SAMPLE,      // uint64_t sample number
+  PROP_SMPLOBJ,     // Sample*
+
+  // DATA_GCEVENT
+  PROP_GCEVENT,     // uint64_t event id
+  PROP_GCEVENTOBJ,  // GCEvent*
+
+  // DATA_CLOCK
+  PROP_MSTATE,      // unsigned        ProfilePacket::mstate
+  PROP_NTICK,       // unsigned        ProfilePacket::value
+  PROP_OMPSTATE,    // int ProfilePacket::ompstate
+  PROP_MPISTATE,    // int ProfilePacket::mpistate
+
+  // DATA_SAMPLE     // see PrUsage class, see PROP_MSTATE - TBR?
+  PROP_UCPU,
+  PROP_SCPU,
+  PROP_TRAP,
+  PROP_TFLT,
+  PROP_DFLT,
+  PROP_KFLT,
+  PROP_ULCK,
+  PROP_TSLP,
+  PROP_WCPU,
+  PROP_TSTP,
+
+  // DATA_SYNCH
+  PROP_SRQST,       // hrtime_t SyncPacket::requested
+  PROP_SOBJ,        // Vaddr SyncPacket::objp
+
+  // DATA_HWC
+  PROP_HWCTAG,      // uint32_t HWCntrPacket::tag;
+  PROP_HWCINT,      // uint64_t HWCntrPacket::interval
+  PROP_VADDR,       // Vaddr HWCntrPacket::dbeVA->eaddr
+  PROP_PADDR,       // Vaddr HWCntrPacket::dbePA->eaddr
+  PROP_HWCDOBJ,     // DataObject* HWCntrPacket::dobj
+  PROP_VIRTPC,      // Vaddr HWCntrPacket::eventVPC
+  PROP_PHYSPC,      // Vaddr HWCntrPacket::eventPPC
+  PROP_EA_PAGESIZE, // uint32_t HWCntrPacket::ea_pagesize
+  PROP_PC_PAGESIZE, // uint32_t HWCntrPacket::pc_pagesize
+  PROP_EA_LGRP,     // uint32_t HWCntrPacket::ea_lgrp
+  PROP_PC_LGRP,     // uint32_t HWCntrPacket::pc_lgrp
+  PROP_LWP_LGRP_HOME, // uint32_t HWCntrPacket::lwp_lgrp_home
+  PROP_PS_LGRP_HOME,  // uint32_t HWCntrPacket::ps_lgrp_home
+  PROP_MEM_LAT,     // uint64_t HWCntrPacket::latency
+  PROP_MEM_SRC,     // uint64_t HWCntrPacket::data_source
+
+  // DATA_HEAP
+  PROP_HTYPE,       // Heap_type HeapPacket::mtype
+  PROP_HSIZE,       // Size HeapPacket::size (bytes alloc'd by this event)
+  PROP_HVADDR,      // Vaddr HeapPacket::vaddr
+  PROP_HOVADDR,     // Vaddr HeapPacket::ovaddr
+  PROP_HLEAKED,     // Size HeapPacket::leaked (net bytes leaked)
+  PROP_HMEM_USAGE,  // Size heap memory usage
+  PROP_HFREED,      // Size (bytes freed by this event)
+  PROP_HCUR_ALLOCS, // int64_t (net allocations running total.  Recomputed after each filter)
+  PROP_HCUR_NET_ALLOC, // int64_t (net allocation for this packet.  Recomputed after each filter)
+  PROP_HCUR_LEAKS,  // Size (net leaks running total.  Recomputed after each filter)
+
+  // DATA_IOTRACE
+  PROP_IOTYPE,      // IOTrace_type IOTracePacket::iotype
+  PROP_IOFD,        // int32_t IOTracePacket::fd
+  PROP_IONBYTE,     // Size_type IOTracePacket::nbyte
+  PROP_IORQST,      // hrtime_t IOTracePacket::requested
+  PROP_IOOFD,       // int32_t IOTracePacket::ofd
+  PROP_IOFSTYPE,    // FileSystem_type IOTracePacket::fstype
+  PROP_IOFNAME,     // char IOTracePacket::fname
+  PROP_IOVFD,       // int32_t virtual file descriptor
+
+  // DATA_MPI
+  PROP_MPITYPE,     // MPI_type MPIPacket::mpitype
+  PROP_MPISCOUNT,   // Size MPIPacket::scount
+  PROP_MPISBYTES,   // Size MPIPacket::sbytes
+  PROP_MPIRCOUNT,   // Size MPIPacket::rcount
+  PROP_MPIRBYTES,   // Size MPIPacket::rbytes
+
+  // DATA_OMP*
+  PROP_CPRID,       // uint64_t (Note: not same as "PROP_CPRID" below)
+  PROP_PPRID,       // uint64_t OMPPacket::omp_pprid
+  PROP_TSKID,       // uint64_t (Note: not same as "PROP_CPRID" below)
+  PROP_PTSKID,      // uint64_t OMPPacket::omp_ptskid
+  PROP_PRPC,        // uint64_t OMPPacket::omp_prpc
+
+  // DATA_RACE
+  PROP_RTYPE,       // Race_type RacePacket::rtype
+  PROP_RID,         // uint32_t RacePacket::id
+  PROP_RVADDR,      // Vaddr RacePacket::vaddr
+  PROP_RCNT,        // uint32_t RacePacket::count
+  PROP_LEAFPC,      // Vaddr CommonPacket::leafpc
+
+  // DATA_DLCK
+  PROP_DID,         // uint32_t DeadlockPacket::id
+  PROP_DTYPE,       // Deadlock_Lock_type DeadlockPacket::lock_type
+  PROP_DLTYPE,      // Deadlock_type DeadlockPacket::dl_type
+  PROP_DVADDR,      // Vaddr DeadlockPacket::lock_addr
+
+  // Synthetic properties (queries only)
+  PROP_STACKID,
+  PROP_STACK,       // void* Generic; mapped to M, U, or XSTACK
+  PROP_MSTACK,      // void* machine stack
+  PROP_USTACK,      // void* user_stack
+  PROP_XSTACK,      // void* expert_stack
+  PROP_HSTACK,      // void* hide_stack
+  //PROP_CPRID,       // void* (Note: not same as "PROP_CPRID" above)
+  //PROP_TSKID,       // void* (Note: not same as "PROP_TSKID" above)
+  PROP_JTHREAD,     // JThread* CommonPacket::jthread
+  PROP_LEAF,        // uint64_t stack leaf function
+  PROP_DOBJ,        // "DOBJ" DataObject*
+  PROP_SAMPLE_MAP,  // Map events to SAMPLE using sample's time range
+  PROP_GCEVENT_MAP, // Map events to GCEVENT using gcevent's time range
+  PROP_PID,         // int unix getpid()
+  PROP_EXPID,       // int Experiment->getUserExpId(), AKA process number, >=1.
+  PROP_EXPID_CMP,   // int "Comparable PROP_EXPID".  In compare mode, if this
+  //              process has been matched to another groups' process,
+  //              returns PROP_EXPID of the matching process with the
+  //              lowest PROP_EXPGRID value.  Otherwise returns PROP_EXPID.
+  PROP_EXPGRID,     // int Comparison group number.  >=0, 0 is Baseline.
+  PROP_PARREG,      // "PARREG" uint64_t (see 6436500) TBR?
+  PROP_TSTAMP_LO,   // hrtime_t Filter: Event's low TSTAMP
+  PROP_TSTAMP_HI,   // hrtime_t Filter: Event's high TSTAMP
+  PROP_TSTAMP2,     // hrtime_t Filter: End TSTAMP (TSTAMP<=TSTAMP2)
+  PROP_FREQ_MHZ,    // int frequency in MHZ (for converting HWC profiling cycles to time)
+  PROP_NTICK_USEC,  // hrtime_t Clock profiling interval, microseconds (PROP_NTICK * Experiment->ptimer_usec)
+  PROP_IOHEAPBYTES, // Size PROP_HSIZE or PROP_IONBYTE
+  PROP_STACKL,      // void* Generic; mapped to M, U, or XSTACK for DbeLine
+  PROP_MSTACKL,     // void* machine stack
+  PROP_USTACKL,     // void* user_stack
+  PROP_XSTACKL,     // void* expert_stack
+  PROP_STACKI,      // void* Generic; mapped to M, U, or XSTACK for DbeInstr
+  PROP_MSTACKI,     // void* machine stack
+  PROP_USTACKI,     // void* user_stack
+  PROP_XSTACKI,     // void* expert_stack
+  PROP_DDSCR_LNK,   // long long index into DataDescriptor table for a related event
+  PROP_VOIDP_OBJ,   // void* pointer to object containing metadata
+  PROP_LAST
+};
+
+enum Prop_flag
+{
+  PRFLAG_NOSHOW     = 0x40
+};
+
+struct PropDescr
+{
+  PropDescr (int propID, const char *name);
+  virtual ~PropDescr ();
+
+  void addState (int value, const char *stname, const char *stuname);
+  char *getStateName (int value);
+  char *getStateUName (int value);
+
+  int
+  getMaxState ()
+  {
+    return stateNames ? stateNames->size () : 0;
+  }
+
+  int propID;
+  char *name;
+  char *uname;
+  VType_type vtype;
+  int flags;
+
+private:
+  Vector<char*>*stateNames;
+  Vector<char*>*stateUNames;
+};
+
+struct FieldDescr
+{
+  FieldDescr (int propID, const char *name);
+  virtual ~FieldDescr ();
+
+  int propID;
+  char *name;
+  int offset;
+  VType_type vtype;
+  char *format;
+};
+
+class PacketDescriptor
+{
+public:
+  PacketDescriptor (DataDescriptor*);
+  virtual ~PacketDescriptor ();
+
+  DataDescriptor *
+  getDataDescriptor ()
+  {
+    return ddscr;
+  }
+
+  Vector<FieldDescr*> *
+  getFields ()
+  {
+    return fields;
+  }
+
+  void addField (FieldDescr*);
+
+private:
+  DataDescriptor *ddscr;
+  Vector<FieldDescr*> *fields;
+};
+
+struct Datum
+{
+
+  void
+  setUINT32 (uint32_t vv)
+  {
+    type = TYPE_UINT32;
+    i = vv;
+  }
+
+  void
+  setUINT64 (uint64_t vv)
+  {
+    type = TYPE_UINT64;
+    ll = vv;
+  }
+
+  void
+  setSTRING (char* vv)
+  {
+    type = TYPE_STRING;
+    l = vv;
+  }
+
+  void
+  setDOUBLE (double vv)
+  {
+    type = TYPE_DOUBLE;
+    d = vv;
+  }
+
+  void
+  setOBJ (void* vv)
+  {
+    type = TYPE_OBJ;
+    p = vv;
+  }
+
+  VType_type type;
+  union
+  {
+    int i;
+    double d;
+    char *l;
+    void *p;
+    unsigned long long ll;
+  };
+};
+
+class Data
+{
+public:
+  static Data *newData (VType_type);
+
+  virtual
+  ~Data () { }
+
+  virtual VType_type
+  type ()
+  {
+    return TYPE_NONE;
+  }
+  virtual void reset () = 0;
+  virtual long getSize () = 0;
+  virtual int fetchInt (long i) = 0;
+  virtual unsigned long long fetchULong (long i) = 0;
+  virtual long long fetchLong (long i) = 0;
+  virtual char *fetchString (long i) = 0;
+  virtual double fetchDouble (long i) = 0;
+  virtual void *fetchObject (long i) = 0;
+  virtual void setDatumValue (long, const Datum*) = 0;
+  virtual void setValue (long, uint64_t) = 0;
+  virtual void setObjValue (long, void*) = 0;
+  virtual int cmpValues (long idx1, long idx2) = 0;
+  virtual int cmpDatumValue (long idx, const Datum *val) = 0;
+};
+
+enum Data_flag
+{
+  DDFLAG_NOSHOW = 0x01
+};
+
+class DataDescriptor
+{
+  /*
+   * An instance of this class stores the data packets for a specific
+   * type of profiling, for example, clock profiling.
+   *
+   * Each packet consists of values for various properties.
+   * For example, a timestamp is a property which is accessed with PROP_TSTAMP.
+   *
+   * Ideally, DataDescriptor contents are considered immutable after the
+   * data is read in.  setValue() should only be used during creation.
+   * - The packets are in fixed order.  This allows DataDescriptor <pkt_id>
+   *   to be treated as a stable handle.
+   * - Sorting/filtering is handled by the DataView class
+   * - In the future, if we need to add the ability to append new packets,
+   *   we might add a flag to show when the class is immutable and/or appendible
+   */
+public:
+
+  DataDescriptor (int id, const char* name, const char* uname, int flags = 0); // master
+  DataDescriptor (int id, const char* name, const char* uname, DataDescriptor*); // reference copy
+  ~DataDescriptor ();
+
+  // packets' descriptions
+  int
+  getId ()
+  {
+    return id;
+  }
+
+  char *
+  getName ()
+  {
+    return name;
+  }
+
+  char *
+  getUName ()
+  {
+    return uname;
+  }
+
+  Vector<PropDescr*> *
+  getProps ()
+  {
+    return props;       // packet properties
+  }
+  PropDescr *getProp (int prop_id);     // packet property
+
+  long
+  getSize ()
+  {
+    return *ref_size;   // number of packets
+  }
+
+  long
+  getFlags ()
+  {
+    return flags;
+  }
+
+  // class to provide sorting and filtering
+  DataView *createView ();
+  DataView *createImmutableView ();
+  DataView *createExtManagedView ();
+
+  // packet property values (<pkt_id> is stable packet handle)
+  int getIntValue (int prop_id, long pkt_id);
+  unsigned long long getULongValue (int prop_id, long pkt_id);
+  long long getLongValue (int prop_id, long pkt_id);
+  void *getObjValue (int prop_id, long pkt_id);
+  Vector<long long> *getSet (int prop_id); // list of sorted, unique values
+
+  // table creation/reset
+  void addProperty (PropDescr*); // add property to all packets
+  long addRecord ();            // add packet
+  Data *getData (int prop_id);  // get all packets
+  void setDatumValue (int prop_id, long pkt_id, const Datum *val);
+  void setValue (int prop_id, long pkt_id, uint64_t val);
+  void setObjValue (int prop_id, long pkt_id, void *val);
+  void reset ();                // remove all packets (ym: TBR?)
+
+  void
+  setResolveFrInfoDone ()
+  {
+    *ref_resolveFrameInfoDone = true;
+  }
+
+  bool
+  isResolveFrInfoDone ()
+  {
+    return *ref_resolveFrameInfoDone;
+  }
+
+
+private:
+  bool isMaster;
+  int flags;        // see Data_flag enum
+  int id;
+  char *name;
+  char *uname;
+
+  // the following should only be accessed if parent==NULL
+  long master_size;
+  bool master_resolveFrameInfoDone;
+
+  // the following point to the master DataDescriptor's fields
+  long *ref_size;
+  bool *ref_resolveFrameInfoDone;
+  Vector<PropDescr*> *props;
+  Vector<Data*> *data;
+  Vector<Vector<long long>*> *setsTBR; // Sets of unique values
+};
+
+typedef struct
+{
+  long begin;
+  long end;
+  long orig_ddsize;
+  DataView *tmpView;
+  long *idxArr;
+  FilterExp *fltr;
+} fltr_dbe_ctx;
+
+class DataView
+{
+  /*
+   * Provides sorting and filtering of DataDescriptor packets
+   */
+public:
+
+  enum Relation
+  {
+    REL_LT,
+    REL_LTEQ,
+    REL_EQ,
+    REL_GTEQ,
+    REL_GT
+  };
+
+  enum DataViewType
+  {
+    DV_NORMAL,      // filterable, sortable
+    DV_IMMUTABLE,   // reflects exact data in DataDescriptor
+    DV_EXT_MANAGED  // sortable.  index[] entries managed externally.
+  };
+
+  DataView (DataDescriptor*);
+  DataView (DataDescriptor*, DataViewType);
+  virtual ~DataView ();
+
+  Vector<PropDescr*> *getProps ();
+  PropDescr *getProp (int prop_id);
+  long getSize ();      // number of post-filter packets
+
+  // packet property values accessed by sort index (not DataDescriptor pkt_id)
+  int getIntValue (int prop_id, long idx);
+  unsigned long long getULongValue (int prop_id, long idx);
+  long long getLongValue (int prop_id, long idx);
+  void *getObjValue (int prop_id, long idx);
+  long getIdByIdx (long idx);   // returns DataDescriptor pkt_id
+
+  // define sort/filter
+  void sort (const int props[], int prop_count);
+  void sort (int prop);
+  void sort (int prop1, int prop2);
+  void sort (int prop1, int prop2, int prop3);
+  void setFilter (FilterExp*);
+
+  // search packets
+  // - sort must already be defined
+  // - requires the user to provide all properties used in current sort.
+  // - For a match, the all but the last sort property (the "leaf")
+  //   must match exactly.
+  long getIdxByVals (const Datum valColumns[], Relation rel);
+  long getIdxByVals (const Datum valColumns[], Relation rel,
+                    long minIdx, long maxIdx); //limit idx search range
+  bool idxRootDimensionsMatch (long idx, const Datum valColumns[]);
+  // packet at idx matches all non-leaf values in valColumns
+
+  // use during table creation, updates underlying DataDescriptor
+  void setDatumValue (int prop_id, long idx, const Datum *val);
+  void setValue (int prop_id, long idx, uint64_t val);
+  void setObjValue (int prop_id, long idx, void *val);
+
+  DataDescriptor *
+  getDataDescriptor ()
+  {
+    return ddscr;
+  }
+
+  void removeDbeViewIdx (long idx);
+
+  // for use with DV_EXT_MANAGED DataViews:
+  void appendDataDescriptorId (long pkt_id);
+  void setDataDescriptorValue (int prop_id, long pkt_id, uint64_t val);
+  long long getDataDescriptorValue (int prop_id, long pkt_id);
+
+private:
+  bool checkUpdate ();
+  void init (DataDescriptor*, DataViewType);
+
+  static void filter_in_chunks (fltr_dbe_ctx *dctx);
+  DataDescriptor *ddscr;
+  long ddsize;
+  Vector<long> *index; // sorted vector of data_id (index into dDscr)
+#define MAX_SORT_DIMENSIONS 10
+#define DATA_SORT_EOL ((Data *) -1)     /* marks end of sortedBy[] array */
+  Data *sortedBy[MAX_SORT_DIMENSIONS + 1]; // columns for sort
+  FilterExp *filter;
+  DataViewType type;
+};
+
+#endif /* _TABLE_H */
diff --git a/gprofng/src/UserLabel.cc b/gprofng/src/UserLabel.cc
new file mode 100644 (file)
index 0000000..bdb9922
--- /dev/null
@@ -0,0 +1,177 @@
+/* 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 "DbeSession.h"
+#include "Expression.h"
+#include "StringBuilder.h"
+#include "util.h"
+#include "UserLabel.h"
+#include "debug.h"
+
+int UserLabel::last_id = 0;
+
+UserLabel::UserLabel (char *_name)
+{
+  name = dbe_strdup (_name);
+  comment = str_expr = all_times = hostname = NULL;
+  start_f = stop_f = false;
+  expr = NULL;
+  start_tv.tv_sec = 0;
+  start_tv.tv_usec = 0;
+  atime = timeStart = timeStop = start_sec = start_hrtime = 0;
+  relative = REL_TIME;
+  id = ++last_id;
+}
+
+UserLabel::~UserLabel ()
+{
+  free (name);
+  free (comment);
+  free (all_times);
+  free (hostname);
+  free (str_expr);
+  delete expr;
+}
+
+void
+UserLabel::gen_expr ()
+{
+  if (!start_f && !stop_f)
+    return;
+  StringBuilder sb;
+  sb.append ('(');
+  if (str_expr)
+    {
+      sb.append (str_expr);
+      sb.append (NTXT (" || ("));
+    }
+  if (start_f)
+    {
+      sb.append (NTXT ("TSTAMP"));
+      sb.append (NTXT (">="));
+      sb.append (timeStart);
+      if (stop_f)
+       {
+         sb.append (NTXT (" && "));
+       }
+    }
+  if (stop_f)
+    {
+      sb.append (NTXT ("TSTAMP"));
+      sb.append ('<');
+      sb.append (timeStop);
+    }
+  sb.append (')');
+  if (str_expr)
+    {
+      sb.append (')');
+      delete str_expr;
+    }
+  str_expr = sb.toString ();
+  start_f = stop_f = false;
+}
+
+void
+UserLabel::register_user_label (int groupId)
+{
+  gen_expr ();
+  if (str_expr)
+    {
+      char *old_str = str_expr;
+      str_expr = dbe_sprintf (NTXT ("(EXPGRID==%d && %s)"), groupId, old_str);
+      delete old_str;
+      UserLabel *ulbl = dbeSession->findUserLabel (name);
+      if (ulbl)
+       {
+         old_str = ulbl->str_expr;
+         ulbl->str_expr = dbe_sprintf (NTXT ("(%s || %s)"), old_str, str_expr);
+         delete old_str;
+         if (comment)
+           {
+             if (ulbl->comment)
+               {
+                 old_str = ulbl->comment;
+                 ulbl->comment = dbe_sprintf (NTXT ("%s; %s"), old_str, comment);
+                 delete old_str;
+               }
+             else
+               ulbl->comment = dbe_strdup (comment);
+           }
+         delete ulbl->expr;
+         ulbl->expr = dbeSession->ql_parse (ulbl->str_expr);
+       }
+      else
+       {
+         expr = dbeSession->ql_parse (str_expr);
+         dbeSession->append (this);
+       }
+    }
+}
+
+char *
+UserLabel::dump ()
+{
+  StringBuilder sb;
+  sb.append (name);
+  if (str_expr)
+    {
+      sb.append (NTXT ("  str_expr='"));
+      sb.append (str_expr);
+      sb.append ('\'');
+    }
+  if (all_times)
+    {
+      sb.append (NTXT (" atime="));
+      sb.append ((unsigned int) (atime / NANOSEC));
+      sb.append ('.');
+      char buf[128];
+      snprintf (buf, sizeof (buf), NTXT ("%09llu"), (unsigned long long) (atime % NANOSEC));
+      sb.append (buf);
+      sb.append (NTXT ("  all_times='"));
+      sb.append (all_times);
+      sb.append ('\'');
+    }
+  if (comment)
+    {
+      sb.append (NTXT ("  comment='"));
+      sb.append (comment);
+      sb.append ('\'');
+    }
+  return sb.toString ();
+}
+
+void
+UserLabel::dump (const char *msg, Vector<UserLabel*> *labels)
+{
+  if (!DUMP_USER_LABELS)
+    return;
+  if (msg)
+    fprintf (stderr, NTXT ("%s\n"), msg);
+  for (int i = 0, sz = labels ? labels->size () : 0; i < sz; i++)
+    {
+      UserLabel *lbl = labels->fetch (i);
+      char *s = lbl->dump ();
+      fprintf (stderr, NTXT ("%2d %s\n"), i, s);
+      delete s;
+    }
+}
diff --git a/gprofng/src/UserLabel.h b/gprofng/src/UserLabel.h
new file mode 100644 (file)
index 0000000..0cb37e4
--- /dev/null
@@ -0,0 +1,61 @@
+/* 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 _USER_LABEL_H
+#define _USER_LABEL_H
+
+#include <time.h>
+#include "vec.h"
+
+class Expression;
+class StringBuilder;
+
+class UserLabel
+{
+public:
+
+  enum
+  {
+    REL_TIME = 0,
+    ABS_TIME = 1,
+    CUR_TIME = 2
+  };
+
+  UserLabel (char *_name);
+  ~UserLabel ();
+  void register_user_label (int groupId);
+  void gen_expr ();
+  char *dump ();
+  static void dump (const char *msg, Vector<UserLabel*> *labels);
+
+  char *name, *comment, *str_expr, *all_times, *hostname;
+  bool start_f, stop_f;
+  Expression *expr;
+  timeval start_tv;
+  long long atime, timeStart, timeStop, start_sec, start_hrtime;
+  int id, relative;
+
+private:
+  void gen_time_expr (StringBuilder *sb, long long hrtime, char *op);
+
+  static int last_id;
+};
+
+#endif
diff --git a/gprofng/src/checks.cc b/gprofng/src/checks.cc
new file mode 100644 (file)
index 0000000..105821e
--- /dev/null
@@ -0,0 +1,516 @@
+/* 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 <ctype.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <sys/param.h>
+
+#include "gp-defs.h"
+#include "Elf.h"
+#include "collctrl.h"
+#include "i18n.h"
+#include "util.h"
+#include "collect.h"
+
+void
+collect::check_target (int argc, char **argv)
+{
+  char *next;
+  char *last = 0;
+  char *a;
+  char *ccret;
+  char **lasts = &last;
+  int tindex = targ_index;
+  int ret;
+  char *basename;
+  is_64 = false;
+
+  /* now check the executable */
+  nargs = argc - targ_index;
+  Exec_status rv = check_executable (argv[targ_index]);
+  switch (rv)
+    {
+    case EXEC_OK:
+      njargs = cc->get_java_arg_cnt ();
+      arglist = (char **) calloc (nargs + 5 + njargs, sizeof (char *));
+      jargs = cc->get_java_args ();
+
+      // store the first argument -- target name
+      ret = 0;
+      arglist[ret++] = argv[tindex++];
+      if (cc->get_java_mode () == 1)
+       {
+         // add any user-specified -J (Java) arguments
+         int length = (int) strlen (argv[targ_index]);
+         int is_java = 0;
+         if ((length >= 6) && strcmp (&argv[targ_index][length - 5], NTXT ("/java")) == 0)
+           is_java = 1;
+         else if ((length == 4) && strcmp (&argv[targ_index][0], NTXT ("java")) == 0)
+           is_java = 1;
+         if (njargs != 0 && is_java)
+           {
+             next = strtok_r (jargs, NTXT (" \t"), lasts);
+             arglist[ret++] = next;
+             for (;;)
+               {
+                 next = strtok_r (NULL, NTXT (" \t"), lasts);
+                 if (next == NULL)
+                   break;
+                 arglist[ret++] = next;
+               }
+           }
+       }
+
+      // copy the rest of the arguments
+      for (int i = 1; i < nargs; i++)
+       arglist[ret++] = argv[tindex++];
+      nargs = ret;
+      break;
+    case EXEC_IS_JAR:
+      // Preface the user-supplied argument list with
+      //       the path to the java, the collector invocation,
+      //       any -J java arguments provided, and "-jar".
+      ccret = cc->set_java_mode (NTXT ("on"));
+      if (ccret != NULL)
+       {
+         writeStr (2, ccret);
+         exit (1);
+       }
+      njargs = cc->get_java_arg_cnt ();
+      arglist = (char **) calloc (nargs + 5 + njargs, sizeof (char *));
+      jargs = cc->get_java_args ();
+
+      a = find_java ();
+      if (a == NULL)
+       exit (1); // message was written
+      ret = 0;
+      arglist[ret++] = a;
+      // add any user-specified Java arguments
+      if (njargs != 0)
+       {
+         next = strtok_r (jargs, NTXT (" \t"), lasts);
+         arglist[ret++] = next;
+         for (;;)
+           {
+             next = strtok_r (NULL, NTXT (" \t"), lasts);
+             if (next == NULL)
+               break;
+             arglist[ret++] = next;
+           }
+       }
+      arglist[ret++] = NTXT ("-jar");
+      for (int i = 0; i < nargs; i++)
+       arglist[ret++] = argv[tindex++];
+      nargs = ret;
+      break;
+    case EXEC_IS_CLASSCLASS:
+      // remove the .class from the name
+      ret = (int) strlen (argv[targ_index]);
+      argv[targ_index][ret - 6] = 0;
+
+      // now fall through to the EXEC_IS_CLASS case
+    case EXEC_IS_CLASS:
+      // Preface the user-supplied argument list with
+      //       the path to the java, the collector invocation,
+      //       and any -J java arguments provided.
+      ccret = cc->set_java_mode (NTXT ("on"));
+      if (ccret != NULL)
+       {
+         writeStr (2, ccret);
+         exit (1);
+       }
+      jargs = cc->get_java_args ();
+      njargs = cc->get_java_arg_cnt ();
+      arglist = (char **) calloc (nargs + 4 + njargs, sizeof (char *));
+
+      a = find_java ();
+      if (a == NULL)
+       exit (1); // message was written
+      ret = 0;
+      arglist[ret++] = a;
+      // add any user-specified Java arguments
+      if (njargs != 0)
+       {
+         next = strtok_r (jargs, NTXT (" \t"), lasts);
+         arglist[ret++] = next;
+         for (;;)
+           {
+             next = strtok_r (NULL, NTXT (" \t"), lasts);
+             if (next == NULL)
+               break;
+             arglist[ret++] = next;
+           }
+       }
+
+      // copy the remaining arguments to the new list
+      for (int i = 0; i < nargs; i++)
+       arglist[ret++] = argv[tindex++];
+      nargs = ret;
+      break;
+    case EXEC_ELF_NOSHARE:
+    case EXEC_OPEN_FAIL:
+    case EXEC_ELF_LIB:
+    case EXEC_ELF_HEADER:
+    case EXEC_ELF_ARCH:
+    case EXEC_ISDIR:
+    case EXEC_NOT_EXEC:
+    case EXEC_NOT_FOUND:
+    default:
+      /* something wrong; write a message */
+      char *errstr = status_str (rv, argv[targ_index]);
+      if (errstr)
+       {
+         dbe_write (2, "%s", errstr);
+         free (errstr);
+       }
+      exit (1);
+    }
+  cc->set_target (arglist[0]);
+
+  /* check the experiment */
+  char *ccwarn;
+  ccret = cc->check_expt (&ccwarn);
+  if (ccwarn != NULL)
+    {
+      writeStr (2, ccwarn);
+      free (ccwarn);
+    }
+  if (ccret != NULL)
+    {
+      writeStr (2, ccret);
+      exit (1);
+    }
+  /* check if java, to see if -j flag was given */
+  if ((basename = strrchr (arglist[0], '/')) == NULL)
+    basename = arglist[0];
+  else
+    basename++;
+  if (strcmp (basename, NTXT ("java")) == 0)
+    {
+      /* the target's name is java; was java flag set? */
+      if ((jseen_global == 0) && (cc->get_java_mode () == 0))
+       {
+         char *cret = cc->set_java_mode (NTXT ("on"));
+         if (cret != NULL)
+           {
+             writeStr (2, cret);
+             exit (1);
+           }
+       }
+    }
+}
+
+collect::Exec_status
+collect::check_executable (char *target_name)
+{
+  char target_path[MAXPATHLEN];
+  struct stat64 statbuf;
+  if (target_name == NULL) // not set, but assume caller knows what it's doing
+    return EXEC_OK;
+  if (getenv ("GPROFNG_SKIP_VALIDATION")) // don't check target
+    return EXEC_OK;
+
+  // see if target exists and is not a directory
+  if ((dbe_stat (target_name, &statbuf) == 0) && ((statbuf.st_mode & S_IFMT) != S_IFDIR))
+    {
+      // target is found, check for access as executable
+      if (access (target_name, X_OK) != 0)
+       {
+         // not an executable, check for jar or class file
+         int i = (int) strlen (target_name);
+         if ((i >= 5) && strcmp (&target_name[i - 4], NTXT (".jar")) == 0)
+           {
+             // could be a jar file
+             // XXXX -- need better check for real jar file
+             cc->set_java_mode ("on");
+             return EXEC_IS_JAR;
+           }
+         if ((i >= 7) && strcmp (&target_name[i - 6], NTXT (".class")) == 0)
+           {
+             // could be a class file
+             // XXXX -- need better check for real class file
+             cc->set_java_mode (NTXT ("on"));
+             return EXEC_IS_CLASSCLASS;
+           }
+         // not a jar or class file, return not an executable
+         return EXEC_NOT_EXEC;
+       }
+      else  // found, and it is executable. set the path to it
+       snprintf (target_path, sizeof (target_path), NTXT ("%s"), target_name);
+    }
+  else
+    {
+      // not found, look on path
+      char *exe_name = get_realpath (target_name);
+      if (access (exe_name, X_OK) == 0)
+       {
+         // target can't be located
+         // one last attempt: append .class to name, and see if we can find it
+         snprintf (target_path, sizeof (target_path), NTXT ("%s.class"), target_name);
+         if (dbe_stat (target_path, &statbuf) == 0)
+           {
+             // the file exists
+             if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
+               {
+                 // this is a directory; that won't do.
+                 return EXEC_ISDIR;
+               }
+             // say it's a class file
+             cc->set_java_mode (NTXT ("on"));
+             return EXEC_IS_CLASS;
+           }
+         return EXEC_NOT_FOUND;
+       }
+      snprintf (target_path, sizeof (target_path), NTXT ("%s"), exe_name);
+      delete exe_name;
+    }
+
+  // target_path is now the purported executable
+  // check for ELF library out of date
+  if (Elf::elf_version (EV_CURRENT) == EV_NONE)
+    return EXEC_ELF_LIB;
+  Elf *elf = Elf::elf_begin (target_path);
+  if (elf == NULL)
+    return EXEC_OK;
+  // do not by pass checking architectural match
+  collect::Exec_status exec_stat = check_executable_arch (elf);
+  if (exec_stat != EXEC_OK)
+    {
+      delete elf;
+      return exec_stat;
+    }
+  delete elf;
+  return EXEC_OK;
+}
+
+collect::Exec_status
+collect::check_executable_arch (Elf *elf)
+{
+  Elf_Internal_Ehdr *ehdrp = elf->elf_getehdr ();
+  if (ehdrp == NULL)
+    return EXEC_ELF_HEADER;
+  unsigned short machine = ehdrp->e_machine;
+
+  switch (machine)
+    {
+#if ARCH(SPARC)
+    case EM_SPARC:
+    case EM_SPARC32PLUS:
+      break;
+    case EM_SPARCV9:
+      is_64 = true;
+      break;
+#elif ARCH(Intel)
+    case EM_X86_64:
+      {
+       is_64 = true;
+       // now figure out if the platform can run it
+       struct utsname unbuf;
+       int r = uname (&unbuf);
+       if (r == 0 && unbuf.machine && strstr (unbuf.machine, "_64") == NULL)
+         // machine can not run 64 bits, but this code is 64-bit
+         return EXEC_ELF_ARCH;
+      }
+      break;
+    case EM_386:
+      break;
+#elif ARCH(Aarch64)
+    case EM_AARCH64:
+      is_64 = true;
+      break;
+#endif
+    default:
+      return EXEC_ELF_ARCH;
+    }
+
+  // now check if target was built with shared libraries
+  int dynamic = 0;
+  for (unsigned cnt = 0; cnt < ehdrp->e_phnum; cnt++)
+    {
+      Elf_Internal_Phdr *phdrp = elf->get_phdr (cnt);
+      if (phdrp && phdrp->p_type == PT_DYNAMIC)
+       {
+         dynamic = 1;
+         break;
+       }
+    }
+  if (dynamic == 0)
+    {
+      // target is not a dynamic executable or shared object;
+      // can't record data
+      return EXEC_ELF_NOSHARE;
+    }
+  return EXEC_OK;
+}
+
+char *
+collect::status_str (Exec_status rv, char *target_name)
+{
+  switch (rv)
+    {
+    case EXEC_OK:
+    case EXEC_IS_JAR:
+    case EXEC_IS_CLASS:
+    case EXEC_IS_CLASSCLASS:
+      // supported flavors -- no error message
+      return NULL;
+    case EXEC_ELF_NOSHARE:
+      return dbe_sprintf (GTXT ("Target executable `%s' must be built with shared libraries\n"), target_name);
+    case EXEC_OPEN_FAIL:
+      return dbe_sprintf (GTXT ("Can't open target executable `%s'\n"), target_name);
+    case EXEC_ELF_LIB:
+      return strdup (GTXT ("Internal error: Not a working version of ELF library\n"));
+    case EXEC_ELF_HEADER:
+      return dbe_sprintf (GTXT ("Target `%s' is not a valid ELF executable\n"), target_name);
+    case EXEC_ELF_ARCH:
+      return dbe_sprintf (GTXT ("Target architecture of executable `%s' is not supported on this machine\n"), target_name);
+    case EXEC_ISDIR:
+      return dbe_sprintf (GTXT ("Target `%s' is a directory, not an executable\n"), target_name);
+    case EXEC_NOT_EXEC:
+      return dbe_sprintf (GTXT ("Target `%s' is not executable\n"), target_name);
+    case EXEC_NOT_FOUND:
+      return dbe_sprintf (GTXT ("Target `%s' not found\n"), target_name);
+    }
+  return NULL;
+}
+
+char *
+collect::find_java (void)
+{
+  char buf[MAXPATHLEN];
+  char *var = NULL;
+  Exec_status rv = EXEC_OK;
+
+  // first see if the user entered a -j argument
+  var = cc->get_java_path ();
+  if (var != NULL)
+    {
+      snprintf (buf, sizeof (buf), NTXT ("%s/bin/java"), var);
+      java_how = NTXT ("-j");
+      rv = check_executable (buf);
+    }
+  // then try JDK_HOME
+  if (java_how == NULL)
+    {
+      var = getenv (NTXT ("JDK_HOME"));
+      if ((var != NULL) && (strlen (var) > 0))
+       {
+         snprintf (buf, sizeof (buf), NTXT ("%s/bin/java"), var);
+         java_how = NTXT ("JDK_HOME");
+         rv = check_executable (buf);
+       }
+    }
+  // then try JAVA_PATH
+  if (java_how == NULL)
+    {
+      var = getenv (NTXT ("JAVA_PATH"));
+      if ((var != NULL) && (strlen (var) > 0))
+       {
+         snprintf (buf, sizeof (buf), NTXT ("%s/bin/java"), var);
+         java_how = NTXT ("JAVA_PATH");
+         rv = check_executable (buf);
+       }
+    }
+  // try the user's path
+  if (java_how == NULL)
+    {
+      snprintf (buf, sizeof (buf), NTXT ("java"));
+      rv = check_executable (buf);
+      if (rv == EXEC_OK)
+       java_how = NTXT ("PATH");
+    }
+  // finally, just try /usr/java -- system default
+  if (java_how == NULL)
+    {
+      snprintf (buf, sizeof (buf), NTXT ("/usr/java/bin/java"));
+      rv = check_executable (buf);
+      java_how = NTXT ("/usr/java/bin/java");
+    }
+
+  // we now have a nominal path to java, and how we chose it
+  // and we have rv set to the check_executable return
+  switch (rv)
+    {
+    case EXEC_OK:
+      java_path = strdup (buf);
+      if (verbose == 1)
+       dbe_write (2, GTXT ("Path to `%s' (set from %s) used for Java profiling\n"),
+                  java_path, java_how);
+      return ( strdup (buf));
+    default:
+      dbe_write (2, GTXT ("Path to `%s' (set from %s) does not point to a JVM executable\n"),
+                buf, java_how);
+      break;
+    }
+  return NULL;
+}
+
+void
+collect::validate_config (int how)
+{
+  if (getenv (NTXT ("GPROFNG_SKIP_VALIDATION")) != NULL)
+    return;
+  char *cmd = dbe_sprintf (NTXT ("%s/perftools_validate"), run_dir);
+  if (access (cmd, X_OK) != 0)
+    {
+      if (how)
+       dbe_write (2, GTXT ("WARNING: Unable to validate system: `%s' could not be executed\n"), cmd);
+      return;
+    }
+  char *quiet = how == 0 ? NTXT ("") : NTXT ("-q"); // check collection, verbosely
+  char *buf;
+  if (cc->get_java_default () == 0 && java_path)
+    buf = dbe_sprintf (NTXT ("%s -c -j %s -H \"%s\" %s"), cmd, java_path, java_how, quiet);
+  else  // not java mode -- don't check the java version
+    buf = dbe_sprintf (NTXT ("%s -c %s"), cmd, quiet);
+  free (cmd);
+
+  /* now run the command */
+  int ret = system (buf);
+  int status = WEXITSTATUS (ret);
+  if ((status & 0x1) != 0)
+    dbe_write (2, GTXT ("WARNING: Data collection may fail: system is not properly configured or is unsupported.\n"));
+  if ((status & 0x2) != 0)
+    dbe_write (2, GTXT ("WARNING: Java data collection may fail: J2SE[tm] version is unsupported.\n"));
+  free (buf);
+}
+
+void
+collect::validate_java (const char *jvm, const char *jhow, int q)
+{
+  char *cmd = dbe_sprintf (NTXT ("%s/perftools_ckjava"), run_dir);
+  if (access (cmd, X_OK) != 0)
+    {
+      dbe_write (2, GTXT ("WARNING: Unable to validate Java: `%s' could not be executed\n"), cmd);
+      return;
+    }
+  char *buf = dbe_sprintf (NTXT ("%s -j %s -H \"%s\" %s"), cmd, jvm, jhow,
+                          (q == 1 ? "-q" : ""));
+  free (cmd);
+
+  /* now run the command */
+  int ret = system (buf);
+  int status = WEXITSTATUS (ret);
+  if (status != 0)
+    dbe_write (2, GTXT ("WARNING: Java data collection may fail: J2SE[tm] version is unsupported.\n"));
+  free (buf);
+}
diff --git a/gprofng/src/collctrl.cc b/gprofng/src/collctrl.cc
new file mode 100644 (file)
index 0000000..48c65ff
--- /dev/null
@@ -0,0 +1,3149 @@
+/* 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 <unistd.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <libgen.h>
+#include <assert.h>
+#include <regex.h>  /* regcomp() */
+
+#include "util.h"
+#include "libiberty.h"
+#include "collctrl.h"
+#include "hwcdrv.h"
+//#include "hwcfuncs.h"
+
+#define SP_GROUP_HEADER     "#analyzer experiment group"
+#define DD_MAXPATHLEN       (MAXPATHLEN * 4) /* large, to build up data descriptor */
+
+/* If the system doesn't provide strsignal, we get it defined in
+   libiberty but no declaration is supplied.   */
+#if !defined (HAVE_STRSIGNAL) && !defined (strsignal)
+extern const char *strsignal (int);
+#endif
+
+// _SC_CPUID_MAX is not available on 2.6/2.7
+#ifndef _SC_CPUID_MAX
+#define _SC_CPUID_MAX       517
+#endif
+
+const char *get_fstype (char *);
+
+Coll_Ctrl::Coll_Ctrl (int _interactive, bool _defHWC, bool _kernelHWC)
+{
+  char hostname[MAXPATHLEN];
+  long ncpumax;
+  interactive = _interactive;
+  defHWC = _defHWC;
+  kernelHWC = _kernelHWC;
+
+  /* set this host's parameters */
+  gethostname (hostname, 1023);
+  node_name = strdup (hostname);
+  char *p = strchr (node_name, (int) '.');
+  if (p != NULL)
+    *p = 0;
+  default_stem = strdup ("test");
+
+  /* get CPU count and processor clock rate */
+  ncpumax = sysconf (_SC_CPUID_MAX);
+  if (ncpumax == -1)
+    {
+      ncpus = sysconf (_SC_NPROCESSORS_CONF);
+      /* add 2048 to count, since on some systems CPUID does not start at zero */
+      ncpumax = ncpus + 2048;
+    }
+  ncpus = 0;
+  cpu_clk_freq = 0;
+
+  // On Linux, read /proc/cpuinfo to get CPU count and clock rate
+  // Note that parsing is different on SPARC and x86
+#if defined(sparc)
+  FILE *procf = fopen ("/proc/cpuinfo", "r");
+  if (procf != NULL)
+    {
+      char temp[1024];
+      while (fgets (temp, (int) sizeof (temp), procf) != NULL)
+       {
+         if (strncmp (temp, "Cpu", 3) == 0 && temp[3] != '\0'
+             && strncmp ((strchr (temp + 1, 'C')) ? strchr (temp + 1, 'C')
+                         : (temp + 4), "ClkTck", 6) == 0)
+           {
+             ncpus++;
+             char *val = strchr (temp, ':');
+             if (val)
+               {
+                 unsigned long long freq;
+                 sscanf (val + 2, "%llx", &freq);
+                 cpu_clk_freq = (unsigned int) (((double) freq) / 1000000.0 + 0.5);
+               }
+             else
+               cpu_clk_freq = 0;
+           }
+       }
+      fclose (procf);
+    }
+
+#elif defined(__aarch64__)
+  asm volatile("mrs %0, cntfrq_el0" : "=r" (cpu_clk_freq));
+  dbe_write (2, GTXT ("CPU clock frequency: %d\n"), cpu_clk_freq);
+
+#else
+  FILE *procf = fopen ("/proc/cpuinfo", "r");
+  if (procf != NULL)
+    {
+      char temp[1024];
+      while (fgets (temp, (int) sizeof (temp), procf) != NULL)
+       {
+         // x86 Linux
+         if (strncmp (temp, "processor", 9) == 0)
+           ncpus++;
+         else if (strncmp (temp, "cpu MHz", 7) == 0)
+           {
+             char *val = strchr (temp, ':');
+             cpu_clk_freq = val ? atoi (val + 1) : 0;
+           }
+       }
+      fclose (procf);
+    }
+#endif
+
+  /* check resolution of system clock */
+  sys_resolution = sysconf (_SC_CLK_TCK);
+  if (sys_resolution == 0)
+    sys_period = 10000;
+  else
+    sys_period = MICROSEC / (int) sys_resolution;
+
+  /* determine memory page size and number of pages */
+  npages = sysconf (_SC_PHYS_PAGES);
+  page_size = sysconf (_SC_PAGE_SIZE);
+
+  /* set default clock parameters */
+  hwcprof_enabled_cnt = 0; // must be set before calling determine_profile_params();
+  determine_profile_params (); // inits clk_params which is used by clock profiling AND HWCs
+  cpc_cpuver = CPUVER_UNDEFINED;
+
+  /* set default control values */
+  debug_mode = 0;
+#if defined(GPROFNG_JAVA_PROFILING)
+  java_mode = 1;
+#else
+  java_mode = 0;
+#endif
+  java_default = 1;
+  java_path = NULL;
+  java_args = NULL;
+  njava_args = 0;
+  follow_mode = FOLLOW_ON;
+  follow_default = 1;
+  follow_spec_usr = NULL;
+  follow_spec_cmp = NULL;
+  prof_idle = 1;
+  archive_mode = strdup ("on");
+  pauseresume_sig = 0;
+  sample_sig = 0;
+  uinterrupt = 0;
+  attach_pid = 0;
+  time_run = 0;
+  start_delay = 0;
+
+  /* clear the string pointers */
+  uexpt_name = NULL;
+  expt_name = NULL;
+  expt_dir = NULL;
+  base_name = NULL;
+  udir_name = NULL;
+  store_dir = NULL;
+  prev_store_dir = strdup ("");
+  store_ptr = NULL;
+  expt_group = NULL;
+  target_name = NULL;
+  data_desc = NULL;
+  lockname = NULL;
+  hwc_string = NULL;
+  project_home = NULL;
+  lockfd = -1;
+
+  /* set default data collection values */
+  enabled = 0;
+  opened = 0;
+  clkprof_enabled = 1;
+  clkprof_default = 1;
+  for (unsigned ii = 0; ii < MAX_PICS; ii++)
+    {
+      memset (&hwctr[ii], 0, sizeof (Hwcentry));
+      hwctr[ii].reg_num = -1;
+    }
+  hwcprof_default = 0;
+  if (defHWC == true)
+    {
+      setup_hwc ();
+      hwcprof_default = 1;
+    }
+  else  // disable the default, and reset the counters
+    hwcprof_enabled_cnt = 0;
+  synctrace_enabled = 0;
+  synctrace_thresh = -1;
+  synctrace_scope = 0;
+  heaptrace_enabled = 0;
+  heaptrace_checkenabled = 0;
+  iotrace_enabled = 0;
+  count_enabled = 0;
+  Iflag = 0;
+  Nflag = 0;
+  sample_period = 1;
+  sample_default = 1;
+  size_limit = 0;
+  nofswarn = 0;
+  expno = 1;
+
+  // ensure that the default name is updated
+  // but don't print any message
+  (void) preprocess_names ();
+  (void) update_expt_name (false, false);
+}
+
+/* Copy constructor */
+Coll_Ctrl::Coll_Ctrl (Coll_Ctrl * cc)
+{
+  uinterrupt = 0;
+  interactive = cc->interactive;
+  defHWC = cc->defHWC;
+  kernelHWC = cc->kernelHWC;
+  node_name = strdup (cc->node_name);
+  default_stem = strdup (cc->default_stem);
+  ncpus = cc->ncpus;
+  cpu_clk_freq = cc->cpu_clk_freq;
+  npages = cc->npages;
+  page_size = cc->page_size;
+  cpc_cpuver = cc->cpc_cpuver;
+  debug_mode = cc->debug_mode;
+  java_mode = cc->java_mode;
+  java_default = cc->java_default;
+  java_path = NULL;
+  java_args = NULL;
+  njava_args = 0;
+  follow_mode = cc->follow_mode;
+  follow_default = cc->follow_default;
+  if (cc->follow_spec_usr)
+    {
+      follow_spec_usr = strdup (cc->follow_spec_usr);
+      follow_spec_cmp = strdup (cc->follow_spec_cmp);
+    }
+  else
+    {
+      follow_spec_usr = NULL;
+      follow_spec_cmp = NULL;
+    }
+  archive_mode = strdup (cc->archive_mode);
+  pauseresume_sig = cc->pauseresume_sig;
+  sample_sig = cc->sample_sig;
+  time_run = cc->time_run;
+  start_delay = cc->start_delay;
+  clk_params = cc->clk_params;
+  clkprof_enabled = cc->clkprof_enabled;
+  clkprof_default = cc->clkprof_default;
+  clkprof_timer = cc->clkprof_timer;
+  clkprof_timer_target = cc->clkprof_timer_target;
+
+  // copy HW counter information
+  hwcprof_default = cc->hwcprof_default;
+  hwcprof_enabled_cnt = cc->hwcprof_enabled_cnt;
+  if (cc->hwc_string != NULL)
+    hwc_string = strdup (cc->hwc_string);
+  else
+    hwc_string = NULL;
+  for (int i = 0; i < hwcprof_enabled_cnt; i++)
+    hwcentry_dup (&hwctr[i], &(cc->hwctr[i]));
+  project_home = cc->project_home ? strdup (cc->project_home) : NULL;
+  synctrace_enabled = cc->synctrace_enabled;
+  synctrace_thresh = cc->synctrace_thresh;
+  synctrace_scope = cc->synctrace_scope;
+  heaptrace_enabled = cc->heaptrace_enabled;
+  heaptrace_checkenabled = cc->heaptrace_checkenabled;
+  iotrace_enabled = cc->iotrace_enabled;
+  count_enabled = cc->count_enabled;
+  Iflag = cc->Iflag;
+  Nflag = cc->Nflag;
+  sample_period = cc->sample_period;
+  sample_default = cc->sample_default;
+  size_limit = cc->size_limit;
+  nofswarn = cc->nofswarn;
+
+  // these will get reset during preprocess_names()
+  expt_name = NULL;
+  expt_dir = NULL;
+  store_dir = NULL;
+  base_name = NULL;
+  expno = 1;
+
+  // these represent user settings
+  expt_group = NULL;
+  if (cc->expt_group != NULL)
+    expt_group = strdup (cc->expt_group);
+  uexpt_name = NULL;
+  if (cc->uexpt_name != NULL)
+    uexpt_name = strdup (cc->uexpt_name);
+  udir_name = NULL;
+  if (cc->udir_name != NULL)
+    udir_name = strdup (cc->udir_name);
+
+  /* clear the string pointers */
+  prev_store_dir = strdup ("");
+  store_ptr = NULL;
+  target_name = NULL;
+  data_desc = NULL;
+  lockname = NULL;
+  lockfd = -1;
+
+  /* set default data collection values */
+  enabled = cc->enabled;
+  opened = 0;
+  nofswarn = cc->nofswarn;
+  sys_resolution = cc->sys_resolution;
+  sys_period = cc->sys_period;
+
+  // ensure that the default name is updated
+  (void) preprocess_names ();
+  (void) update_expt_name (false, false);
+  build_data_desc ();
+}
+
+Coll_Ctrl::~Coll_Ctrl ()
+{
+  free (node_name);
+  free (expt_name);
+  free (expt_dir);
+  free (base_name);
+  free (udir_name);
+  free (store_dir);
+  free (store_ptr);
+  free (expt_group);
+  free (target_name);
+  free (data_desc);
+  free (lockname);
+  free (hwc_string);
+  free (project_home);
+  free (java_path);
+  hwcprof_enabled_cnt = 0;
+}
+
+/* set up the experiment */
+char *
+Coll_Ctrl::setup_experiment ()
+{
+  char *ret;
+  if (enabled == 0)
+    return NULL;
+  build_data_desc ();
+
+  /* create the experiment directory */
+  ret = create_exp_dir ();
+  if (ret != NULL)
+    return ret;
+
+  /* if an experiment-group, join it */
+  ret = join_group ();
+  if (ret != NULL)
+    {
+      remove_exp_dir ();
+      return ret;
+    }
+  /* all is OK, return 0 */
+  opened = 1;
+  return NULL;
+}
+
+void
+Coll_Ctrl::interrupt ()
+{
+  uinterrupt = 1;
+}
+
+char *
+Coll_Ctrl::enable_expt ()
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (cpu_clk_freq == 0)
+    return strdup (GTXT ("Can not determine CPU clock frequency.\n"));
+  if (sys_resolution == 0)
+    return strdup (GTXT ("System clock profile resolution can not be determined.\n"));
+  enabled = 1;
+  return NULL;
+}
+
+/* close the experiment */
+void
+Coll_Ctrl::close_expt ()
+{
+  opened = 0;
+  (void) update_expt_name (false, false);
+}
+
+/* close and delete the experiment */
+void
+Coll_Ctrl::delete_expt ()
+{
+  if (opened == 0)
+    return;
+  remove_exp_dir ();
+
+  /* The order of removing the directory and closing
+   * the experiment may seem unnatural, but it's not.
+   * We do need to update names when we close the experiment
+   * (actually Coll_Ctrl object) and we can't remove anything
+   * after that.
+   */
+  close_expt ();
+}
+
+// Check the experiment settings for consistency.  Returns NULL if OK,
+//     or an error message if there are invalid combinations of settings
+char *
+Coll_Ctrl::check_consistency ()
+{
+  /* check for Java arguments, but not Java profiling */
+  if (java_args != NULL && java_mode == 0)
+    return strdup (GTXT ("Java arguments can not be set if Java profiling is not enabled.\n"));
+
+  /* if count data, no other data is allowed */
+  if (count_enabled != 0
+      && ((clkprof_default != 1 && clkprof_enabled != 0)
+         || hwcprof_enabled_cnt != 0 || synctrace_enabled != 0
+         || heaptrace_enabled != 0 || iotrace_enabled != 0))
+    return strdup (GTXT ("Count data cannot be collected along with any other data.\n"));
+
+  /* if count data, various other options are not allowed */
+  if (count_enabled != 0
+      && ((java_mode != 0 && java_default != 1)
+         || java_args != NULL || debug_mode != 0
+         || (follow_mode != 0 && follow_default != 1)
+         || pauseresume_sig != 0 || sample_sig != 0
+         || (sample_default != 1 && sample_period != 0) || time_run != 0))
+    return strdup (GTXT ("Count data cannot be collected with any of -F -S -y -l -j -J -x -t .\n"));
+  /* if not count data, I and N options are not allowed */
+  if (count_enabled == 0 && (Iflag != 0 || Nflag != 0))
+    return strdup (GTXT ("-I or -N can only be specified with count data.\n"));
+  return NULL;
+}
+
+char *
+Coll_Ctrl::check_expt (char **warn)
+{
+  char *ret;
+  *warn = NULL;
+  ret = check_consistency ();
+  if (ret != NULL)      /* something is wrong, return the error */
+    return ret;
+  /* check for heaptrace and java -- warn that it covers native allocations only */
+  if (heaptrace_enabled == 1 && java_mode == 1 && java_default == 0)
+    *warn = strdup (GTXT ("Note: Heap profiling will only trace native allocations, not Java allocations.\n"));
+
+  /* if no profiling data selected, warn the user */
+  if (clkprof_enabled == 0 && hwcprof_enabled_cnt == 0 && synctrace_enabled == 0
+      && heaptrace_enabled == 0 && iotrace_enabled == 0 && count_enabled == 0)
+    *warn = strdup (GTXT ("Warning: No function level data requested; only statistics will be collected.\n\n"));
+  build_data_desc ();
+
+  /* verify that the directory exists */
+  struct stat statbuf;
+  if (stat (store_dir, &statbuf) != 0)
+    return dbe_sprintf (GTXT ("Store directory %s is not accessible: %s\n"),
+                       store_dir, strerror (errno));
+  if (access (store_dir, W_OK) != 0)
+    return dbe_sprintf (GTXT ("Store directory %s is not writeable: %s\n"),
+               store_dir, strerror (errno));
+
+  /* if an experiment-group, verify that it can be written */
+  ret = check_group ();
+  if (ret != NULL)
+    return ret;
+  return NULL;
+}
+
+char *
+Coll_Ctrl::show (int i)
+{
+  char UEbuf[4096];
+  UEbuf[0] = 0;
+  if (i == 0)
+    {
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("Collection parameters:\n"));
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("    experiment enabled\n"));
+    }
+  if (target_name != NULL)
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             GTXT ("\ttarget = %s\n"), target_name);
+  if (uexpt_name != NULL)
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             GTXT ("\tuser_expt_name = %s\n"), uexpt_name);
+  snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+           GTXT ("\texpt_name = %s\n"),
+           ((expt_name != NULL) ? expt_name : NTXT ("<NULL>")));
+  if (udir_name != NULL)
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             GTXT ("\tdir_name = %s\n"), udir_name);
+  if (expt_group != NULL)
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             GTXT ("\texpt_group = %s\n"), expt_group);
+  if (debug_mode == 1)
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             GTXT ("\tdebug_mode enabled\n"));
+  if (clkprof_enabled != 0)
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             GTXT ("\tclock profiling enabled, %.3f millisec.\n"),
+             (double) (clkprof_timer) / 1000.);
+  if (synctrace_enabled != 0)
+    {
+      if (synctrace_thresh < 0)
+       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                 GTXT ("\tsynchronization tracing enabled, threshold: calibrate; "));
+      else if (synctrace_thresh == 0)
+       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                 GTXT ("\tsynchronization tracing enabled, threshold: all; "));
+      else
+       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                 GTXT ("\tsynchronization tracing enabled, threshold: %d micros.; "), synctrace_thresh);
+      switch (synctrace_scope)
+       {
+       case SYNCSCOPE_NATIVE:
+         snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                   GTXT ("Native-APIs\n"));
+         break;
+       case SYNCSCOPE_JAVA:
+         snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                   GTXT ("Java-APIs\n"));
+         break;
+       case SYNCSCOPE_NATIVE | SYNCSCOPE_JAVA:
+         snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                   GTXT ("Native- and Java-APIs\n"));
+         break;
+       default:
+         snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                   GTXT ("ERR -- unexpected synctrace_scope %d\n"), synctrace_scope);
+         break;
+       }
+    }
+  if (hwcprof_enabled_cnt != 0)
+    {
+      char ctrbuf[MAXPATHLEN];
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("\thardware counter profiling%s enabled:\n"),
+               (hwcprof_default == 1 ? GTXT (" (default)") : ""));
+      for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
+       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                 GTXT ("\t  %u. %s\n"), ii + 1,
+                 hwc_hwcentry_specd_string (ctrbuf, MAXPATHLEN, &hwctr[ii]));
+    }
+  if (heaptrace_enabled != 0)
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             GTXT ("\theap tracing enabled, %s\n"),
+             (heaptrace_checkenabled == 0 ? GTXT ("no checking") :
+              (heaptrace_checkenabled == 1 ? GTXT ("over/underrun checking") :
+               GTXT ("over/underrun checking and pattern storing"))));
+  if (iotrace_enabled != 0)
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             GTXT ("\tI/O tracing enabled\n"));
+  switch (count_enabled)
+    {
+    case 0:
+      break;
+    case 1:
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("\tcount data enabled\n"));
+      break;
+    case -1:
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("\tstatic count data will be generated (for a.out only)\n"));
+      break;
+    }
+  switch (follow_mode)
+    {
+    case FOLLOW_ON:
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("\tdescendant processes will be followed\n"));
+      break;
+    case FOLLOW_ALL:
+      if (follow_spec_usr && follow_spec_cmp)
+       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                 GTXT ("\texperiments will be recorded for descendant processes that match pattern '%s'\n"),
+                 follow_spec_usr);
+      else
+       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                 GTXT ("\tdescendant processes will all be followed\n"));
+      break;
+    case FOLLOW_NONE:
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("\tdescendant processes will not be followed\n"));
+      break;
+    default:
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("\tfollowing descendant processes: <UNKNOWN>\n"));
+      break;
+    }
+  if (java_mode == 0)
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             GTXT ("\tjava profiling disabled\n"));
+  if (pauseresume_sig != 0)
+    {
+      const char *buf = strsignal (pauseresume_sig);
+      if (buf != NULL)
+       {
+         if (pauseresume_pause == 1)
+           snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                     GTXT ("\tpause-resume (delayed initialization) signal %s (%d) -- paused\n"), buf, pauseresume_sig);
+         else
+           snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                     GTXT ("\tpause-resume (delayed initialization) signal %s (%d)\n"), buf, pauseresume_sig);
+       }
+      else
+       {
+         if (pauseresume_pause == 1)
+           snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                     GTXT ("\tpause-resume (delayed initialization) signal %d -- paused\n"), pauseresume_sig);
+         else
+           snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                     GTXT ("\tpause-resume (delayed initialization) signal %d\n"), pauseresume_sig);
+       }
+    }
+  if (sample_sig != 0)
+    {
+      const char *buf = strsignal (sample_sig);
+      if (buf != NULL)
+       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                 GTXT ("\tsample signal %s (%d)\n"), buf, sample_sig);
+      else
+       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                 GTXT ("\tsample signal %d\n"), sample_sig);
+    }
+  if (time_run != 0 || start_delay != 0)
+    {
+      if (start_delay != 0)
+       {
+         if (time_run != 0)
+           snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                     GTXT ("\tdata-collection duration, %d-%d secs.\n"), start_delay, time_run);
+         else
+           snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                     GTXT ("\tdata-collection duration, %d- secs.\n"), start_delay);
+       }
+      else
+       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                 GTXT ("\tdata-collection duration, %d secs.\n"), time_run);
+    }
+  if (sample_period != 0)
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             GTXT ("\tperiodic sampling, %d secs.\n"), sample_period);
+  else
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             GTXT ("\tno periodic sampling\n"));
+  if (size_limit != 0)
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             GTXT ("\texperiment size limit %d MB.\n"), size_limit);
+  else
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             GTXT ("\tno experiment size limit set\n"));
+  snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+           GTXT ("\texperiment archiving: -a %s\n"), archive_mode);
+  snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+           GTXT ("\tdata descriptor: \"%s\"\n"),
+           ((data_desc != NULL) ? data_desc : NTXT ("<NULL>")));
+#if 0
+  snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+           GTXT ("\t expt_dir: %s\n"),
+           ((expt_dir != NULL) ? expt_dir : NTXT ("<NULL>")));
+  snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+           GTXT ("\t base_name: %s\n"),
+           ((base_name != NULL) ? base_name : NTXT ("<NULL>")));
+  snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+           GTXT ("\t store_dir: %s\n"),
+           ((store_dir != NULL) ? store_dir : NTXT ("<NULL>")));
+  snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+           GTXT ("\t store_ptr: %s\n"),
+           ((store_ptr != NULL) ? store_ptr : NTXT ("<NULL>")));
+#endif
+  snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+           GTXT ("\t\thost: `%s', ncpus = %d, clock frequency %d MHz.\n"),
+           ((node_name != NULL) ? node_name : NTXT ("<NULL>")),
+           (int) ncpus, (int) cpu_clk_freq);
+  if (npages > 0)
+    {
+      long long memsize = ((long long) npages * (long long) page_size) / (1024 * 1024);
+      snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+               GTXT ("\t\tmemory:  %ld pages @ %ld bytes = %lld MB.\n"),
+               npages, page_size, memsize);
+    }
+  return strdup (UEbuf);
+}
+
+#define MAX_COLLECT_ARGS    100
+
+char **
+Coll_Ctrl::get_collect_args ()
+{
+  char buf[DD_MAXPATHLEN];
+  char **p;
+  char **argv = (char **) calloc (MAX_COLLECT_ARGS, sizeof (char *));
+  if (argv == NULL)     // poor way of dealing with calloc failure
+    abort ();
+  p = argv;
+  *p++ = strdup ("collect");
+  if (debug_mode == 1)
+    *p++ = strdup ("-x");
+  if (clkprof_enabled != 0)
+    {
+      *p++ = strdup ("-p");
+      snprintf (buf, sizeof (buf), "%du", clkprof_timer);
+      *p++ = strdup (buf);
+    }
+  if (hwcprof_enabled_cnt > 0)
+    {
+      *buf = 0;
+      *p++ = strdup ("-h");
+      for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
+       {
+         char*rateString = hwc_rate_string (&hwctr[ii], 1); //"1" is for temporary goldfile compatibility. TBR YXXX!!
+         snprintf (buf + strlen (buf), sizeof (buf) - strlen (buf),
+                   "%s%s,%s%s", ii ? "," : "", hwctr[ii].name,
+                   rateString ? rateString : "",
+                   (ii + 1 < hwcprof_enabled_cnt) ? "," : "");
+         free (rateString);
+       }
+      if (strlen (buf) + 1 >= sizeof (buf))
+       abort ();
+      *p++ = strdup (buf);
+    }
+  if (heaptrace_enabled != 0)
+    {
+      *p++ = strdup ("-H");
+      *p++ = strdup ("on");
+    }
+  if (iotrace_enabled != 0)
+    {
+      *p++ = strdup ("-i");
+      *p++ = strdup ("on");
+    }
+  if (synctrace_enabled != 0)
+    {
+      *p++ = strdup ("-s");
+      if (synctrace_thresh < 0)
+       *p++ = strdup ("calibrate");
+      else if (synctrace_thresh < 0)
+       *p++ = strdup ("all");
+      else
+       *p++ = dbe_sprintf ("%d", synctrace_thresh);
+      *p++ = dbe_sprintf (",%d", synctrace_scope);
+    }
+  if (follow_mode != 0)
+    {
+      *p++ = strdup ("-F");
+      char * fs = get_follow_usr_spec ();
+      if (fs)
+       *p++ = strdup (fs);
+      else
+       {
+         switch (get_follow_mode ())
+           {
+           case FOLLOW_ON:
+             *p++ = strdup ("on");
+             break;
+           case FOLLOW_ALL:
+             *p++ = strdup ("all");
+             break;
+           case FOLLOW_NONE:
+           default:
+             *p++ = strdup ("off");
+             break;
+           }
+       }
+    }
+  *p++ = strdup ("-a");
+  *p++ = strdup (get_archive_mode ());
+  if (java_mode != 0)
+    {
+      *p++ = strdup ("-j");
+      *p++ = strdup ("on");
+    }
+  if (pauseresume_sig != 0)
+    {
+      *p++ = strdup ("-y");
+      *p++ = dbe_sprintf ("%d%s", pauseresume_sig,
+                         (pauseresume_pause == 0 ? ",r" : ""));
+    }
+  if (sample_sig != 0)
+    {
+      *p++ = strdup ("-l");
+      *p++ = dbe_sprintf ("%d", sample_sig);
+    }
+  if (sample_period != 0)
+    {
+      *p++ = strdup ("-S");
+      *p++ = dbe_sprintf ("%d", sample_period);
+    }
+  if (size_limit != 0)
+    {
+      *p++ = strdup ("-L");
+      *p++ = dbe_sprintf ("%d", size_limit);
+    }
+  if (expt_group != NULL)
+    {
+      *p++ = strdup ("-g");
+      *p++ = strdup (expt_group);
+    }
+  if (udir_name != 0)
+    {
+      *p++ = strdup ("-d");
+      *p++ = strdup (udir_name);
+    }
+  if (expt_name != 0)
+    {
+      *p++ = strdup ("-o");
+      *p++ = strdup (expt_name);
+    }
+  if (p - argv >= MAX_COLLECT_ARGS) // argument list too small -- fatal error
+    abort ();
+  return argv;
+}
+
+char *
+Coll_Ctrl::show_expt ()
+{
+  if (enabled == 0)
+    return NULL;
+  char UEbuf[4096];
+  UEbuf[0] = 0;
+  snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+           GTXT ("Creating experiment directory %s (Process ID: %ld) ...\n"),
+           ((store_ptr != NULL) ? store_ptr : NTXT ("<NULL>")), (long) getpid ());
+  char *caller = getenv ("SP_COLLECTOR_FROM_GUI"); // Collector from GUI
+  if (caller != NULL)   // Print non-localized message
+    snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+             NTXT ("\nCreating experiment directory %s (Process ID: %ld) ...\n"),
+             ((store_ptr != NULL) ? store_ptr : NTXT ("<NULL>")), (long) getpid ());
+#if 0
+  char *fstype = get_fstype (store_dir);
+  if ((fstype != NULL) && (nofswarn == 0))
+    {
+      // only warn if clock or hwc profiling is turned on
+      if (clkprof_enabled || hwcprof_enabled_cnt != 0)
+       snprintf (UEbuf + strlen (UEbuf), sizeof (UEbuf) - strlen (UEbuf),
+                 GTXT ("this experiment is being recorded to a file system \nof type \"%s\", which may distort the measured performance."),
+                 fstype);
+    }
+#endif
+  return strdup (UEbuf);
+}
+
+void
+Coll_Ctrl::set_clk_params (int min, int res, int max, int hi, int norm, int lo)
+{
+  clk_params.min = min;
+  clk_params.res = res;
+  clk_params.max = max;
+  clk_params.hival = hi;
+  clk_params.normval = norm;
+  clk_params.lowval = lo;
+  set_clkprof_timer_target (clk_params.normval); // note: requires clk_params to be initialized!
+}
+
+char *
+Coll_Ctrl::reset_clkprof (int val)
+{
+  if (val != clkprof_timer)
+    {
+      // profiler has had to reset to a different value; warn user
+      char *msg = dbe_sprintf (
+             GTXT ("Warning: Clock profiling timer reset from %.3f millisec. to %.3f millisec. as required by profiling driver\n\n"),
+             (double) (clkprof_timer) / 1000., (double) (val) / 1000.);
+      adjust_clkprof_timer (val);
+      return msg;
+    }
+  return NULL;
+}
+
+char *
+Coll_Ctrl::set_clkprof (const char *string, char** warn)
+{
+  int ticks;
+  int nclkprof_timer;
+  int prevclkprof_enabled;
+  int prevclkprof_default;
+  *warn = NULL;
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  /* if the first character is a +, warn user that it is no longer supported */
+  if (string[0] == '+')
+    return strdup (GTXT ("Warning: clock-based memoryspace and dataspace profiling is no longer supported\n"));
+  if (strcmp (string, "off") == 0)
+    {
+      clkprof_enabled = 0;
+      clkprof_default = 0;
+      return NULL;
+    }
+  else if (string == NULL || strcmp (string, "on") == 0)
+    nclkprof_timer = clk_params.normval;
+  else if (strcmp (string, "lo") == 0 || strcmp (string, "low") == 0)
+    nclkprof_timer = clk_params.lowval;
+  else if (strcmp (string, "hi") == 0 || strcmp (string, "high") == 0
+          || strcmp (string, "h") == 0)
+    nclkprof_timer = clk_params.hival;
+  else
+    {
+      /* the remaining string should be a number > 0 */
+      char *endchar = NULL;
+      double dval = strtod (string, &endchar);
+      if (*endchar == 'm' || *endchar == 0) /* user specified milliseconds */
+       dval = dval * 1000.;
+      else if (*endchar == 'u')     /* user specified microseconds */
+       dval = dval;
+      else
+       return dbe_sprintf (GTXT ("Unrecognized clock-profiling interval `%s'\n"), string);
+      nclkprof_timer = (int) (dval + 0.5);
+    }
+  // we now have the proposed value; ensure it's within limits
+  if (nclkprof_timer <= 0)
+    return dbe_sprintf (GTXT ("Unrecognized clock-profiling interval `%s'\n"), string);
+
+  // Check consistency with experiment
+  prevclkprof_enabled = clkprof_enabled;
+  prevclkprof_default = clkprof_default;
+  clkprof_enabled = 1;
+  clkprof_default = 0;
+  char *ret = check_consistency ();
+  if (ret != NULL)
+    {
+      clkprof_default = prevclkprof_default;
+      clkprof_enabled = prevclkprof_enabled;
+      return ret;
+    }
+  int ref_nclkprof_timer = nclkprof_timer;
+
+  // check for minimum value
+  if (nclkprof_timer < clk_params.min)
+    {
+      /* value too small, use minimum value, with warning */
+      *warn = dbe_sprintf (
+               GTXT ("Warning: Clock profiling at %.3f millisec. interval is not supported on this system; minimum %.3f millisec. used\n"),
+               (double) (nclkprof_timer) / 1000., (double) (clk_params.min) / 1000.);
+      nclkprof_timer = clk_params.min;
+    }
+
+  // check for maximum value
+  if (nclkprof_timer > clk_params.max)
+    {
+      *warn = dbe_sprintf (
+               GTXT ("Clock profiling at %.3f millisec. interval is not supported on this system; maximum %.3f millisec. used\n"),
+               (double) (nclkprof_timer) / 1000., (double) (clk_params.max) / 1000.);
+      nclkprof_timer = clk_params.max;
+    }
+
+  /* see if setting is a multiple of the period */
+  if (nclkprof_timer > clk_params.res)
+    {
+      ticks = ((nclkprof_timer / clk_params.res) * clk_params.res);
+      if (ticks != nclkprof_timer)
+       {
+         /* no, we need to reset to a multiple */
+         *warn = dbe_sprintf (
+                   GTXT ("Clock profile interval rounded from %.3f to %.3f (system resolution = %.3f) millisec."),
+                   (double) (nclkprof_timer) / 1000., (double) (ticks) / 1000.,
+                   (double) (clk_params.res) / 1000.);
+         nclkprof_timer = ticks;
+       }
+    }
+
+  // limit reference "target" rate.  Target rate is also used for HWCS.
+  if (ref_nclkprof_timer > PROFINT_MAX)
+    ref_nclkprof_timer = PROFINT_MAX;
+  if (ref_nclkprof_timer < PROFINT_MIN)
+    ref_nclkprof_timer = PROFINT_MIN;
+  set_clkprof_timer_target (ref_nclkprof_timer);
+  adjust_clkprof_timer (nclkprof_timer);
+  return NULL;
+}
+
+char *
+Coll_Ctrl::set_synctrace (const char *string)
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  char *comma_p = NULL;
+  if (string == NULL)
+    {
+      /* no argument provided,  use default: calibrate and native */
+      synctrace_enabled = 1;
+      synctrace_thresh = -1;
+      synctrace_scope = SYNCSCOPE_NATIVE;
+      char *ret = check_consistency ();
+      if (ret != NULL)
+       {
+         synctrace_enabled = 0;
+         return ret;
+       }
+      return NULL;
+    }
+  char *val = strdup (string);
+  /* see if there's a comma in the string */
+  char *next = strchr (val, (int) ',');
+  if (next != NULL)
+    {
+      /* remember where the comma was */
+      comma_p = next;
+
+      /* set the scope based on the characters following the comma */
+      synctrace_scope = 0;
+      next++;
+      while (*next != 0)
+       {
+         if (*next == 'n')
+           synctrace_scope |= SYNCSCOPE_NATIVE;
+         else if (*next == 'j')
+           synctrace_scope |= SYNCSCOPE_JAVA;
+         else
+           return dbe_sprintf (GTXT ("Unrecognized synchronization tracing threshold `%s'\n"), string);
+         next++;
+       }
+      if (synctrace_scope == 0)
+       synctrace_scope = SYNCSCOPE_NATIVE;
+      /* clear the comma for the threshold determination */
+      *comma_p = 0;
+    }
+  else      /* no ",<scope>" -- default to native and Java */
+    synctrace_scope = SYNCSCOPE_NATIVE | SYNCSCOPE_JAVA;
+  if (!strlen (val) || !strcmp (val, "calibrate") || !strcmp (val, "on"))
+    {
+      /* use default: calibrate and native */
+      synctrace_enabled = 1;
+      synctrace_thresh = -1;
+      free (val);
+      char *ret = check_consistency ();
+      if (ret != NULL)
+       {
+         synctrace_enabled = 0;
+         return ret;
+       }
+      return NULL;
+    }
+  if (strcmp (val, "off") == 0)
+    {
+      synctrace_enabled = 0;
+      free (val);
+      return NULL;
+    }
+  if (strcmp (val, "all") == 0)
+    {
+      /* set to record all events */
+      synctrace_thresh = 0;
+      synctrace_enabled = 1;
+      char *ret = check_consistency ();
+      free (val);
+      if (ret != NULL)
+       {
+         synctrace_enabled = 0;
+         return ret;
+       }
+      return NULL;
+    }
+  /* the remaining string should be a number >= 0 */
+  char *endchar = NULL;
+  int tval = (int) strtol (val, &endchar, 0);
+  free (val);
+  if (*endchar != 0 || tval < 0)
+    {
+      /* invalid setting */
+      /* restore the comma, if it was zeroed out */
+      if (comma_p != NULL)
+       *comma_p = ',';
+      return dbe_sprintf (GTXT ("Unrecognized synchronization tracing threshold `%s'\n"), string);
+    }
+  synctrace_thresh = tval;
+  synctrace_enabled = 1;
+  return NULL;
+}
+
+char *
+Coll_Ctrl::set_heaptrace (const char *string)
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (string == NULL || strlen (string) == 0 || strcmp (string, "on") == 0)
+    {
+      heaptrace_enabled = 1;
+      char *ret = check_consistency ();
+      if (ret != NULL)
+       {
+         heaptrace_enabled = 0;
+         return ret;
+       }
+      return NULL;
+    }
+  if (strcmp (string, "off") == 0)
+    {
+      heaptrace_enabled = 0;
+      return NULL;
+    }
+#if 0
+  if (strcmp (string, "check") == 0)
+    {
+      /* set to check for over/underruns */
+      heaptrace_checkenabled = 1;
+      heaptrace_enabled = 1;
+      return NULL;
+    }
+  if (strcmp (string, "clear") == 0)
+    {
+      /* set to check for over/underruns, and store patterns */
+      heaptrace_checkenabled = 2;
+      heaptrace_enabled = 1;
+      return NULL;
+    }
+#endif
+  return dbe_sprintf (GTXT ("Unrecognized heap tracing parameter `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_iotrace (const char *string)
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (string == NULL || strlen (string) == 0 || strcmp (string, "on") == 0)
+    {
+      iotrace_enabled = 1;
+      char *ret = check_consistency ();
+      if (ret != NULL)
+       {
+         iotrace_enabled = 0;
+         return ret;
+       }
+      return NULL;
+    }
+  if (strcmp (string, "off") == 0)
+    {
+      iotrace_enabled = 0;
+      return NULL;
+    }
+  return dbe_sprintf (GTXT ("Unrecognized I/O tracing parameter `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_count (const char *string)
+{
+  int ret = -1;
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (string == NULL || strlen (string) == 0 || strcmp (string, "off") == 0)
+    {
+      count_enabled = 0;
+      ret = 0;
+    }
+  if (strcmp (string, "on") == 0)
+    {
+      count_enabled = 1;
+      char *cret = check_consistency ();
+      if (cret != NULL)
+       {
+         count_enabled = 0;
+         return cret;
+       }
+      ret = 0;
+    }
+  if (strcmp (string, "static") == 0)
+    {
+      count_enabled = -1;
+      char *cret = check_consistency ();
+      if (cret != NULL)
+       {
+         count_enabled = 0;
+         return cret;
+       }
+      ret = 0;
+    }
+  if (ret == 0)
+    {
+      if (count_enabled != 0)
+       {
+         /* ensure that sample period is 0, if set by default */
+         if (sample_default == 1)
+           sample_period = 0;
+         /* ensure that clock profiling is off, if set by default */
+         if (clkprof_default == 1)
+           {
+             clkprof_default = 0;
+             clkprof_enabled = 0;
+           }
+         if (hwcprof_default == 1)
+           hwcprof_default = 0;
+       }
+      return NULL;
+    }
+  return dbe_sprintf (GTXT ("Unrecognized count parameter `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_time_run (const char *valarg)
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (valarg == NULL)   /* invalid setting */
+    return strdup (GTXT ("time parameter can not be NULL\n"));
+  /* the string should be a number >= 0 */
+  int prev_start_delay = start_delay;
+  int prev_time_run = time_run;
+  const char *endchar = valarg;
+  char *newchar = NULL;
+  int val = 0;
+  if (*endchar != '-')
+    {
+      val = (int) strtol (endchar, &newchar, 0);
+      endchar = newchar;
+      if (val < 0)
+       return dbe_sprintf (GTXT ("Unrecognized time parameter `%s'\n"), valarg);
+      if (*endchar == 'm')
+       {
+         val = val * 60; /* convert to seconds */
+         endchar++;
+       }
+      else if (*endchar == 's')     /* no conversion needed */
+       endchar++;
+      if (*endchar == 0)
+       {
+         time_run = val;
+         return NULL;
+       }
+      else if (*endchar != '-')
+       return dbe_sprintf (GTXT ("Unrecognized time parameter `%s'\n"), valarg);
+    }
+  /* a second number is provided */
+  start_delay = val;
+  endchar++;
+  val = (int) strtol (endchar, &newchar, 0);
+  endchar = newchar;
+  if (val < 0)
+    {
+      start_delay = prev_start_delay;
+      return dbe_sprintf (GTXT ("Unrecognized time parameter `%s'\n"), valarg);
+    }
+  if (*endchar == 'm')
+    {
+      val = val * 60; /* convert to seconds */
+      endchar++;
+    }
+  else if (*endchar == 's')     /* no conversion needed */
+    endchar++;
+  if (*endchar != 0)
+    {
+      start_delay = prev_start_delay;
+      return dbe_sprintf (GTXT ("Unrecognized time parameter `%s'\n"), valarg);
+    }
+  time_run = val;
+  if (time_run != 0 && start_delay >= time_run)
+    {
+      start_delay = prev_start_delay;
+      return dbe_sprintf (GTXT ("Invalid time parameter `%s': start time must be earlier than end time\n"), valarg);
+    }
+  char *ret = check_consistency ();
+  if (ret != NULL)
+    {
+      start_delay = prev_start_delay;
+      time_run = prev_time_run;
+      return ret;
+    }
+  return NULL;
+}
+
+char *
+Coll_Ctrl::set_attach_pid (char *valarg)
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (valarg == NULL)
+    return strdup (GTXT ("Specified PID can not be NULL\n"));
+
+  /* the string should be a number corresponding to an active process' pid */
+  char *endchar = NULL;
+  int val = (int) strtol (valarg, &endchar, 0);
+  if (*endchar != 0 || val < 0)
+    return dbe_sprintf (GTXT ("Invalid process pid `%s'\n"), valarg);
+  int prev_attach_pid = attach_pid;
+  attach_pid = val;
+  char *ret = check_consistency ();
+  if (ret != NULL)
+    {
+      attach_pid = prev_attach_pid;
+      return ret;
+    }
+  return NULL;
+}
+
+void
+Coll_Ctrl::free_hwc_fields (Hwcentry * tmpctr)
+{
+  if (tmpctr->name != NULL)
+    free (tmpctr->name);
+  if (tmpctr->int_name != NULL)
+    free (tmpctr->int_name);
+  memset (tmpctr, 0, sizeof (Hwcentry));
+  tmpctr->reg_num = -1;
+}
+
+void
+Coll_Ctrl::hwcentry_dup (Hwcentry *hnew, Hwcentry *_hwc)
+{
+  *hnew = *_hwc;
+  if (_hwc->name != NULL)
+    hnew->name = strdup (_hwc->name);
+  else
+    hnew->name = NULL;
+  if (_hwc->int_name != NULL)
+    hnew->int_name = strdup (_hwc->int_name);
+  else
+    hnew->int_name = NULL;
+  if (_hwc->metric != NULL)
+    hnew->metric = strdup (_hwc->metric);
+  else
+    hnew->metric = NULL;
+  if (_hwc->short_desc != NULL)
+    hnew->short_desc = strdup (_hwc->short_desc);
+  else
+    hnew->short_desc = NULL;
+  if (_hwc->reg_list != NULL)
+    {
+      hnew->reg_list = (regno_t*) malloc (sizeof (regno_t*) * MAX_PICS);
+      // poor way of dealing with malloc failure
+      if (hnew->reg_list)
+       {
+         for (int i = 0; i < MAX_PICS; i++)
+           {
+             hnew->reg_list[i] = _hwc->reg_list[i];
+             if (hnew->reg_list[i] == REGNO_ANY)
+               break;
+           }
+       }
+    }
+}
+
+// Routine to initialize the HWC tables, set up the default experiment, etc.
+void
+Coll_Ctrl::setup_hwc ()
+{
+  static bool is_hwc_setup = false;
+  if (is_hwc_setup == true)
+    return;
+  // try to set the default counters
+  is_hwc_setup = true;
+  set_hwcdefault ();
+}
+
+hrtime_t
+Coll_Ctrl::clkprof_timer_2_hwcentry_min_time (int target_clkprof_usec)
+{
+  hrtime_t hwc_nanosec;
+  if (target_clkprof_usec == clk_params.normval)
+    hwc_nanosec = HWCTIME_ON;
+  else if (target_clkprof_usec == clk_params.lowval)
+    hwc_nanosec = HWCTIME_LO;
+  else if (target_clkprof_usec == clk_params.hival)
+    hwc_nanosec = HWCTIME_HI;
+  else
+    hwc_nanosec = 1000LL * target_clkprof_usec; // nanoseconds
+  return hwc_nanosec;
+}
+
+void
+Coll_Ctrl::set_clkprof_timer_target (int microseconds)
+{
+  clkprof_timer = microseconds;
+  clkprof_timer_target = microseconds;
+  hrtime_t hwc_min_time_nanosec = clkprof_timer_2_hwcentry_min_time (microseconds);
+  for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
+    {
+      hwctr[ii].min_time_default = hwc_min_time_nanosec;
+      hwc_update_val (&hwctr[ii]);
+    }
+}
+
+void
+Coll_Ctrl::adjust_clkprof_timer (int use)
+{
+  clkprof_timer = use;
+}
+
+/* set HWC counter set from a string */
+char * /* return an error string */
+Coll_Ctrl::set_hwcstring (const char *string, char **warnmsg)
+{
+  *warnmsg = NULL;
+  if (string == NULL || strcmp (string, "off") == 0)
+    {
+      hwcprof_enabled_cnt = 0;
+      return NULL;
+    }
+  setup_hwc ();
+  int old_cnt = hwcprof_enabled_cnt;
+  int old_hwcprof_default = hwcprof_default;
+
+  /* reset any previous count to zero */
+  hwcprof_enabled_cnt = 0;
+  char *ret = add_hwcstring (string, warnmsg);
+  if (ret != NULL)
+    {
+      // restore previous setting
+      hwcprof_enabled_cnt = old_cnt;
+      hwcprof_default = old_hwcprof_default;
+    }
+  return ret;
+}
+
+/* add additional HWC counters to counter set from string */
+char * /* return an error string */
+Coll_Ctrl::add_hwcstring (const char *string, char **warnmsg)
+{
+  *warnmsg = NULL;
+  if (string == NULL || strcmp (string, "off") == 0)
+    {
+      hwcprof_enabled_cnt = 0;
+      return NULL;
+    }
+  setup_hwc ();
+  int rc = 0;
+  int old_cnt = hwcprof_enabled_cnt;
+  int prev_cnt = hwcprof_enabled_cnt;
+  // int old_hwcprof_default = hwcprof_default;
+  char UEbuf[MAXPATHLEN * 5];
+  int UEsz;
+  Hwcentry tmpctr[MAX_PICS];
+  Hwcentry * ctrtable[MAX_PICS];
+  char *emsg;
+  char *wmsg;
+  UEbuf[0] = 0;
+  UEsz = sizeof (UEbuf);
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (hwcprof_default == 0)
+    {
+      /* Copy the counters already defined */
+      for (int ii = 0; ii < prev_cnt; ii++)
+       tmpctr[ii] = hwctr[ii];
+    }
+  else  /* the previously-defined counters were defaulted; don't copy them */
+    prev_cnt = 0;
+
+  /* look up the CPU version */
+  cpc_cpuver = hwc_get_cpc_cpuver ();
+  if (string && *string)
+    {
+      /* lookup counters */
+      /* set up a pointer array */
+      for (unsigned ii = 0; ii < MAX_PICS; ii++)
+       ctrtable[ii] = &tmpctr[ii];
+      hrtime_t global_min_time = clkprof_timer_2_hwcentry_min_time (clkprof_timer_target);
+      rc = hwc_lookup (kernelHWC, global_min_time, string, &ctrtable[prev_cnt], MAX_PICS - prev_cnt, &emsg, &wmsg);
+      if (wmsg != NULL)
+       *warnmsg = wmsg;
+      if (rc < 0)
+       return emsg;
+      /* set count for sum of old and new counters */
+      rc = rc + prev_cnt;
+    }
+
+  /* even though the actual hwctr[] array is not updated, we can check consistency */
+  char *ret = check_consistency ();
+  if (ret != NULL)
+    {
+      hwcprof_enabled_cnt = old_cnt;
+      return ret;
+    }
+
+  /* finally, validate the full counter set */
+  emsg = hwc_validate_ctrs (kernelHWC, ctrtable, rc);
+  if (emsg != NULL)
+    {
+      hwcprof_enabled_cnt = old_cnt;
+      return emsg;
+    }
+
+  /* success, update real counters and the string for them */
+  /* turn off the default */
+  hwcprof_default = 0;
+  hwcprof_enabled_cnt = rc;
+  free (hwc_string);
+  for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
+    {
+      /* shallow copy of new counters */
+      hwctr[ii] = tmpctr[ii];
+      char *rateString = hwc_rate_string (&hwctr[ii], 0);
+      snprintf (UEbuf + strlen (UEbuf), UEsz - strlen (UEbuf),
+               NTXT (",%s,%s"), hwctr[ii].name,
+               rateString ? rateString : "");
+      free (rateString);
+    }
+  /* now duplicate that string, skipping the leading comma */
+  hwc_string = strdup (&UEbuf[1]);
+  return NULL;
+}
+
+/* add default HWC counters to counter set with resolution (on, hi, or lo) */
+/* Note that the resultion will also be used to set the clock-profiling default */
+char * /* return an error string */
+Coll_Ctrl::add_default_hwcstring (const char *resolution, char **warnmsg, bool add, bool forKernel)
+{
+  setup_hwc ();
+  *warnmsg = NULL;
+  char *def_string = hwc_get_default_cntrs2 (forKernel, 1);
+  if (def_string == NULL)
+    {
+      /* no string defined, format and return an error message */
+      char cpuname[128];
+      hwc_get_cpuname (cpuname, sizeof (cpuname));
+      return dbe_sprintf (GTXT ("No default HW counter set is defined for %s\n"), cpuname);
+    }
+  int len = strlen (def_string);
+  if (len == 0)
+    {
+      /* string zero-length, meaning default counters can't be used */
+      char cpuname[128];
+      hwc_get_cpuname (cpuname, sizeof (cpuname));
+      return dbe_sprintf (GTXT ("HW counter set for %s cannot be loaded on this system\n"), cpuname);
+    }
+  /* allocate return string */
+  int retsize = 2 * len + 10;
+  char *ret = (char *) malloc (retsize);
+  if (ret == NULL)
+    return strdup (GTXT ("internal error formating HW counter set; malloc failed\n"));
+  *ret = 0;
+  char *retp = ret;
+  char *stringp = def_string;
+  int first = 1;
+  char *hwc_defaultx = strdup (def_string);
+
+  /* now massage the string in order to insert resolution for each counter */
+  for (;;)
+    {
+      /* find the next comma */
+      char * next;
+      char *nextp;
+      if (first == 1)
+       nextp = stringp;
+      else
+       nextp = stringp + 1;
+      first = 0;
+      if ((next = strchr (nextp, (int) ',')) != NULL)
+       {
+         if (next == nextp)
+           {
+             /* next counter is zero-length -- invalid string */
+             char cpuname[128];
+             hwc_get_cpuname (cpuname, sizeof (cpuname));
+             free (ret);
+             ret = dbe_sprintf (GTXT ("HW counter set for %s, \"%s\", format error\n"), cpuname, hwc_defaultx);
+             free (hwc_defaultx);
+             return ret;
+           }
+         /* another field found */
+         *next = 0;
+         char nextc = *(next + 1);
+         if ((nextc == 0) || (nextc == ','))
+           {
+             /* either ,, between fields, or string ends in comma */
+             /* append the string */
+             strncat (retp, stringp, (retsize - strlen (retp) - 1));
+             strncat (retp, ",", (retsize - strlen (retp) - 1));
+             strncat (retp, resolution, (retsize - strlen (retp) - 1));
+             if (nextc == 0)       /* string ended in comma; we're done */
+               break;
+           }
+         else
+           {
+             /* string had only one comma between counter names; that's not valid */
+             char cpuname[128];
+             hwc_get_cpuname (cpuname, sizeof (cpuname));
+             free (ret);
+             ret = dbe_sprintf (GTXT ("HW counter set for %s, \"%s\", format error\n"), cpuname, hwc_defaultx);
+             free (hwc_defaultx);
+             return ret;
+           }
+         /* string had ,, between fields; move to next field */
+         stringp = next + 1;
+         if (* (stringp + 1) == 0)     /* name ended in ,, -- we're done */
+           break;
+         continue;
+       }
+      else
+       {
+         /* no comma found, add the last counter and the comma and resolution */
+         strncat (retp, stringp, (retsize - strlen (retp) - 1));
+         strncat (retp, ",", (retsize - strlen (retp) - 1));
+         strncat (retp, resolution, (retsize - strlen (retp) - 1));
+         break;
+       }
+    }
+
+  /* we have now formatted the new string, with resolution inserted */
+  char *ccret;
+  if (add == true)
+    ccret = add_hwcstring (ret, warnmsg);
+  else
+    ccret = set_hwcstring (ret, warnmsg);
+  free (hwc_defaultx);
+  free (ret);
+
+  /* now set the clock-profiling timer, if on by default */
+  if (clkprof_default == 1)
+    {
+      if (strcmp (resolution, NTXT ("on")) == 0)
+       set_clkprof_timer_target (clk_params.normval);
+      else if (strcmp (resolution, NTXT ("lo")) == 0)
+       set_clkprof_timer_target (clk_params.lowval);
+      else if (strcmp (resolution, NTXT ("hi")) == 0)
+       set_clkprof_timer_target (clk_params.hival);
+    }
+  return ccret;
+}
+
+void
+Coll_Ctrl::set_hwcdefault ()
+{
+  char *string = hwc_get_default_cntrs2 (kernelHWC, 1);
+  if (string != NULL)
+    {
+      if (strlen (string) == 0)
+       hwcprof_default = 0;
+      else
+       {
+         char * warnmsg = NULL;
+         char *ccret = add_hwcstring (string, &warnmsg);
+         if (ccret != NULL)
+           {
+#if 0
+             /* set string to zero-length so that it won't be used again */
+             hwc_set_default_cntrs (kernelHWC, NTXT (""));
+#endif
+             hwcprof_default = 0;
+           }
+         else
+           hwcprof_default = 1;
+       }
+      free (string);
+    }
+  else
+    hwcprof_default = 0;
+}
+
+void
+Coll_Ctrl::disable_hwc ()
+{
+  hwcprof_enabled_cnt = 0;
+  hwcprof_default = 0;
+  free (hwc_string);
+  hwc_string = NULL;
+}
+
+char *
+Coll_Ctrl::set_sample_period (const char *string)
+{
+  int val;
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (string == NULL || strcmp (string, "on") == 0)
+    val = 1;
+  else if (strcmp (string, "off") == 0)
+    val = 0;
+  else
+    {
+      /* string should be a number > 0 */
+      char *endchar = NULL;
+      val = (int) strtol (string, &endchar, 0);
+      if (*endchar != 0 || val <= 0)
+       return dbe_sprintf (GTXT ("Unrecognized sample period `%s'\n"), string);
+    }
+  /* set that value */
+  int prev_sample_period = sample_period;
+  sample_period = val;
+  char *ret = check_consistency ();
+  if (ret != NULL)
+    {
+      sample_period = prev_sample_period;
+      return ret;
+    }
+  sample_default = 0;
+  return NULL;
+}
+
+char *
+Coll_Ctrl::set_size_limit (const char *string)
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (string == NULL || strlen (string) == 0
+      || strcmp (string, "unlimited") == 0 || strcmp (string, "none") == 0)
+    {
+      size_limit = 0;
+      return NULL;
+    }
+  /* string should be a number >0; 0 is an error */
+  char *endchar = NULL;
+  int val = (int) strtol (string, &endchar, 0);
+  if (*endchar != 0 || val <= 0)
+    return dbe_sprintf (GTXT ("Unrecognized size limit `%s'\n"), string);
+  size_limit = val;
+  return 0;
+}
+
+void
+Coll_Ctrl::build_data_desc ()
+{
+  char spec[DD_MAXPATHLEN];
+  spec[0] = 0;
+
+  // Put sample sig before clock profiling. Dbx uses PROF
+  // for that purpose and we want it to be processed first.
+  if (project_home)
+    snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "P:%s;", project_home);
+  if (sample_sig != 0)
+    snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "g:%d;", sample_sig);
+  if (pauseresume_sig != 0)
+    snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "d:%d%s;", pauseresume_sig,
+             (pauseresume_pause == 1 ? "p" : ""));
+  if (clkprof_enabled == 1)
+    snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "p:%d;", clkprof_timer);
+  if (synctrace_enabled == 1)
+    snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "s:%d,%d;", synctrace_thresh, synctrace_scope);
+  if (heaptrace_enabled == 1)
+    snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "H:%d;", heaptrace_checkenabled);
+  if (iotrace_enabled == 1)
+    snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "i:;");
+  if (hwcprof_enabled_cnt > 0)
+    {
+      snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "h:%s",
+               (hwcprof_default == true) ? "*" : "");
+      for (int ii = 0; ii < hwcprof_enabled_cnt; ii++)
+       {
+         /* min_time is a "new" field.
+          *
+          * To help process_data_descriptor() in hwcfuncs.c parse
+          * the HWC portion of this string -- specifically, to
+          * recognize min_time when it's present and skip over
+          * when it's not -- we prepend 'm' to the min_time value.
+          *
+          * When we no longer worry about, say, an old dbx
+          * writing this string and a new libcollector looking for
+          * the min_time field, the 'm' character can be
+          * removed and process_data_descriptor() simplified.
+          */
+         hrtime_t min_time = hwctr[ii].min_time;
+         if (min_time == HWCTIME_TBD)
+           // user did not specify any value for overflow rate
+           min_time = hwctr[ii].min_time_default;
+         snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec),
+                   "%s%s:%s:%d:%d:m%lld:%d:%d:0x%x", ii ? "," : "",
+                   strcmp (hwctr[ii].name, hwctr[ii].int_name) ? hwctr[ii].name : "",
+                   hwctr[ii].int_name, hwctr[ii].reg_num, hwctr[ii].val,
+                   min_time, ii, /*tag*/ hwctr[ii].timecvt, hwctr[ii].memop);
+       }
+      snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), ";");
+    }
+  if ((time_run != 0) || (start_delay != 0))
+    {
+      if (start_delay != 0)
+       snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "t:%d:%d;", start_delay, time_run);
+      else
+       snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "t:%d;", time_run);
+    }
+  if (sample_period != 0)
+    snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "S:%d;",
+             sample_period);
+  if (size_limit != 0)
+    snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "L:%d;",
+             size_limit);
+  if (java_mode != 0)
+    snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "j:%d;", (int) java_mode);
+  if (follow_mode != FOLLOW_NONE)
+    snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "F:%d;", (int) follow_mode);
+  snprintf (spec + strlen (spec), sizeof (spec) - strlen (spec), "a:%s;", archive_mode);
+  if (strlen (spec) + 1 >= sizeof (spec))
+    abort ();
+  free (data_desc);
+  data_desc = strdup (spec);
+}
+
+char *
+Coll_Ctrl::check_group ()
+{
+  char group_file[MAXPATHLEN];
+  if (expt_group == NULL)
+    return NULL;
+  // Is the group an relative path, with a store directory set?
+  if ((expt_group[0] == '/') || ((udir_name == NULL) || (udir_name[0] == '0')))
+    snprintf (group_file, sizeof (group_file), "%s", expt_group);
+  else  // relative path, store directory; make group_file in that directory
+    snprintf (group_file, sizeof (group_file), "%s/%s", udir_name, expt_group);
+  // See if we can write the group file
+  int ret = access (group_file, W_OK);
+  if (ret != 0)
+    {
+      if (errno == ENOENT)
+       {
+         char *stmp = group_file;
+         char *dir = dirname (stmp);
+         ret = access (dir, W_OK);
+         if (ret != 0) // group file does not exist;
+           return dbe_sprintf (GTXT ("Directory (%s) for group file %s is not writeable: %s\n"),
+                               dir, group_file, strerror (errno));
+       }
+      else
+       return dbe_sprintf (GTXT ("Group file %s is not writeable: %s\n"),
+                           group_file, strerror (errno));
+    }
+  return NULL;
+}
+
+char *
+Coll_Ctrl::join_group ()
+{
+  int tries = 0;
+  int groupfd;
+  FILE *file;
+  char group_file[MAXPATHLEN];
+  struct stat statbuf;
+  struct flock flockbuf;
+  flockbuf.l_type = F_WRLCK;
+  flockbuf.l_whence = SEEK_SET;
+  flockbuf.l_start = 0;
+  flockbuf.l_len = 0;
+  if (expt_group == NULL)
+    return NULL;
+  // Is the group an relative path, with a store directory set?
+  if (expt_group[0] == '/' || udir_name == NULL || udir_name[0] == '0')
+    snprintf (group_file, sizeof (group_file), "%s", expt_group);
+  else  // relative path, store directory; make group_file in that directory
+      snprintf (group_file, sizeof (group_file), "%s/%s", udir_name, expt_group);
+  for (;;)
+    {
+      tries++;
+      // try to open the group file
+      while ((groupfd = open (group_file, O_RDWR)) >= 0)
+       {
+         if (uinterrupt == 1)
+           {
+             close (groupfd);
+             return strdup (GTXT ("user interrupt\n"));
+           }
+         // it's opened, now lock it
+         if (fcntl (groupfd, F_SETLK, &flockbuf) != -1)
+           {
+             // we got the lock; check the file size
+             if (fstat (groupfd, &statbuf) != 0)
+               {
+                 // can't stat the file -- give up
+                 close (groupfd);
+                 return dbe_sprintf (GTXT ("Can't fstat group file %s\n"), group_file);
+               }
+             if (statbuf.st_size == 0)
+               {
+                 // size is zero: we got the lock just as someone
+                 //   else created the group file
+                 //   close the file and release the lock; try again
+                 close (groupfd);
+                 continue;
+               }
+             else
+               {
+                 // size is non-zero, add our record
+                 file = fdopen (groupfd, "a");
+                 if (file == NULL)
+                   {
+                     close (groupfd);
+                     return dbe_sprintf (GTXT ("Can't access group file %s\n"), group_file);
+                   }
+                 if (fprintf (file, "%s\n", store_ptr) <= 0)
+                   {
+                     fclose (file);
+                     return dbe_sprintf (GTXT ("Can't update group file %s\n"), group_file);
+                   }
+                 // close the file, releasing our lock
+                 fclose (file);
+                 return NULL;
+               }
+           }
+         else
+           {
+             // can't get the lock, close the file and try again
+             close (groupfd);
+             if (uinterrupt == 1)
+               return strdup (GTXT ("user interrupt\n"));
+             if (tries == 11900)
+               return dbe_sprintf (GTXT ("Timed out: waiting for group file %s\n"), group_file);
+#if 0
+             if (tries % 500 == 0)
+               USR_WARN (GTXT ("Waiting for group file %s . . ."), group_file);
+#endif
+             usleep (10000U);
+             continue;
+           }
+       }
+      // If the error was not that the file did not exist, report it
+      if (errno != ENOENT)
+       return dbe_sprintf (GTXT ("Can't open group file %s: %s\n"),
+                           group_file, strerror (errno));
+      // the file did not exist, try to create it
+      groupfd = open (group_file, O_CREAT | O_EXCL | O_RDWR, 0666);
+      if (groupfd < 0)
+       {
+         // we could not create the file
+         if (errno == EEXIST)
+           continue;
+         return dbe_sprintf (GTXT ("Can't create group file %s: %s\n"),
+                             group_file, strerror (errno));
+       }
+      // we created the group file, now lock it, waiting for the lock
+      while (fcntl (groupfd, F_SETLKW, &flockbuf) == -1)
+       {
+         // we created the file, but couldn't lock it
+         if (errno != EINTR)
+           return dbe_sprintf (GTXT ("Unable to lock group file %s\n"), group_file);
+       }
+      // we created and locked the file, write to it
+      file = fdopen (groupfd, "a");
+      if (file == NULL)
+       {
+         close (groupfd);
+         return dbe_sprintf (GTXT ("Can't access group file %s\n"), group_file);
+       }
+      // write the header line
+      if (fprintf (file, "%s\n", SP_GROUP_HEADER) <= 0)
+       {
+         fclose (file);
+         return dbe_sprintf (GTXT ("Can't initialize group file %s\n"), group_file);
+       }
+      if (fprintf (file, "%s\n", store_ptr) <= 0)
+       {
+         fclose (file);
+         return dbe_sprintf (GTXT ("Can't update group file %s\n"), group_file);
+       }
+      // finally, close the file, releasing the lock
+      fclose (file);
+      return NULL;
+    }
+  // never reached
+}
+
+char *
+Coll_Ctrl::set_directory (char *dir, char **warn)
+{
+  struct stat statbuf;
+  *warn = NULL;
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (stat (dir, &statbuf) != 0)
+    return dbe_sprintf (GTXT ("Can't set directory `%s': %s\n"),
+                       dir, strerror (errno));
+  if (!S_ISDIR (statbuf.st_mode))
+    return dbe_sprintf (GTXT ("Can't set directory `%s': %s\n"),
+                       dir, strerror (ENOTDIR));
+  free (udir_name);
+  udir_name = strdup (dir);
+
+  // Process new setting
+  *warn = preprocess_names ();
+  if ((uexpt_name != NULL) || (interactive != 0))
+    {
+      char *ret = update_expt_name (true, true);
+      if (ret != NULL)
+       {
+         if (*warn != NULL)
+           {
+             char *msg = dbe_sprintf ("%s%s", *warn, ret);
+             free (*warn);
+             free (ret);
+             *warn = msg;
+           }
+         else
+           *warn = ret;
+       }
+    }
+  else
+    (void) update_expt_name (false, false);
+  return NULL;      // All is OK
+}
+
+int
+Coll_Ctrl::set_target (char* targetname)
+{
+  free (target_name);
+  target_name = NULL;
+  if (targetname != NULL)
+    target_name = strdup (targetname);
+  return 0;
+}
+
+void
+Coll_Ctrl::set_default_stem (const char* stem)
+{
+  default_stem = strdup (stem);
+  preprocess_names ();
+  (void) update_expt_name (false, false); // no warnings
+}
+
+char *
+Coll_Ctrl::set_expt (const char *ename, char **warn, bool overwriteExp)
+{
+  *warn = NULL;
+  if (ename == NULL)
+    {
+      free (uexpt_name);
+      uexpt_name = NULL;
+      return NULL;
+    }
+  char *exptname = canonical_path(strdup(ename));
+  size_t i = strlen (exptname);
+  if (i < 4 || strcmp (&exptname[i - 3], ".er") != 0)
+    {
+      free (exptname);
+      return dbe_sprintf (GTXT ("Experiment name `%s' must end in `.er'\n"),
+                         ename);
+    }
+  // Name is OK
+  free (uexpt_name);
+  uexpt_name = exptname;
+  preprocess_names ();
+  char *err = update_expt_name (true, true, overwriteExp);
+  if (err != NULL)
+    return err;
+  if (overwriteExp)
+    {
+      char *nm = dbe_sprintf ("%s/%s", store_dir, base_name);
+      struct stat statbuf;
+      char *cmd = dbe_sprintf ("/bin/rm -rf %s >/dev/null 2>&1", nm);
+      system (cmd);
+      free (cmd);
+      if (stat (nm, &statbuf) == 0)
+       return dbe_sprintf (GTXT ("Cannot remove experiment `%s'\n"), nm);
+      if (errno != ENOENT)
+       return dbe_sprintf (GTXT ("Cannot remove experiment `%s'\n"), nm);
+      free (nm);
+    }
+  *warn = update_expt_name (true, false);
+  return NULL;
+}
+
+char *
+Coll_Ctrl::set_group (char *groupname)
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (expt_group != NULL)
+    {
+      free (expt_group);
+      expt_group = NULL;
+    }
+  if (groupname == NULL)
+    {
+      // reset the name
+      preprocess_names ();
+      (void) update_expt_name (true, false);
+      return NULL;
+    }
+  int i = (int) strlen (groupname);
+  if (i < 5 || strcmp (&groupname[i - 4], ".erg") != 0)
+    return dbe_sprintf (GTXT ("Experiment group name `%s'must end in `.erg'\n"), groupname);
+  expt_group = strdup (groupname);
+  preprocess_names ();
+  (void) update_expt_name (true, false);
+  return NULL;
+}
+
+char *
+Coll_Ctrl::set_java_mode (const char *string)
+{
+  struct stat statbuf;
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (string == NULL || strlen (string) == 0 || strcmp (string, "on") == 0)
+    {
+#if defined(GPROFNG_JAVA_PROFILING)
+      int prev_java_mode = java_mode;
+      int prev_java_default = java_default;
+      java_mode = 1;
+      java_default = 0;
+      char *ret = check_consistency ();
+      if (ret != NULL)
+       {
+         java_mode = prev_java_mode;
+         java_default = prev_java_default;
+         return ret;
+       }
+      return NULL;
+#else
+      return strdup (GTXT ("gprofng was built without support for profiling Java applications\n"));
+#endif
+    }
+  if (strcmp (string, "off") == 0)
+    {
+      int prev_java_mode = java_mode;
+      int prev_java_default = java_default;
+      java_mode = 0;
+      java_default = 0;
+      char *ret = check_consistency ();
+      if (ret != NULL)
+       {
+         java_mode = prev_java_mode;
+         java_default = prev_java_default;
+         return ret;
+       }
+       free (java_path);
+      java_path = NULL;
+      return NULL;
+    }
+  /* any other value should be a path to Java installation directory */
+  if (stat (string, &statbuf) == 0)
+    {
+      if ((statbuf.st_mode & S_IFMT) == S_IFDIR)
+       {
+         // it's a directory -- set the Java path to it
+         int prev_java_mode = java_mode;
+         int prev_java_default = java_default;
+         java_mode = 1;
+         java_default = 0;
+         char *ret = check_consistency ();
+         if (ret != NULL)
+           {
+             java_mode = prev_java_mode;
+             java_default = prev_java_default;
+             return ret;
+           }
+         return set_java_path (string);
+       }
+    }
+  return dbe_sprintf (GTXT ("Java-profiling parameter is neither \"on\", nor \"off\", nor is it a directory: `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_java_path (const char *string)
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  free (java_path);
+  java_path = strdup (string);
+  return NULL;
+}
+
+char *
+Coll_Ctrl::set_java_args (char *string)
+{
+  char *next;
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  char *prev_java_args = java_args;
+  if (string == NULL || strlen (string) == 0)
+    java_args = strdup ("");
+  else
+    java_args = strdup (string);
+  // now count the number of Java arguments
+  for (next = java_args; *next; next++)
+    {
+      if (*next == ' ' || *next == '\t')
+       continue;
+      njava_args++;
+      for (++next; *next; next++)
+       if (*next == ' ' || *next == '\t')
+         break;
+      if (!*next)
+       break;
+    }
+  if (njava_args == 0)
+    java_args = NULL;
+  char *ret = check_consistency ();
+  if (ret != NULL)
+    {
+      java_args = prev_java_args;
+      return ret;
+    }
+  free (prev_java_args);
+  return NULL;
+}
+
+char *
+Coll_Ctrl::set_follow_mode (const char *string)
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  free (follow_spec_usr);
+  free (follow_spec_cmp);
+  follow_spec_usr = NULL;
+  follow_spec_cmp = NULL;
+  if (string == NULL || strlen (string) == 0 || strcmp (string, "all") == 0
+      || strcmp (string, "on") == 0)
+    {
+      follow_mode = FOLLOW_ON;
+      follow_default = 0;
+      return NULL;
+    }
+  if (strcmp (string, "off") == 0)
+    {
+      follow_mode = FOLLOW_NONE;
+      follow_default = 0;
+      return NULL;
+    }
+
+  /* compile regular expression if string starts with "=" */
+  if (string[0] == '=' && string[1] != 0)
+    {
+      // user has specified a string matching specification
+      regex_t regex_desc;
+      int ercode;
+      const char *userspec = &string[1];
+      size_t newstrlen = strlen (userspec) + 3;
+      char * str = (char *) malloc (newstrlen);
+      if (str)
+       {
+         snprintf (str, newstrlen, "^%s$", userspec);
+         assert (strlen (str) == newstrlen - 1);
+         ercode = regcomp (&regex_desc, str, REG_EXTENDED | REG_NOSUB | REG_NEWLINE);
+       }
+      else
+       ercode = 1;
+      if (!ercode)
+       {
+         follow_spec_usr = strdup (string);
+         /* Ideally, follow_spec_cmp = [serialized regex_desc], */
+         /* so that libcollector wouldn't have to recompile it. */
+         /* For now, just copy the regular expression into follow_spec_cmp */
+         follow_spec_cmp = str;
+         follow_mode = FOLLOW_ALL;
+         follow_default = 0;
+         return NULL;
+       }
+      // syntax error in parsing string
+#if 0
+      char errbuf[256];
+      regerror (ercode, &regex_desc, errbuf, sizeof (errbuf));
+      fprintf (stderr, "Coll_Ctrl::set_follow_mode: regerror()=%s\n", errbuf);
+#endif
+      free (str);
+    }
+  return dbe_sprintf (GTXT ("Unrecognized follow-mode parameter `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_prof_idle (const char *string)
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (string == NULL || strlen (string) == 0 || strcmp (string, "on") == 0)
+    {
+      prof_idle = 1;
+      return NULL;
+    }
+  if (strcmp (string, "off") == 0)
+    {
+      prof_idle = 0;
+      return NULL;
+    }
+  return dbe_sprintf (GTXT ("Unrecognized profiling idle cpus parameter `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_archive_mode (const char *string)
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (string == NULL || strlen (string) == 0)
+    string = "on";
+  if (strcasecmp (string, "on") == 0 || strcasecmp (string, "off") == 0
+      || strcasecmp (string, "ldobjects") == 0
+      || strcasecmp (string, "usedldobjects") == 0
+      || strcasecmp (string, "src") == 0 || strcasecmp (string, "usedsrc") == 0
+      || strcasecmp (string, "all") == 0)
+    {
+      free (archive_mode);
+      archive_mode = strdup (string);
+      return NULL;
+    }
+  return dbe_sprintf (GTXT ("Unrecognized archive-mode parameter `%s'\n"), string);
+}
+
+char *
+Coll_Ctrl::set_sample_signal (int value)
+{
+  const char *buf;
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (value == 0)
+    {
+      sample_sig = 0;
+      return NULL;
+    }
+  if (value == pauseresume_sig)
+    return report_signal_conflict (value);
+  if ((buf = strsignal (value)) != NULL)
+    sample_sig = value;
+  else
+    return dbe_sprintf (GTXT ("Invalid sample signal %d\n"), value);
+  return NULL;
+}
+
+/* find a signal by name */
+int
+Coll_Ctrl::find_sig (const char *string)
+{
+  int val;
+  char *signame_alloc = NULL;
+  const char *signame;
+  val = -1;
+  if (strcmp (string, "off") == 0)
+    return 0;
+  // see if the name begins with SIG
+  if (strncmp (string, "SIG", 3) != 0)
+    {
+      // no: add it
+      signame_alloc = (char *) malloc (strlen (string) + 3 + 1);
+      if (signame_alloc == NULL)
+       return -1;
+      strcpy (signame_alloc, "SIG");
+      strcpy (&signame_alloc[3], string);
+      signame = signame_alloc;
+    }
+  else
+    signame = string;
+
+  /* see if the string is a number */
+  char *endchar = NULL;
+  val = (int) strtol (signame, &endchar, 0);
+  if (*endchar != 0)
+    val = strtosigno (signame);
+  free (signame_alloc);
+  if (val == SIGKILL)
+    return -1;
+  return val;
+}
+
+char *
+Coll_Ctrl::set_pauseresume_signal (int value, int resume)
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  if (value == 0)
+    {
+      pauseresume_sig = 0;
+      return NULL;
+    }
+  if (value == sample_sig)
+    return report_signal_conflict (value);
+  if (strsignal (value) != NULL)
+    {
+      pauseresume_sig = value;
+      pauseresume_pause = resume;
+    }
+  else
+    return dbe_sprintf (GTXT ("Invalid pause-resume (delayed initialization) signal %d\n"), value);
+  return NULL;
+}
+
+char *
+Coll_Ctrl::report_signal_conflict (int value)
+{
+  const char *xbuf = strsignal (value);
+  if (xbuf != NULL)
+    return dbe_sprintf (GTXT ("Signal %s (%d) can not be used for both sample and pause-resume (delayed initialization)\n"),
+                       xbuf, value);
+  return dbe_sprintf (GTXT ("Signal %d can not be used for both sample and pause-resume (delayed initialization)\n"),
+                     value);
+}
+
+char *
+Coll_Ctrl::set_debug_mode (int value)
+{
+  if (opened == 1)
+    return strdup (GTXT ("Experiment is active; command ignored.\n"));
+  debug_mode = value;
+  return NULL;
+}
+
+char *
+Coll_Ctrl::create_exp_dir ()
+{
+  int max = 4095; // 0xFFF - can be increased if it seems too low
+  for (int i = 0; i < max; i++)
+    {
+      if (mkdir (store_ptr,
+                S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0)
+       {
+         int err = errno;
+         if (err == EACCES)
+           return dbe_sprintf (GTXT ("Store directory %s is not writeable: %s\n"),
+                               store_dir, strerror (err));
+         if (i + 1 >= max) // no more attempts
+           return dbe_sprintf (GTXT ("Unable to create directory `%s' -- %s\n%s: %d\n"),
+                               store_ptr, strerror (err),
+                               GTXT ("collect: Internal error: loop count achieved"),
+                               max);
+         char *ermsg = update_expt_name (false, false, true);
+         if (ermsg != NULL)
+           {
+             char *msg = dbe_sprintf (GTXT ("Unable to create directory `%s' -- %s\n"),
+                                      store_ptr, ermsg);
+             free (ermsg);
+             return msg;
+           }
+         continue;
+       }
+      return NULL;  // All is OK
+    }
+  return dbe_sprintf (GTXT ("Unable to create directory `%s'\n"), store_ptr);
+}
+
+char *
+Coll_Ctrl::get_exp_name (const char *stembase)
+{
+  expno = 1;
+  return dbe_sprintf ("%s.%d.er", stembase, expno);
+}
+
+char *
+Coll_Ctrl::preprocess_names ()
+{
+  char buf[MAXPATHLEN];
+  char msgbuf[MAXPATHLEN];
+  char *ret = NULL;
+
+  /* convert the experiment name and directory into store name/dir */
+  /* free the old strings */
+  if (store_dir != NULL)
+    {
+      free (store_dir);
+      store_dir = NULL;
+    }
+  if (expt_dir != NULL)
+    {
+      free (expt_dir);
+      expt_dir = NULL;
+    }
+  if (base_name != NULL)
+    {
+      free (base_name);
+      base_name = NULL;
+    }
+  if (expt_name != NULL)
+    {
+      free (expt_name);
+      expt_name = NULL;
+    }
+  expno = 1;
+  if (uexpt_name != NULL)
+    expt_name = strdup (uexpt_name);
+  else
+    {
+      // no user name -- pick a default
+      char *c;
+      char *stem;
+      char *stembase;
+      if (expt_group == NULL)
+       {
+         stem = strdup (default_stem);
+         stembase = stem;
+       }
+      else
+       {
+         stem = strdup (expt_group);
+         stem[strlen (stem) - 4] = 0;
+         stembase = stem;
+         // now remove any leading directory
+         for (int i = 0;; i++)
+           {
+             if (stem[i] == 0)
+               break;
+             if (stem[i] == '/')
+               stembase = &stem[i + 1];
+           }
+         if (strlen (stembase) == 0)
+           {
+             free (stem);
+             stem = strdup (default_stem);
+             stembase = stem;
+           }
+       }
+      c = get_exp_name (stembase);
+      expt_name = c;
+      free (stem);
+    }
+  snprintf (buf, sizeof (buf), NTXT ("%s"), expt_name);
+  if (buf[0] == '/')
+    {
+      // it's a full path name
+      if (udir_name != NULL)
+       {
+         snprintf (msgbuf, sizeof (msgbuf),
+                   GTXT ("Warning: Experiment name is an absolute path; directory name %s ignored.\n"),
+                   udir_name);
+         ret = strdup (msgbuf);
+       }
+    }
+
+  // now extract the directory and basename
+  int lastslash = 0;
+  for (int i = 0;; i++)
+    {
+      if (buf[i] == 0)
+       break;
+      if (buf[i] == '/')
+       lastslash = i;
+    }
+  expt_dir = strdup (buf);
+  if (lastslash != 0)
+    base_name = strdup (&buf[lastslash + 1]);
+  else
+    base_name = strdup (buf);
+  expt_dir[lastslash] = 0;
+  if (expt_dir[0] == '/')
+    store_dir = strdup (expt_dir);
+  else if ((udir_name == NULL) || (udir_name[0] == 0))
+    {
+      if (expt_dir[0] == 0)
+       store_dir = strdup (".");
+      else
+       store_dir = strdup (expt_dir);
+    }
+  else
+    {
+      /* udir_name is a non-empty string */
+      if (expt_dir[0] == 0)
+       store_dir = strdup (udir_name);
+      else
+       {
+         snprintf (buf, sizeof (buf), "%s/%s", udir_name, expt_dir);
+         store_dir = strdup (buf);
+       }
+    }
+  free (store_ptr);
+  if (strcmp (store_dir, ".") == 0)
+    store_ptr = strdup (base_name);
+  else
+    {
+      snprintf (buf, sizeof (buf), "%s/%s", store_dir, base_name);
+      store_ptr = strdup (buf);
+    }
+
+  // determine the file system type
+  if (strcmp (store_dir, prev_store_dir) != 0)
+    {
+      free (prev_store_dir);
+      prev_store_dir = strdup (store_dir);
+      const char *fstype = get_fstype (store_dir);
+      if (interactive && enabled && (fstype != NULL) && (nofswarn == 0))
+       {
+         snprintf (msgbuf, sizeof (msgbuf),
+                   GTXT ("%sExperiment directory is set to a file system of type \"%s\",\n  which may distort the measured performance;\n  it is preferable to record to a local disk.\n"),
+                   (ret == NULL ? "" : ret), fstype);
+         free (ret);
+         ret = strdup (msgbuf);
+       }
+    }
+  return ret;
+}
+
+char *
+Coll_Ctrl::update_expt_name (bool chgmsg, bool chkonly, bool newname)
+{
+  char *ret = NULL;
+  struct stat statbuf;
+  // make sure the name ends in .er
+  // set count to the length of the name
+  int count = (int) strlen (base_name);
+
+  // this should have been checked already, so we can abort
+  if (count < 4 || strcmp (&base_name[count - 3], ".er") != 0)
+    abort ();
+  int pcount = count - 4;
+  if (!newname)
+    { // check if old name can be used
+      char fullname[MAXPATHLEN];
+      snprintf (fullname, sizeof (fullname), "%s/%s", store_dir, base_name);
+      if (stat (fullname, &statbuf) != 0)
+       if (errno == ENOENT) // name does not exist, we can use it
+         return NULL;
+    }
+  else if (chkonly)
+    return NULL;
+
+  // current name will not work, update the name
+  DIR *dir;
+  struct dirent *dir_entry;
+
+  // see if there's a numeric field in front of the .er of the name
+  int digits = 0;
+  while (isdigit ((int) (base_name[pcount])) != 0)
+    {
+      pcount--;
+      if (pcount == 0)  // name is of the form 12345.er; don't update it
+       return dbe_sprintf (GTXT ("name %s is in use and cannot be updated\n"),
+                           base_name);
+      digits++;
+    }
+  if (digits == 0)  // name is of form xyz.er (or xyz..er); don't update it
+    return dbe_sprintf (GTXT ("name %s is in use and cannot be updated\n"),
+                       base_name);
+  if (base_name[pcount] != '.')   // name is of form xyz123.er; don't update it
+    return dbe_sprintf (GTXT ("name %s is in use and cannot be updated\n"),
+                       base_name);
+  if (chkonly)
+    return NULL;
+
+  // save the name for a changed message
+  char *oldbase = strdup (base_name);
+
+  // the name is of the from prefix.nnn.er; extract the value of nnn
+  int version = atoi (&base_name[pcount + 1]);
+  if (newname)  // do not try to use old name
+    version++;
+  int max_version = version - 1;
+
+  // terminate the base_name string after that . yielding "prefix."
+  base_name[pcount + 1] = 0;
+  if ((dir = opendir (store_dir)) == NULL)
+    {
+      // ignore error -- we'll hit it again later
+      free (oldbase);
+      return NULL;
+    }
+
+  // find the maximum version in the directory
+  // count is the number of characters before the number
+  //
+  while ((dir_entry = readdir (dir)) != NULL)
+    {
+      count = (int) strlen (dir_entry->d_name);
+      if ((count < 4) || (strcmp (&dir_entry->d_name[count - 3], ".er") != 0))
+       continue;
+      // check that the name is of the form prefix.nnn.er; if not, skip it
+      if (strncmp (base_name, dir_entry->d_name, pcount + 1) == 0)
+       {
+         // the "prefix." part matches, terminate the entry name before the .er
+         dir_entry->d_name[count - 3] = 0;
+         char *lastchar;
+         int dversion = (int) strtol (&dir_entry->d_name[pcount + 1], &lastchar, 10);
+
+         // if it did not end where the .er was, skip it
+         if (*lastchar != 0)
+           continue;
+         if (dversion > max_version)
+           max_version = dversion;
+       }
+    }
+
+  // we now have the maximum version determined
+  char newbase[MAXPATHLEN];
+  base_name[pcount + 1] = 0;
+  version = max_version + 1;
+  snprintf (newbase, sizeof (newbase), "%s%d.er", base_name, version);
+  if ((strcmp (oldbase, newbase) != 0) && chgmsg)
+    {
+      ret = dbe_sprintf (GTXT ("name %s is in use; changed to %s\n"),
+               oldbase, newbase);
+      free (oldbase);
+    }
+  else
+    free (oldbase);
+  free (base_name);
+  base_name = strdup (newbase);
+
+  // now, reset expt_name to reflect new setting
+  free (expt_name);
+  if (expt_dir[0] == 0)
+    expt_name = strdup (base_name);
+  else
+    expt_name = dbe_sprintf ("%s/%s", expt_dir, base_name);
+  free (store_ptr);
+  if (strcmp (store_dir, ".") == 0)
+    store_ptr = strdup (base_name);
+  else
+    store_ptr = dbe_sprintf ("%s/%s", store_dir, base_name);
+  closedir (dir);
+  return ret;
+}
+
+void
+Coll_Ctrl::remove_exp_dir ()
+{
+  if (store_ptr == NULL)
+    return;
+  rmdir (store_ptr);
+  free (store_ptr);
+  store_ptr = NULL;
+  return;
+}
+
+void
+Coll_Ctrl::determine_profile_params ()
+{
+  struct itimerval itimer;
+  struct itimerval otimer;
+  int period;
+  long nperiod;
+  struct sigaction act;
+  struct sigaction old_handler;
+  memset (&act, 0, sizeof (struct sigaction));
+  period = 997;
+
+  // set SIGPROF handler to SIG_IGN
+  sigemptyset (&act.sa_mask);
+  act.sa_handler = SIG_IGN;
+  act.sa_flags = SA_RESTART | SA_SIGINFO;
+  if (sigaction (SIGPROF, &act, &old_handler) == -1)
+    {
+      /* couldn't set signal */
+      fprintf (stderr, GTXT ("Can't set SIGPROF: %s\n"), strerror (errno));
+      exit (1);
+    }
+
+  // set the timer to arbitrary resolution
+  itimer.it_interval.tv_sec = period / MICROSEC;
+  itimer.it_interval.tv_usec = period % MICROSEC;
+  itimer.it_value = itimer.it_interval;
+  setitimer (ITIMER_REALPROF, &itimer, &otimer);
+
+  // now reset the timer to turn it off
+  itimer.it_value.tv_sec = 0;
+  itimer.it_value.tv_usec = 0;
+  if (setitimer (ITIMER_REALPROF, &itimer, &otimer) == -1)  // call failed
+    nperiod = -1;
+  else
+    nperiod = otimer.it_interval.tv_sec * MICROSEC + otimer.it_interval.tv_usec;
+
+  // check the returned value: is the what we asked for?
+  if (period == nperiod)    // arbitrary precision is OK
+    set_clk_params (PROFINT_MIN, 1, PROFINT_MAX, PROFINT_HIGH, PROFINT_NORM, PROFINT_LOW);
+  else if (nperiod < 10000) // hi resolution allowed, but not arbitrary precision
+    set_clk_params ((int) nperiod, 1000, PROFINT_MAX, 1000, 10000, 100000);
+  else      // low resolution only allowed
+    set_clk_params (10000, 10000, PROFINT_MAX, 1000, 10000, 100000);
+
+  // If old handler was default, ignore it; otherwise restore it
+  if (old_handler.sa_handler != SIG_DFL)
+    {
+      act.sa_handler = old_handler.sa_handler;
+      if (sigaction (SIGPROF, &act, &old_handler) == -1)
+       {
+         /* couldn't reset signal */
+         fprintf (stderr, GTXT ("Can't reset SIGPROF: %s\n"), strerror (errno));
+         exit (1);
+       }
+    }
+}
+
+const char *
+get_fstype (char *)
+{
+  /* On Linux, statvfs() doesn't return any information that seems to indicate
+     the filetype. The structure statvfs does not have any field/flag that
+     gives this information. Comparing the fields from
+     /usr/include/bits/statvfs.h:
+             unsigned long int f_fsid;
+             int __f_unused;
+             ^^^^ On Solaris, this is where f_basetype is
+             unsigned long int f_flag;
+             unsigned long int f_namemax;
+             XXX Need to revisit this XXX
+   */
+  return NULL; // no NFS warning on Linux for now
+}
+
+//========== Special functions to communicate with the Collector GUI ==========//
+
+/* Interface strings GUI <-> CLI */
+const char *ipc_str_exp_limit = "exp_limit";
+const char *ipc_str_time_limit = "time_limit";
+const char *ipc_str_arch_exp = "arch_exp";
+const char *ipc_str_descendant = "descendant";
+const char *ipc_str_clkprof = "clkprof";
+const char *ipc_str_hwcprof = "hwcprof";
+const char *ipc_str_hwc2_prof = "hwc2_prof";
+const char *ipc_str_javaprof = "javaprof";
+const char *ipc_str_sample = "sample";
+const char *ipc_str_sample_sig = "sample_sig";
+const char *ipc_str_pause_resume_sig = "pause_resume_sig";
+const char *ipc_str_synctrace = "synctrace";
+const char *ipc_str_heaptrace = "heaptrace";
+const char *ipc_str_iotrace = "iotrace";
+const char *ipc_str_count = "count";
+const char *ipc_str_prof_idle = "prof_idle";    // -x option
+// Standard answers
+const char *ipc_str_empty = "";
+const char *ipc_str_on = "on";
+const char *ipc_str_off = "off";
+const char *ipc_str_src = "src";
+const char *ipc_str_usedsrc = "usedsrc";
+const char *ipc_str_usedldobjects = "usedldobjects";
+const char *ipc_str_unlimited = "unlimited";
+const char *ipc_str_unknown_control = "Unknown control";
+const char *ipc_str_internal_error = "Internal error";
+
+/**
+ * Finds signal name
+ * @param signal
+ * @return NULL or signal name (pointer to allocated memory)
+ */
+char *
+Coll_Ctrl::find_signal_name (int signal)
+{
+  char *str_signal = NULL;
+  const char *buf = strsignal (signal);
+  if (buf != NULL)
+    str_signal = strdup (buf);
+  return str_signal;
+}
+
+/**
+ * Gets control's value
+ * @param control
+ * @return value
+ */
+char *
+Coll_Ctrl::get (char * control)
+{
+  int len = strlen (control);
+  if (!strncmp (control, ipc_str_exp_limit, len))
+    {
+      if ((size_limit > 0))
+       return dbe_sprintf ("%d", size_limit);
+      return strdup (ipc_str_unlimited);
+    }
+  if (!strncmp (control, ipc_str_time_limit, len))
+    {
+      if ((time_run != 0) || (start_delay != 0))
+       {
+         if (start_delay != 0)
+           {
+             if (time_run != 0)
+               return dbe_sprintf ("%ds-%ds", start_delay, start_delay + time_run);
+             return dbe_sprintf ("%ds-0s", start_delay);
+           }
+         return dbe_sprintf ("0s-%ds", time_run);
+       }
+      return strdup (ipc_str_unlimited);
+    }
+  if (strncmp (control, ipc_str_arch_exp, len) == 0)
+    return strdup (get_archive_mode ());
+  if (!strncmp (control, ipc_str_descendant, len))
+    {
+      switch (get_follow_mode ())
+       {
+       case FOLLOW_ON:
+         return strdup (ipc_str_on);
+       case FOLLOW_ALL:
+         return strdup (ipc_str_on);
+       case FOLLOW_NONE:
+       default:
+         return strdup (ipc_str_off);
+       }
+    }
+  if (!strncmp (control, ipc_str_prof_idle, len))
+    {
+      if (prof_idle == 0)
+       return strdup (ipc_str_off);
+      return strdup (ipc_str_on);
+    }
+  if (!strncmp (control, ipc_str_clkprof, len))
+    {
+      if (clkprof_default == 1 && clkprof_enabled == 1)     // Default value
+       return strdup (ipc_str_empty);
+      if (clkprof_enabled == 0)
+       return strdup (ipc_str_off);
+      if ((clkprof_timer > 0))
+       return dbe_sprintf ("%d", clkprof_timer / 1000);
+      return strdup (ipc_str_internal_error);
+    }
+  if (!strncmp (control, ipc_str_hwcprof, len))
+    {
+      if (hwcprof_enabled_cnt == 0)
+       return strdup (ipc_str_off);
+      if (hwc_string != NULL)
+       return dbe_sprintf ("on\n%s", hwc_string);
+      return strdup (ipc_str_on); // XXX need more details?
+    }
+  if (!strncmp (control, ipc_str_javaprof, len))
+    {
+      if ((java_mode == 0))
+       return strdup (ipc_str_off);
+      return strdup (ipc_str_on);
+    }
+  if (!strncmp (control, ipc_str_sample, len))
+    {
+      if (sample_default == 1 && sample_period == 1)    // Default value
+       return strdup (ipc_str_empty);
+      if (sample_period == 0)
+       return strdup (ipc_str_off);
+      if (sample_period > 0)
+       return dbe_sprintf ("%d", sample_period);
+      return strdup (ipc_str_internal_error);
+    }
+  if (!strncmp (control, ipc_str_sample_sig, len))
+    {
+      if ((sample_sig == 0))
+       return strdup (ipc_str_off);
+      char *str_signal = find_signal_name (sample_sig);
+      if (str_signal != NULL)
+       return str_signal;
+      return dbe_sprintf (GTXT ("Invalid sample signal %d\n"), sample_sig);
+    }
+  if (!strncmp (control, ipc_str_pause_resume_sig, len))
+    {
+      if (pauseresume_sig == 0)
+       return strdup (ipc_str_off);
+      char *str_signal = find_signal_name (pauseresume_sig);
+      if (str_signal != NULL)
+       return str_signal;
+      return dbe_sprintf (GTXT ("Invalid pause/resume signal %d\n"), pauseresume_sig);
+    }
+  if (!strncmp (control, ipc_str_synctrace, len))
+    {
+      if (synctrace_enabled == 0)
+       return strdup (ipc_str_off);
+      if (synctrace_thresh < 0)
+       return strdup ("on\nthreshold: calibrate");
+      if (synctrace_thresh == 0)
+       return strdup ("on\nthreshold: all");
+      return dbe_sprintf ("on\nthreshold: %d", synctrace_thresh);
+    }
+  if (!strncmp (control, ipc_str_heaptrace, len))
+    {
+      if ((heaptrace_enabled == 0))
+       return strdup (ipc_str_off);
+      return strdup (ipc_str_on);
+    }
+  if (!strncmp (control, ipc_str_iotrace, len))
+    {
+      if ((iotrace_enabled == 0))
+       return strdup (ipc_str_off);
+      return strdup (ipc_str_on);
+    }
+  if (!strncmp (control, ipc_str_count, len))
+    {
+      if ((count_enabled == 0))
+       return strdup (ipc_str_off);
+      if ((count_enabled < 0))
+       return strdup ("on\nstatic");
+      return strdup (ipc_str_on);
+    }
+  return strdup (ipc_str_unknown_control);
+}
+
+/**
+ * Resets control's value (restores the default value)
+ * @param control
+ * @param value
+ * @return error or warning or NULL (done)
+ */
+char *
+Coll_Ctrl::set (char * control, const char * value)
+{
+  char * ret;
+  char * warn = NULL;
+  int len = strlen (control);
+  if (!strncmp (control, ipc_str_exp_limit, len))
+    return set_size_limit (value);
+  if (!strncmp (control, ipc_str_time_limit, len))
+    return set_time_run (value);
+  if (!strncmp (control, ipc_str_arch_exp, len))
+    return set_archive_mode (value);
+  if (!strncmp (control, ipc_str_descendant, len))
+    return set_follow_mode (value);
+  if (!strncmp (control, ipc_str_prof_idle, len))
+    return set_prof_idle (value);
+  if (!strncmp (control, ipc_str_clkprof, len))
+    {
+      ret = set_clkprof (value, &warn);
+      if (ret == NULL)
+       {
+         if (warn != NULL)
+           return warn; // Warning
+         return NULL; // Done
+       }
+      return ret; // Error
+    }
+  if (!strncmp (control, ipc_str_hwcprof, len))
+    {
+      ret = set_hwcstring (value, &warn);
+      if (ret == NULL)
+       {
+         if (warn != NULL)
+           return warn; // Warning
+         return NULL; // Done
+       }
+      return ret; // Error
+    }
+  if (!strncmp (control, ipc_str_hwc2_prof, len))
+    {
+      ret = set_hwcstring (value, &warn);
+      if (ret == NULL)
+       {
+         if (warn != NULL)
+           return warn; // Warning
+         return NULL; // Done
+       }
+      return ret; // Error
+    }
+  if (!strncmp (control, ipc_str_javaprof, len))
+    return set_java_mode (value);
+  if (!strncmp (control, ipc_str_sample, len))
+    return set_sample_period (value);
+  if (!strncmp (control, ipc_str_sample_sig, len))
+    return set_sample_signal (find_sig (value));
+  if (!strncmp (control, ipc_str_pause_resume_sig, len))
+    {
+      char *str_signal = strdup (value);
+      char *str_state = strchr (str_signal, (int) '\n');
+      if (str_state != NULL)
+       {
+         *str_state = 0;
+         str_state++;
+       }
+      int signal = atoi (str_signal);
+      int state = 0;
+      if (str_state != NULL)
+       state = atoi (str_state);
+      free (str_signal);
+      return set_pauseresume_signal (signal, state);
+    }
+  if (!strncmp (control, ipc_str_synctrace, len))
+    return set_synctrace (value);
+  if (!strncmp (control, ipc_str_heaptrace, len))
+    return set_heaptrace (value);
+  if (!strncmp (control, ipc_str_iotrace, len))
+    return set_iotrace (value);
+  if (!strncmp (control, ipc_str_count, len))
+    return set_count (value);
+  return strdup (ipc_str_unknown_control);
+}
+
+/**
+ * Resets control's value (restores the default value)
+ * @param control
+ * @return error or NULL (done)
+ */
+char *
+Coll_Ctrl::unset (char * control)
+{
+  int len = strlen (control);
+  if (!strncmp (control, ipc_str_exp_limit, len))
+    size_limit = 0;
+  if (!strncmp (control, ipc_str_time_limit, len))
+    {
+      time_run = 0;
+      start_delay = 0;
+    }
+  if (!strncmp (control, ipc_str_arch_exp, len))
+    {
+      archive_mode = strdup ("on");
+      return NULL;
+    }
+  if (!strncmp (control, ipc_str_descendant, len))
+    {
+      follow_mode = FOLLOW_NONE;
+      return NULL;
+    }
+  if (!strncmp (control, ipc_str_prof_idle, len))
+    {
+      prof_idle = 1;
+      return NULL;
+    }
+  if (!strncmp (control, ipc_str_clkprof, len))
+    {
+      clkprof_default = 1;
+      clkprof_enabled = 1;
+      return NULL;
+    }
+  if (!strncmp (control, ipc_str_hwcprof, len))
+    {
+      setup_hwc ();
+      set_hwcdefault ();
+      return NULL;
+    }
+  if (!strncmp (control, ipc_str_javaprof, len))
+    {
+      java_mode = 0;
+      java_default = 0;
+      free (java_path);
+      java_path = NULL;
+      free (java_args);
+      java_args = NULL;
+    }
+  if (!strncmp (control, ipc_str_sample, len))
+    {
+      sample_period = 1;
+      sample_default = 1;
+      return NULL;
+    }
+  if (!strncmp (control, ipc_str_sample_sig, len))
+    {
+      sample_sig = 0;
+      return NULL;
+    }
+  if (!strncmp (control, ipc_str_pause_resume_sig, len))
+    {
+      pauseresume_sig = 0;
+      return NULL;
+    }
+  if (!strncmp (control, ipc_str_synctrace, len))
+    {
+      synctrace_enabled = 0;
+      synctrace_thresh = -1;
+      return NULL;
+    }
+  if (!strncmp (control, ipc_str_heaptrace, len))
+    {
+      heaptrace_enabled = 0;
+      return NULL;
+    }
+  if (!strncmp (control, ipc_str_iotrace, len))
+    {
+      iotrace_enabled = 0;
+      return NULL;
+    }
+  if (!strncmp (control, ipc_str_count, len))
+    {
+      count_enabled = 0;
+      Iflag = 0;
+      Nflag = 0;
+      return NULL;
+    }
+  return strdup (ipc_str_unknown_control);
+}
+
+void
+Coll_Ctrl::set_project_home (char *s)
+{
+  if (s)
+    project_home = strdup (s);
+}
diff --git a/gprofng/src/collctrl.h b/gprofng/src/collctrl.h
new file mode 100644 (file)
index 0000000..6555df7
--- /dev/null
@@ -0,0 +1,405 @@
+/* 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.  */
+
+/* This file describes the data structures used to control
+ * data collection; it is used by various commands in the MPMT
+ * tree, and is also shared with dbx.  Care should be taken
+ * to ensure that both the mpmt and dbx builds continue.
+
+ * To remove any APIs or change any enum cases:
+ *
+ * 1.  Make the changes in mpmt, and preserve the old APIs
+ *     as scaffolding and any old enum values as #defines.
+ *
+ * 2.  Add the new APIs and new cases to dbx, remove the
+ *     old ones.
+ *
+ * 3.  Remove the old API scaffolding and enum values here
+ *
+ */
+
+#ifndef        _COLLCTRL_H
+#define        _COLLCTRL_H
+
+#include "hwcentry.h"
+#include "cc_libcollector.h"
+
+/*---------------------------------------------------------------------------*/
+
+/* class */
+
+typedef struct {
+    int min;
+    int res;
+    int max;
+    int hival;
+    int normval;
+    int lowval;
+} clk_params_t;
+
+#define PROFINT_HIGH 997
+#define PROFINT_NORM 10007
+#define PROFINT_LOW 100003
+
+#define PROFINT_MIN 500
+#define PROFINT_MAX 1000000
+
+class Coll_Ctrl {
+public:
+
+  /* _interactive is 1 for dbx, 0 for collect */
+  Coll_Ctrl(int _interactive = 0, bool _defHWC = false, bool _kernelHWC = false);
+  ~Coll_Ctrl();
+
+  Coll_Ctrl(Coll_Ctrl *cc);       /* constructor for duplicate */
+  char *check_expt(char **);      /* check the experiment directory */
+  char *setup_experiment();       /* set up the experiment directory, etc. */
+  void close_expt();
+  void interrupt();               /* the user interrupts experiment */
+  void delete_expt();
+
+  /* enable/disable the experiment */
+  char *enable_expt();
+  void disable_expt()     { enabled = 0; };
+  int isenabled()         { return enabled; };
+
+  /* check for active experiment */
+  int isopened()          { return opened; };
+
+  /* set the parameters for clock-profiling */
+  void set_clk_params(int min, int res, int max, int hi, int norm, int lo);
+  char *set_clkprof(const char *valptr, char **warn);
+  char *reset_clkprof(int val); /* called if profiler must reset value */
+  int get_sys_period()    { return clk_params.min; };
+  int get_clk_min()       { return clk_params.min; };
+  int get_clk_max()       { return clk_params.max; };
+  int get_clk_res()       { return clk_params.res; };
+  int get_clkprof_mode()  { return clkprof_enabled; };
+  int get_clkprof_timer() { return clkprof_timer; };
+
+  /* set the parameters for synchronization tracing */
+  char *set_synctrace(const char *valptr);
+  int get_synctrace_mode()    { return synctrace_enabled; };
+  int get_synctrace_thresh()  { return synctrace_thresh; };
+  int get_synctrace_scope()   { return synctrace_scope; };
+
+  /* set the parameters for heap tracing */
+  char *set_heaptrace(const char *);
+  int get_heaptrace_mode()    { return heaptrace_enabled; };
+  int get_heaptrace_checkmode() { return heaptrace_checkenabled; };
+
+  /* set the parameters for I/O tracing */
+  char *set_iotrace(const char *);
+  int get_iotrace_mode()      { return iotrace_enabled; };
+
+  /* set the parameters for HW counting */
+  void setup_hwc();
+  char *set_hwcstring(const char *str, char **warn);
+  char *add_hwcstring(const char *str, char **warn);
+  char *add_default_hwcstring(const char *str, char **warn, bool add, bool forKernel = false);
+  void set_hwcdefault();
+  void disable_hwc();
+  int get_hwc_cnt()       { return hwcprof_enabled_cnt; };
+  int get_hwc_mode()      { return hwcprof_enabled_cnt ? 1 : 0; };
+  char *get_hwc_string()  { return hwc_string; };
+
+  Hwcentry *
+  get_hwc_entry (int n)
+  {
+    if (n < 0 || n >= hwcprof_enabled_cnt)
+      return 0;
+    return &hwctr[n];
+  };
+
+  void hwcentry_dup (Hwcentry *, Hwcentry *);
+  char *get_hwc_counter (int n) { return get_hwc_entry (n)->name; };
+
+  /* set the parameters for count data */
+  char *set_count (const char *);
+  int get_count ()              { return count_enabled; };
+  void set_Iflag ()             { Iflag = 1; };
+  void set_Nflag ()             { Nflag = 1; };
+
+  /* set time interval for attach with dbx timed collection */
+  /* also used for er_kernel */
+  char *set_time_run (const char *);
+  int get_time_run (void)       { return time_run; };
+  int get_start_delay (void)    { return start_delay; };
+
+  /* set pid for attach with dbx to collect data */
+  char *set_attach_pid (char *);
+  int get_attach_pid (void)     { return attach_pid; };
+
+  /* set java mode, "on" = yes; "off" = no; anthing else implies
+   *   yes, and is the path to the java to use
+   *   java_mode is returned as zero for off, one for on
+   *   java_default is returned as zero for explicitly set, one for defaulted on
+   */
+  char *set_java_mode (const char *);
+  int get_java_mode ()          { return java_mode; };
+  int get_java_default ()       { return java_default; };
+
+  /* setting Java path explicitly */
+  char *set_java_path (const char *);
+  char *get_java_path ()        { return java_path; };
+
+  /* set additional arguments for Java invocation */
+  char *set_java_args (char *);
+  char *get_java_args ()        { return java_args; };
+  int get_java_arg_cnt ()       { return njava_args; };
+
+  /* set load-object archive mode, 0 = no; other = yes */
+  char *set_archive_mode (const char *);
+  char *get_archive_mode ()     { return archive_mode; };
+
+  /* set follow-descendants mode, 0 = no; other = yes */
+  char *set_follow_mode (const char *);
+  Follow_type get_follow_mode () { return follow_mode; };
+  int get_follow_default ()     { return follow_default; };
+  char *get_follow_usr_spec ()  { return follow_spec_usr; };
+  char *get_follow_cmp_spec ()  { return follow_spec_cmp; };
+
+  /* set profile idle cpus mode, 1 = no; 0 = yes */
+  char *set_prof_idle (const char *);
+  int get_prof_idle ()          { return prof_idle; };
+
+  /* set debug more, 1 = yes; other = no */
+  /* if set, target will be set to halt at exit from exec */
+  char *set_debug_mode (int);
+  int get_debug_mode ()         { return debug_mode; };
+
+  /* find a signal from a string */
+  int find_sig (const char *);
+  /* find a signal name from a signal value */
+  char *find_signal_name (int signal);
+
+  /* set the pauseresume (delayed initialization) signal */
+  char *set_pauseresume_signal (int, int);
+  int get_pauseresume_signal () { return pauseresume_sig; };
+  int get_pauseresume_pause ()  { return pauseresume_pause; };
+
+  /* set the sample signal */
+  char *set_sample_signal (int);
+  int get_sample_signal ()      { return sample_sig; };
+
+  /* set the periodic sampling */
+  char *set_sample_period (const char *);
+  int get_sample_period (void)  { return sample_period; };
+
+  /* set experiment size limit */
+  char *set_size_limit (const char *);
+  int get_size_limit (void)     { return size_limit; };
+
+  /* naming methods */
+  /* set the target executable name */
+  int set_target (char *);
+  char *get_target ()           { return target_name; };
+
+  /* set the experiment name */
+  void set_default_stem (const char *);
+  char *set_expt (const char *, char **, bool);
+  char *get_expt ()             { return expt_name; };
+
+  /* set the experiment directory */
+  char *set_directory (char *, char **);
+
+  char *get_directory ()        { return udir_name ? udir_name : store_dir; };
+
+  /* return the real experiment ptr file name */
+  char *get_experiment ()       { return store_ptr; };
+  char *update_expt_name (bool verbose = true, bool ckonly = false, bool newname = false);
+
+  /* remove the experiment */
+  void remove_exp_dir ();
+
+  /* return the data descriptor */
+  char *
+  get_data_desc ()
+  {
+    return data_desc;
+  };
+
+  /* set the experiment group */
+  char *set_group (char *);
+  char *get_group ()            { return expt_group; };
+
+  /* return the experiment settings as a string */
+  char *show (int); /* full show */
+  char *show_expt (); /* short form */
+
+  /* return an argv array to compose a "collect" command from settings */
+  char **get_collect_args ();
+
+  /* determine characteristics of system */
+  char *get_node_name ()        { return node_name; };
+  long get_ncpus ()             { return ncpus; };
+  int get_cpu_clk_freq ()       { return cpu_clk_freq; };
+  int get_cpc_cpuver ()         { return cpc_cpuver; };
+
+    /* disable warning about non-local filesystems */
+  void set_nofswarn ()          { nofswarn = 1; };
+
+  //========== Special functions to communicate with the Collector GUI ==========//
+  char *get (char *);   /* get control's value */
+  char *set (char *, const char *); /* set control's value */
+  char *unset (char *); /* reset control's value to its default */
+  void set_project_home (char *);
+
+private:
+  int interactive;      /* 1 - dbx, 0 - collect */
+  bool defHWC;          /* true if default HWC experiment should be run */
+  bool kernelHWC;       /* T if default HWC counters are for kernel profiling */
+  int opened;           /* T if an experiment is opened */
+  int enabled;          /* T if an experiment is enabled */
+  volatile int uinterrupt; /* set if interrupt from user */
+
+  /* experiment/machine characteristics */
+  char *node_name;      /* name of machine on which experiment is run */
+  long ncpus;           /* number of online CPUs */
+  int cpu_clk_freq;     /* chip clock (MHz.), as reported from processor_info */
+  int cpc_cpuver;       /* chip version, as reported from libcpc */
+  long sys_resolution;  /* system clock resolution */
+  int sys_period;       /* profiling clock resolution on the system */
+  int sample_period;    /* period for sampling, seconds */
+  int sample_default;    /* if period for sampling set by default */
+  int size_limit;       /* experiment size limit, MB */
+  long npages;          /* number of pages configured */
+  long page_size;       /* size of system page */
+  clk_params_t clk_params;
+
+  /* user specification of name */
+  /*  user may specify both uexpt_name and udir_name
+   *   if uexpt_name is absolute path, udir_name is ignored, with warning
+   *   otherwise, udir_name is prepended to uexpt_name
+   *
+   *   if uexpt_name is of the form: <dir>/zzzz.nnn.er, where nnn is numeric,
+   *   nnn will be reset to one greater than the the highest experiment
+   *     with a name of the same form.
+   */
+  char *default_stem;   /* default stem for experiment name */
+  char *uexpt_name;     /* suggested experiment name */
+  char *expt_name;      /* experiment name, after defaulting */
+  char *expt_dir;       /* directory part of suggested experiment name */
+  char *base_name;      /* basename of suggested experiment name */
+  char *udir_name;      /* user name of directory for data */
+
+  char *store_dir;      /* directory to contain experiment dir. */
+  char *prev_store_dir; /* previously set store directory */
+  char *store_ptr;      /* experiment pointer file */
+  char *expt_group;     /* name of experiment group, if any */
+  char *project_home;   /* argv[0] */
+
+  char *target_name;    /* target executable name */
+  char *data_desc;      /* string describing the data to be collected */
+  char *lockname;       /* name of directory lock file */
+  int lockfd;           /* fd of open lock file */
+
+  int nofswarn;         /* if 1, don't warn of filesystem */
+  int expno;            /* number in <stem>.<expno>.er */
+
+  /* T if an target is to be left for debugger attach */
+  int debug_mode;
+
+  /* clock-profiling controls */
+  /* T if clock-based profiling */
+  int clkprof_enabled;
+
+  /* T if on by default, rather than explicit setting */
+  int clkprof_default;
+
+  /* value for timer, microseconds. */
+  int clkprof_timer; // adjusted clock profiling interval
+  int clkprof_timer_target; // desired clock profiling interval
+
+  /* HW counter-profiling controls */
+  /* >0 if HW counter-based profiling */
+  int hwcprof_default;
+  int hwcprof_enabled_cnt;
+  char *hwc_string;
+  Hwcentry hwctr[MAX_PICS];
+
+  int synctrace_enabled;    /* T if synchronization tracing */
+  /*  sync trace threshold value, microsec. */
+  /* if 0, record all */
+  /* if <0, calibrate */
+  int synctrace_thresh;
+
+  /* sync trace scope -- a bit mask */
+  /*   definitions in data_pckts.h */
+  int synctrace_scope;
+
+  int heaptrace_enabled;    /* T if heap tracing */
+  /* if 0 no checking;
+   * if 1, check for over- and under-write
+   * if 2, also set patterns in malloc'd and free'd areas
+   */
+  int heaptrace_checkenabled;
+  int iotrace_enabled;  /* T if I/O tracing */
+
+  /* count controls */
+  /* 1 if counting is enabled; -1 if count static is enabled */
+  int count_enabled;
+  int Iflag;    /* specify bit output directory -- only with count_enabled */
+  int Nflag;    /* specify bit library to ignore -- only with count_enabled */
+
+  /* pid, if -P <pid> is invoked for attach with dbx */
+  int attach_pid;
+
+  /* time_run -- non-zero if timed execution request (dbx/er_kernel) */
+  int time_run;
+  int start_delay;
+
+  /* T if Java profiling is requested */
+  int java_mode;
+  int java_default;
+  char *java_path;
+  char *java_args;
+  int njava_args;
+
+  /* whether/how following-descendants is requested */
+  Follow_type follow_mode;
+  int follow_default;
+  char *follow_spec_usr;    // user's selective follow spec
+  char *follow_spec_cmp;    // compiled selective follow spec
+  int prof_idle;            // whether profiling idle cpus is requested
+  char *archive_mode;       // how load-objects archiving is requested
+
+  // signals to control pause-resume (delayed initialization) and samples
+  int pauseresume_sig;      // for pause-resume signal -- delayed initialization
+  int pauseresume_pause;    // 1 if pauseresume and start paused; 0 if not
+  int sample_sig;           // to trigger sample
+  char *report_signal_conflict (int);
+  char *check_consistency ();   // check the experiment settings for consistency
+  void determine_profile_params ();
+  char *preprocess_names ();
+  char *get_exp_name (const char *);
+  char *create_exp_dir ();
+  void build_data_desc ();
+  char *check_group ();
+  char *join_group ();
+  void free_hwc_fields (Hwcentry *tmpctr);
+
+  // propagates clkprof_timer change to Hwcentry hwctr[]
+  void set_clkprof_timer_target (int microseconds);
+  void adjust_clkprof_timer (int microseconds);
+  hrtime_t clkprof_timer_2_hwcentry_min_time (int clkprof_microseconds);
+};
+
+#endif /* !_COLLCTRL_H */
diff --git a/gprofng/src/collect.h b/gprofng/src/collect.h
new file mode 100644 (file)
index 0000000..c500dee
--- /dev/null
@@ -0,0 +1,156 @@
+/* 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 _COLLECT_H
+#define _COLLECT_H
+
+#include <Application.h>
+
+extern "C"
+{
+  typedef void (*SignalHandler)(int);
+}
+
+class Coll_Ctrl;
+class Elf;
+
+#define MAXLABELS       10      /* maximum number of -C arguments */
+#define STDEBUFSIZE     24000
+
+enum { MAX_LD_PRELOAD_TYPES = 3 };
+
+struct Process
+{
+  Process (pid_t _pid) : pid (_pid) { }
+  pid_t pid;
+};
+
+struct DtraceTool
+{
+  DtraceTool (char*);
+  ~DtraceTool ();
+
+  char *name;       // Tool name as specified by -D flag
+  char *params;     // Tool parameters
+  char *dfile;      // Extracted d-script
+  char *mfile;      // Extracted metadata file
+  char *ofile;      // Output file
+  pid_t pid;
+};
+
+// collect object
+class collect : Application
+{
+public:
+  collect (int argc, char *argv[], char **envp);
+  virtual ~collect ();
+  void start (int argc, char *argv[]);
+  void  writeStr (int f, const char *buf);
+
+  // the collector control class
+  Coll_Ctrl *cc;
+
+private:
+  enum Exec_status
+  {
+    EXEC_OK = 0, // found as runnable executable
+    EXEC_ELF_NOSHARE, // found, but built unshared
+    EXEC_IS_JAR, // found as a .jar file
+    EXEC_IS_CLASS, // found as a .class file but name missing .class
+    EXEC_IS_CLASSCLASS, // found as a .class file with explicit .class
+    EXEC_OPEN_FAIL, // could not be opened
+    EXEC_ELF_LIB, // internal error: bad elf library
+    EXEC_ELF_HEADER, // executable, with bad ELF header
+    EXEC_ELF_ARCH, // executable, but unrunnable architecture
+    EXEC_ISDIR, // a directory, not a file
+    EXEC_NOT_EXEC, // a file, but not executable
+    EXEC_NOT_FOUND // a directory, not a file
+  };
+
+  // override methods in base class
+  void usage ();
+  void short_usage ();
+  void show_hwc_usage ();
+  int check_args (int argc, char *argv[]);
+  void check_target (int, char **);
+  Exec_status check_executable (char *);
+  Exec_status check_executable_arch (Elf *);
+  char *status_str (Exec_status, char *);
+  int do_flag (const char *);
+  char *find_java (void);
+  char *java_path;
+  char *java_how;
+  int putenv_libcollector ();
+  int putenv_libcollector_ld_audits ();
+  int putenv_libcollector_ld_preloads ();
+  int putenv_libcollector_ld_misc ();
+  void add_ld_preload (const char *lib);
+  int putenv_ld_preloads ();
+  int putenv_memso ();
+  int env_strip (char *env, const char *str);
+  int putenv_purged_ld_preloads (const char *var);
+  int putenv_append (const char *var, const char *val);
+  void get_count_data ();
+  void prepare_dbx ();
+  int traceme (const char *file, char *const argv[]);
+  int checkflagterm (const char *);
+  void dupflagseen (char);
+  void dupflagseen (const char *);
+  void validate_config (int);
+  void validate_java (const char *, const char *, int);
+  int set_output ();
+  void reset_output ();
+
+  /* Logging warning messages */
+  char **collect_warnings;
+  int collect_warnings_idx;
+  void warn_open ();
+  void warn_close ();
+  void warn_write (const char *format, ...);
+  void warn_comment (const char *kind, int num, char *s = NULL, int len = 0);
+  char *warnfilename;
+  FILE *warn_file;
+
+  /* MPI experiment handling */
+  void setup_MPI_expt ();   /* the founder experiment */
+  void write_MPI_founder_log ();
+  void close_MPI_founder_log (int, int);
+  void spawn_MPI_job (); /* run the MPI job */
+  void copy_collect_args (char ***);   /* copy collect args for an MPI target */
+  int disabled;
+  int jseen_global;         /* if -j flag was seen */
+  int verbose;
+  bool mem_so_me;           /* if T, preload mem.so, not libcollector */
+  int origargc;
+  char **arglist;
+  char **origargv;
+  char **origenvp;
+  int targ_index;           // index of name of target in origargv
+  bool is_64;
+  int nargs;
+  int njargs;
+  char *jargs;
+  int nlabels;
+  char *label[MAXLABELS];
+  char *sp_preload_list[MAX_LD_PRELOAD_TYPES + 1];  // +1 for NULL termination
+  char *sp_libpath_list[MAX_LD_PRELOAD_TYPES + 1];  // +1 for NULL termination
+};
+
+#endif /* ! _COLLECT_H */
diff --git a/gprofng/src/collector_module.h b/gprofng/src/collector_module.h
new file mode 100644 (file)
index 0000000..512af7a
--- /dev/null
@@ -0,0 +1,223 @@
+/* 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_MODULE_H
+#define _COLLECTOR_MODULE_H
+
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "gp-defs.h"
+
+struct stat;
+struct tm;
+
+#define COLLECTOR_MODULE_ERR    ((CollectorModule)-1)
+
+/* -------  libc interface ----------------- */
+/* the fields in this structure are in alphabetical order.
+ * If you add any, please put it in the right place */
+typedef struct CollectorUtilFuncs
+{
+  int (*access)();
+  int (*atoi)(const char *nptr);
+  void *(*calloc)(size_t nelem, size_t elsize);
+  int (*clearenv)(void);
+  int (*close)(int);
+  int (*closedir)();
+  int (*execv)(const char *path, char *const argv[]);
+  void (*exit)(int status);
+  int (*fclose)(FILE *stream);
+  int (*fcntl)(int fd, int cmd, ...);
+  char *(*fgets)(char *s, int n, FILE *stream);
+  FILE *(*fopen)(const char *filename, const char *mode);
+  pid_t (*vfork)();
+  int (*fprintf)(FILE *stream, const char *format, ...);
+  void (*free)(void *ptr);
+  int (*fstat)(int fd, struct stat *buf);
+  int (*getcpuid)();
+  char *(*getcwd)(char *buf, size_t size);
+  char *(*getenv)(const char *name);
+  struct tm *(*gmtime_r)(const time_t *clock, struct tm *res);
+  int (*ioctl)(int d, int request, ...);
+  off_t (*lseek)(int fd, off_t offset, int whence);
+  void *(*malloc)(size_t size);
+  void *(*memset)(void *s1, int c, size_t n);
+  int (*mkdir)();
+  time_t (*mktime)(struct tm *timeptr);
+  void *(*mmap)(void *, size_t, int, int, int, off_t);
+  void *(*mmap64)();
+  int (*munmap)();
+  int (*open)(const char *, int, ...);
+  int (*open_bare)(const char *, int, ...);
+  DIR *(*opendir)();
+  int (*pclose)(FILE *stream);
+  FILE *(*popen)(const char *command, const char *mode);
+  int (*putenv)(char *string);
+  ssize_t (*pwrite)();
+  ssize_t (*pwrite64)();
+  ssize_t (*read)();
+  int (*setenv)(const char *name, const char *value, int overwrite);
+  int (*sigfillset)(sigset_t *set);
+  int (*sigprocmask)(int how, const sigset_t *set, sigset_t *oldset);
+  int (*snprintf)(char *str, size_t size, const char *format, ...);
+  int (*stack_getbounds)();
+  char *(*strchr)(const char *name, int c);
+  int (*strcmp)(const char *s1, const char *s2);
+  int (*strcpy)(const char *s1, const char *s2);
+  char *(*libc_strdup)(const char *s1); // Don't use "strdup" because it is a macro in gcc
+  char *(*strerror)(int errnum);
+  int (*strerror_r)(int errnum, char *strerrbuf, size_t buflen);
+  size_t (*strlcat)(char *dest, const char *src, size_t dstsize);
+  size_t (*strlcpy)(char *dest, const char *src, size_t dstsize);
+  size_t (*strlen)(const char *string);
+  int (*strncmp)(const char *s1, const char *s2, size_t n);
+  size_t (*strncpy)(char *dst, const char *src, size_t dstsize);
+  size_t (*strspn)(const char *s1, const char *s2);
+  char *(*strrchr)(const char *name, int c);
+  char *(*strstr)(const char *s1, const char *s2);
+  long int (*strtol)(const char *nptr, char **endptr, int base);
+  long long int (*strtoll)(const char *nptr, char **endptr, int base);
+  unsigned long int (*strtoul)(const char *nptr, char **endptr, int base);
+  unsigned long long int (*strtoull)(const char *nptr, char **endptr, int base);
+  int (*symlink)(const char *s1, const char *s2);
+  int (*syscall)(int number, ...);
+  long (*sysconf)(int name);
+  long (*sysinfo)(int command, char *buf, long count);
+  time_t (*time)(time_t *tloc);
+  int (*unsetenv)(const char *name);
+  int (*vsnprintf)(char *str, size_t size, const char *format, va_list ap);
+  pid_t (*waitpid)(pid_t pid, int *stat_loc, int options);
+  ssize_t (*write)();
+  double (*atof)();
+  void *n_a;
+} CollectorUtilFuncs;
+
+extern CollectorUtilFuncs __collector_util_funcs;
+extern int __collector_dlsym_guard;
+
+#define CALL_UTIL(x) __collector_util_funcs.x
+
+/* The following constants define the meaning of the "void *arg"
+ * argument of getFrameInfo().
+ */
+/* arg is a pointer to ucontext_t, walk the stack described by it */
+#define FRINFO_FROM_UC          1
+/* walk the current stack starting from the frame containing arg */
+#define FRINFO_FROM_STACK       2
+/* walk the current stack starting from the caller of the frame containing arg */
+#define FRINFO_FROM_STACK_ARG   3
+/* arg is a pc, process a stack containing just that pc */
+#define FRINFO_FROM_PC          4
+/* arg is of type CM_Array describing a stack image */
+#define FRINFO_FROM_ARRAY       5
+#define FRINFO_NO_OMP_INFO      0x80000000
+#define FRINFO_NO_WALK          0x40000000
+
+typedef struct CM_Array
+{
+  unsigned int length;          /* in bytes, not including length */
+  void *bytes;
+} CM_Array;
+
+// Interface with libcollector.so:
+typedef enum
+{
+  SP_ORIGIN_FORK        = -1,
+  SP_ORIGIN_LIBCOL_INIT = 0,
+  SP_ORIGIN_DBX_ATTACH  = 1,
+  SP_ORIGIN_GENEXP      = 2,
+  SP_ORIGIN_KERNEL      = 3,
+  SP_ORIGIN_DTRACE      = 4,
+  SP_ORIGIN_COLLECT     = 5
+} sp_origin_t;
+
+struct Heap;
+struct Common_packet;
+struct CM_Packet;
+struct ModuleInterface;
+
+typedef long long HiResTime;
+typedef int CollectorModule;
+typedef unsigned long long FrameInfo;
+typedef struct CollectorInterface
+{
+  /* General services */
+  CollectorModule (*registerModule)(struct ModuleInterface*);
+  const char *(*getParams)();
+  const char *(*getExpDir)();
+  int (*writeLog)(char *format, ...);
+  FrameInfo (*getFrameInfo)(CollectorModule modl, HiResTime ts, int mode, void *arg);
+  FrameInfo (*getUID)(CM_Array *arg);
+  FrameInfo (*getUID2)(CM_Array *arg, FrameInfo uid);
+  int (*getStackTrace)(void *buf, int size, void *bptr, void *eptr, void *arg);
+  int (*writeMetaData)(CollectorModule modl, char *format, ...);
+
+  /* writeDataRecord ensures that the header is filled in, and then calls writeDataPacket */
+  int (*writeDataRecord)(CollectorModule modl, struct Common_packet *pckt);
+  int (*writeDataPacket)(CollectorModule modl, struct CM_Packet *pckt);
+  void (*write_sample)(char *name);
+  void (*get_progspec)(char *retstr, int tmp_sz, char *namestr, int name_sz);
+  int (*open_experiment)(const char *exp, const char *params, sp_origin_t origin);
+  HiResTime (*getHiResTime)();
+
+  /* Dynamic memory allocation service */
+  struct Heap *(*newHeap)();
+  void (*deleteHeap)(struct Heap *heap);
+  void *(*allocCSize)(struct Heap *heap, unsigned sz, int log);
+  void (*freeCSize)(struct Heap *heap, void *ptr, unsigned sz);
+  void *(*allocVSize)(struct Heap *heap, unsigned sz);
+  void *(*reallocVSize)(struct Heap *heap, void *ptr, unsigned newsz);
+
+  /* Thread specific data service */
+  unsigned (*createKey)(size_t sz, void (*init)(void*), void (*fini)(void*));
+  void *(*getKey)(unsigned key);
+
+  /* Debugging services */
+  void (*writeDebugInfo)(int, int, char *, ...) __attribute__ ((format (printf, 3, 4)));
+} CollectorInterface;
+
+typedef struct ModuleInterface
+{
+  char *description;
+  int (*initInterface)(CollectorInterface*);
+  int (*openExperiment)(const char *);
+  int (*startDataCollection)();
+  int (*stopDataCollection)();
+  int (*closeExperiment)();
+  int (*detachExperiment)(); /* called from fork-child before openExperiment() */
+} ModuleInterface;
+
+typedef CollectorModule (*RegModuleFunc)(ModuleInterface*);
+typedef void (*ModuleInitFunc)(CollectorInterface*);
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+  CollectorModule __collector_register_module (ModuleInterface *modint);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _COLLECTOR_MODULE_H */
diff --git a/gprofng/src/comp_com.c b/gprofng/src/comp_com.c
new file mode 100644 (file)
index 0000000..486bd1a
--- /dev/null
@@ -0,0 +1,3481 @@
+/* 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <values.h>
+#include <assert.h>
+
+#include "comp_com.h"
+
+/*
+ * To add a new message _FORMAT_ please perform the following tasks:
+ * 1) Insert it into the list below, with the matching comment.
+ *    The table is sorted by parameter type.  In increasing order
+ *    they are: String, Procedure, Variable, Loop, Region, Integer.
+ * 2) Insert the corresponding information into the following
+ *    procedures in this file: ccm_num_params(), ccm_paramlist_index(),
+ *    ccm_param_primtype(), and ccm_param_hightype().
+ * 3) If you are also creating a new high-type or primitive-type,
+ *    extend the corresponding enum, update this comment and make sure
+ *    to update any code in the analyzer, iropt, cg or ube that depends
+ *    on knowing the limited set of types.
+ */
+
+typedef enum ccm_fmt {
+    CCMFMT_NONE,               /* none */
+    CCMFMT_S1,                 /* s1 */
+    CCMFMT_S1S2,               /* s1, s2 */
+    CCMFMT_S1L2,               /* s1, l2 */
+    CCMFMT_S1L2VV3,            /* s1, l2, v3, v4, ... */
+    CCMFMT_S1R2VV3,            /* s1, r2, v3, v4, ... */
+    CCMFMT_S1X2,               /* s1, x2 */
+    CCMFMT_P1,                 /* p1 */
+    CCMFMT_P1S2,               /* p1, s2 */
+    CCMFMT_P1S2P3,             /* p1, s2, p3 */
+    CCMFMT_P1S2P3I4,           /* p1, s2, p3, i4 */
+    CCMFMT_P1S2I3,             /* p1, s2, i3 */
+    CCMFMT_P1P2,               /* p1, p2 */
+    CCMFMT_P1L2,               /* p1, l2 */
+    CCMFMT_P1I2,               /* p1, i2 */
+    CCMFMT_P1I2L3,             /* p1, i2, l3 */
+    CCMFMT_P1I2LL3,            /* p1, i2, l3, l4 ... */
+    CCMFMT_P1I2I3,             /* p1, i2, i3 */
+    CCMFMT_PP1,                        /* p1, p2, ... */
+    CCMFMT_V1,                 /* v1 */
+    CCMFMT_V1V2,               /* v1, v2 */
+    CCMFMT_V1L2,               /* v1, l2 */
+    CCMFMT_VV1,                        /* v1, v2, ... */
+    CCMFMT_L1,                 /* l1 */
+    CCMFMT_L1S2,               /* l1, s2 */
+    CCMFMT_L1S2L3,             /* l1, s2, l3 */
+    CCMFMT_L1P2,               /* l1, p2 */
+    CCMFMT_L1P2I3,             /* l1, p2, i3 */
+    CCMFMT_L1PP2,              /* l1, p2, p3, ... */
+    CCMFMT_L1VV2,              /* l1, v2, v3, ... */
+    CCMFMT_L1L2,               /* l1, l2 */
+    CCMFMT_L1L2L3,             /* l1, l2, l3 */
+    CCMFMT_LL1,                        /* l1, l2, ... */
+    CCMFMT_L1R2,               /* l1, r2 */
+    CCMFMT_L1I2,               /* l1, i2 */
+    CCMFMT_L1I2L3,             /* l1, i2, l3 */
+    CCMFMT_L1I2LL3,            /* l1, i2, l3, l4, ... */
+    CCMFMT_L1I2I3L4,           /* l1, i2, i3, l4 */
+    CCMFMT_L1I2I3I4I5,         /* l1, i2, ..., i5 */
+    CCMFMT_L1I2I3I4I5I6I7,     /* l1, i2, ..., i7 */
+    CCMFMT_L1I2I3I4I5I6I7I8I9, /* l1, i2, ..., i9 */
+    CCMFMT_L1II2,              /* l1, i2, i3, ... */
+    CCMFMT_R1,                 /* r1 */
+    CCMFMT_R1VV2,              /* r1, v2, v3, ... */
+    CCMFMT_I1,                 /* i1 */
+    CCMFMT_I1P2I3,             /* i1, p2, i3 */
+    CCMFMT_I1V2,               /* i1, v2 */
+    CCMFMT_I1V2V3,             /* i1, v2, v3 */
+    CCMFMT_I1L2,               /* i1, l2 */
+    CCMFMT_I1LL2,              /* i1, l2, l3, ... */
+    CCMFMT_I1I2I3I4,           /* i1, i2, i3, i4 */
+    CCMFMT_I1I2I3I4I5I6,       /* i1, i2, ..., i6 */
+    CCMFMT_I1I2I3I4I5I6I7I8,   /* i1, i2, ..., i8 */
+    CCMFMT_LAST
+} Ccm_Fmttype_t;
+
+/*
+ * Low- and high-level types for commentary parameters.
+ */
+
+typedef enum ccm_primtype
+{
+  CCM_PRIMTYPE_NONE,
+  CCM_PRIMTYPE_STRING,
+  CCM_PRIMTYPE_INTEGER,
+  CCM_PRIMTYPE_HEXSTRING
+} Ccm_Primtype_t;
+
+typedef enum ccm_hightype
+{
+  CCM_HITYPE_NONE,
+  CCM_HITYPE_STRING,
+  CCM_HITYPE_PROCEDURE,
+  CCM_HITYPE_VARIABLE,
+  CCM_HITYPE_LOOPTAG,
+  CCM_HITYPE_REGIONTAG,
+  CCM_HITYPE_HEXSTRING,
+  CCM_HITYPE_INTEGER
+} Ccm_Hitype_t;
+
+typedef struct ccm_attrs
+{
+  char *msg;            /* I18N msg string */
+  const char *name;     /* Print name for this message ID */
+  int32_t vis;          /* Visibility bits */
+  Ccm_Fmttype_t fmt;    /* Format type */
+} Ccm_Attr_t;
+
+static Ccm_Attr_t *ccm_attrs;            /* Table of per-msg attributes */
+static nl_catd ccm_catd = (nl_catd) - 1; /* messages id */
+
+/*
+ * map COMPMSG_ID to table indices
+ */
+static int
+ccm_vis_index (COMPMSG_ID m)
+{
+  int32_t high = m >> 8;
+  int32_t low = m & 0xFF;
+  for (int i = 0; i < 24; i++, high >>= 1)
+    if (high <= 1)
+      return (i << 8) + low + 1;
+  return 0;
+}
+
+/*
+ * Return # parameters for this message; MAXINT for messages with
+ * parameter lists.
+ */
+static int
+ccm_num_params (COMPMSG_ID m)
+{
+  int vindex;
+  int res;
+  vindex = ccm_vis_index (m);
+  switch (ccm_attrs[vindex].fmt)
+    {
+    case CCMFMT_NONE:
+      res = 0;
+      break;
+    case CCMFMT_S1:
+    case CCMFMT_P1:
+    case CCMFMT_V1:
+    case CCMFMT_L1:
+    case CCMFMT_R1:
+    case CCMFMT_I1:
+      res = 1;
+      break;
+    case CCMFMT_S1S2:
+    case CCMFMT_S1L2:
+    case CCMFMT_S1X2:
+    case CCMFMT_P1S2:
+    case CCMFMT_P1P2:
+    case CCMFMT_P1L2:
+    case CCMFMT_P1I2:
+    case CCMFMT_V1V2:
+    case CCMFMT_V1L2:
+    case CCMFMT_L1S2:
+    case CCMFMT_L1P2:
+    case CCMFMT_L1L2:
+    case CCMFMT_L1R2:
+    case CCMFMT_L1I2:
+    case CCMFMT_I1V2:
+    case CCMFMT_I1L2:
+      res = 2;
+      break;
+    case CCMFMT_P1S2P3:
+    case CCMFMT_P1S2I3:
+    case CCMFMT_P1I2L3:
+    case CCMFMT_P1I2I3:
+    case CCMFMT_L1S2L3:
+    case CCMFMT_L1P2I3:
+    case CCMFMT_L1L2L3:
+    case CCMFMT_L1I2L3:
+    case CCMFMT_I1P2I3:
+    case CCMFMT_I1V2V3:
+      res = 3;
+      break;
+    case CCMFMT_P1S2P3I4:
+    case CCMFMT_L1I2I3L4:
+    case CCMFMT_I1I2I3I4:
+      res = 4;
+      break;
+    case CCMFMT_L1I2I3I4I5:
+      res = 5;
+      break;
+    case CCMFMT_I1I2I3I4I5I6:
+      res = 6;
+      break;
+    case CCMFMT_L1I2I3I4I5I6I7:
+      res = 7;
+      break;
+    case CCMFMT_I1I2I3I4I5I6I7I8:
+      res = 8;
+      break;
+    case CCMFMT_L1I2I3I4I5I6I7I8I9:
+      res = 9;
+      break;
+    case CCMFMT_S1L2VV3:
+    case CCMFMT_S1R2VV3:
+    case CCMFMT_PP1:
+    case CCMFMT_P1I2LL3:
+    case CCMFMT_VV1:
+    case CCMFMT_L1PP2:
+    case CCMFMT_L1VV2:
+    case CCMFMT_LL1:
+    case CCMFMT_L1I2LL3:
+    case CCMFMT_L1II2:
+    case CCMFMT_R1VV2:
+    case CCMFMT_I1LL2:
+      res = MAXINT;
+      break;
+    case CCMFMT_LAST:
+    default:
+      /* programming failure */
+      /* if(1) is hack to get around warning from C++ compiler */
+      if (1) assert (0);
+      break;
+    }
+  return res;
+}
+
+static int
+ccm_paramlist_index (COMPMSG_ID m)
+{
+  int res;
+  int vindex = ccm_vis_index (m);
+  switch (ccm_attrs[vindex].fmt)
+    {
+    case CCMFMT_NONE:
+    case CCMFMT_S1:
+    case CCMFMT_S1S2:
+    case CCMFMT_S1L2:
+    case CCMFMT_S1X2:
+    case CCMFMT_P1:
+    case CCMFMT_P1S2:
+    case CCMFMT_P1S2P3:
+    case CCMFMT_P1S2P3I4:
+    case CCMFMT_P1S2I3:
+    case CCMFMT_P1P2:
+    case CCMFMT_P1L2:
+    case CCMFMT_P1I2:
+    case CCMFMT_P1I2L3:
+    case CCMFMT_P1I2I3:
+    case CCMFMT_V1:
+    case CCMFMT_V1V2:
+    case CCMFMT_V1L2:
+    case CCMFMT_L1:
+    case CCMFMT_L1S2:
+    case CCMFMT_L1S2L3:
+    case CCMFMT_L1P2:
+    case CCMFMT_L1P2I3:
+    case CCMFMT_L1L2:
+    case CCMFMT_L1L2L3:
+    case CCMFMT_L1R2:
+    case CCMFMT_L1I2:
+    case CCMFMT_L1I2L3:
+    case CCMFMT_L1I2I3L4:
+    case CCMFMT_L1I2I3I4I5:
+    case CCMFMT_L1I2I3I4I5I6I7:
+    case CCMFMT_L1I2I3I4I5I6I7I8I9:
+    case CCMFMT_R1:
+    case CCMFMT_I1:
+    case CCMFMT_I1P2I3:
+    case CCMFMT_I1V2:
+    case CCMFMT_I1V2V3:
+    case CCMFMT_I1L2:
+    case CCMFMT_I1I2I3I4:
+    case CCMFMT_I1I2I3I4I5I6:
+    case CCMFMT_I1I2I3I4I5I6I7I8:
+      res = 0;
+      break;
+    case CCMFMT_PP1:
+    case CCMFMT_VV1:
+    case CCMFMT_LL1:
+      res = 1;
+      break;
+    case CCMFMT_L1PP2:
+    case CCMFMT_L1VV2:
+    case CCMFMT_L1II2:
+    case CCMFMT_R1VV2:
+    case CCMFMT_I1LL2:
+      res = 2;
+      break;
+    case CCMFMT_S1L2VV3:
+    case CCMFMT_S1R2VV3:
+    case CCMFMT_P1I2LL3:
+    case CCMFMT_L1I2LL3:
+      res = 3;
+      break;
+    case CCMFMT_LAST:
+    default:
+      /* programming failure */
+      /* if(1) is hack to get around warning from C++ compiler */
+      if (1) assert (0);
+      break;
+    }
+  return res;
+}
+
+static Ccm_Primtype_t
+ccm_param_primtype (COMPMSG_ID m, int param_idx)
+{
+  int vindex;
+  Ccm_Primtype_t res;
+  if (param_idx <= 0 || param_idx > ccm_num_params (m))
+    return CCM_PRIMTYPE_NONE;
+
+  res = CCM_PRIMTYPE_NONE; /* should always be updated */
+  vindex = ccm_vis_index (m);
+  switch (ccm_attrs[vindex].fmt)
+    {
+      /*
+       * Sort cases by:
+       * 1) # parameters
+       * 2) Strings before Integers
+       * 3) Enum tags
+       */
+    case CCMFMT_NONE:
+      /* programming failure */
+      /* if(1) is hack to get around warning from C++ compiler */
+      if (1)
+       assert (0);
+      break;
+    case CCMFMT_S1:
+    case CCMFMT_P1:
+    case CCMFMT_V1:
+    case CCMFMT_L1:
+    case CCMFMT_R1:
+      if (param_idx == 1)
+       res = CCM_PRIMTYPE_STRING;
+      break;
+    case CCMFMT_I1:
+      if (param_idx == 1)
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+    case CCMFMT_S1S2:
+    case CCMFMT_S1L2:
+    case CCMFMT_P1S2:
+    case CCMFMT_P1P2:
+    case CCMFMT_P1L2:
+    case CCMFMT_V1V2:
+    case CCMFMT_V1L2:
+    case CCMFMT_L1S2:
+    case CCMFMT_L1P2:
+    case CCMFMT_L1L2:
+    case CCMFMT_L1R2:
+      if (param_idx == 1 || param_idx == 2)
+       res = CCM_PRIMTYPE_STRING;
+      break;
+    case CCMFMT_S1X2:
+      if (param_idx == 1)
+       res = CCM_PRIMTYPE_STRING;
+      else if (param_idx == 2)
+       res = CCM_PRIMTYPE_HEXSTRING;
+      break;
+    case CCMFMT_P1I2:
+    case CCMFMT_L1I2:
+      if (param_idx == 1)
+       res = CCM_PRIMTYPE_STRING;
+      else if (param_idx == 2)
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+    case CCMFMT_I1V2:
+    case CCMFMT_I1L2:
+      if (param_idx == 1)
+       res = CCM_PRIMTYPE_INTEGER;
+      else if (param_idx == 2)
+       res = CCM_PRIMTYPE_STRING;
+      break;
+    case CCMFMT_P1S2P3:
+    case CCMFMT_L1S2L3:
+    case CCMFMT_L1L2L3:
+      if (param_idx >= 1 && param_idx <= 3)
+       res = CCM_PRIMTYPE_STRING;
+      break;
+    case CCMFMT_P1S2I3:
+    case CCMFMT_L1P2I3:
+      if (param_idx == 1 || param_idx == 2)
+       res = CCM_PRIMTYPE_STRING;
+      else if (param_idx == 3)
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+    case CCMFMT_P1I2L3:
+    case CCMFMT_L1I2L3:
+      if (param_idx == 1 || param_idx == 3)
+       res = CCM_PRIMTYPE_STRING;
+      else if (param_idx == 2)
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+   case CCMFMT_P1I2I3:
+      if (param_idx == 1)
+       res = CCM_PRIMTYPE_STRING;
+      else if (param_idx == 2  || param_idx == 3)
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+    case CCMFMT_I1V2V3:
+      if (param_idx == 1)
+       res = CCM_PRIMTYPE_INTEGER;
+      else if (param_idx == 2 || param_idx == 3)
+       res = CCM_PRIMTYPE_STRING;
+      break;
+    case CCMFMT_I1P2I3:
+      if (param_idx == 1 || param_idx == 3)
+       res = CCM_PRIMTYPE_INTEGER;
+      else if (param_idx == 2)
+       res = CCM_PRIMTYPE_STRING;
+      break;
+    case CCMFMT_L1I2I3L4:
+      if (param_idx == 1 || param_idx == 4)
+       res = CCM_PRIMTYPE_STRING;
+      else if (param_idx == 2 || param_idx == 3)
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+    case CCMFMT_P1S2P3I4:
+      if (param_idx >= 1 && param_idx <= 3)
+       res = CCM_PRIMTYPE_STRING;
+      else if (param_idx == 4)
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+    case CCMFMT_I1I2I3I4:
+      if (param_idx >= 1 && param_idx <= 4)
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+    case CCMFMT_L1I2I3I4I5:
+      if (param_idx == 1)
+       res = CCM_PRIMTYPE_STRING;
+      else if (param_idx >= 2 && param_idx <= 5)
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+    case CCMFMT_I1I2I3I4I5I6:
+      if (param_idx >= 1 && param_idx <= 6)
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+    case CCMFMT_L1I2I3I4I5I6I7:
+      if (param_idx == 1)
+       res = CCM_PRIMTYPE_STRING;
+      else if (param_idx >= 2 && param_idx <= 7)
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+    case CCMFMT_I1I2I3I4I5I6I7I8:
+      if (param_idx >= 1 && param_idx <= 8)
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+    case CCMFMT_L1I2I3I4I5I6I7I8I9:
+      if (param_idx == 1)
+       res = CCM_PRIMTYPE_STRING;
+      else if (param_idx >= 2 && param_idx <= 9)
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+    case CCMFMT_S1L2VV3:
+    case CCMFMT_S1R2VV3:
+    case CCMFMT_PP1:
+    case CCMFMT_VV1:
+    case CCMFMT_L1PP2:
+    case CCMFMT_L1VV2:
+    case CCMFMT_LL1:
+    case CCMFMT_R1VV2:
+      res = CCM_PRIMTYPE_STRING;
+      break;
+    case CCMFMT_P1I2LL3:
+    case CCMFMT_L1I2LL3:
+      if (param_idx == 2)
+       res = CCM_PRIMTYPE_INTEGER;
+      else
+       res = CCM_PRIMTYPE_STRING;
+      break;
+    case CCMFMT_L1II2:
+      if (param_idx == 1)
+       res = CCM_PRIMTYPE_STRING;
+      else
+       res = CCM_PRIMTYPE_INTEGER;
+      break;
+    case CCMFMT_I1LL2:
+      if (param_idx == 1)
+       res = CCM_PRIMTYPE_INTEGER;
+      else
+       res = CCM_PRIMTYPE_STRING;
+      break;
+    case CCMFMT_LAST:
+    default:
+      /* programming failure */
+      /* if(1) is hack to get around warning from C++ compiler */
+      if (1)
+       assert (0);
+      break;
+    }
+  return res;
+}
+
+static Ccm_Hitype_t
+ccm_param_hightype (COMPMSG_ID m, int param_idx)
+{
+  int vindex;
+  Ccm_Hitype_t res;
+
+  if (param_idx <= 0 || param_idx > ccm_num_params (m))
+    return CCM_HITYPE_NONE;
+  res = CCM_HITYPE_NONE; /* should always be updated */
+  vindex = ccm_vis_index (m);
+  switch (ccm_attrs[vindex].fmt)
+    {
+    case CCMFMT_NONE:
+      /* programming failure */
+      /* if(1) is hack to get around warning from C++ compiler */
+      if (1)
+       assert (0);
+      break;
+    case CCMFMT_S1:
+      if (param_idx == 1)
+       res = CCM_HITYPE_STRING;
+      break;
+    case CCMFMT_S1S2:
+      if (param_idx == 1 || param_idx == 2)
+       res = CCM_HITYPE_STRING;
+      break;
+    case CCMFMT_S1L2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_STRING;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_LOOPTAG;
+      break;
+    case CCMFMT_S1L2VV3:
+      if (param_idx == 1)
+       res = CCM_HITYPE_STRING;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_LOOPTAG;
+      else
+       res = CCM_HITYPE_STRING;
+      break;
+    case CCMFMT_S1R2VV3:
+      if (param_idx == 1)
+       res = CCM_HITYPE_STRING;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_REGIONTAG;
+      else
+       res = CCM_HITYPE_VARIABLE;
+      break;
+    case CCMFMT_S1X2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_STRING;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_HEXSTRING;
+      break;
+    case CCMFMT_P1:
+      if (param_idx == 1)
+       res = CCM_HITYPE_PROCEDURE;
+      break;
+    case CCMFMT_P1S2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_PROCEDURE;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_STRING;
+      break;
+    case CCMFMT_P1S2P3:
+      if (param_idx == 1 || param_idx == 3)
+       res = CCM_HITYPE_PROCEDURE;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_STRING;
+      break;
+    case CCMFMT_P1S2P3I4:
+      if (param_idx == 1 || param_idx == 3)
+       res = CCM_HITYPE_PROCEDURE;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_STRING;
+      else if (param_idx == 4)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_P1S2I3:
+      if (param_idx == 1)
+       res = CCM_HITYPE_PROCEDURE;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_STRING;
+      else if (param_idx == 3)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_P1P2:
+      if (param_idx == 1 || param_idx == 2)
+       res = CCM_HITYPE_PROCEDURE;
+      break;
+    case CCMFMT_P1L2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_PROCEDURE;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_LOOPTAG;
+      break;
+    case CCMFMT_P1I2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_PROCEDURE;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_P1I2L3:
+      if (param_idx == 1)
+       res = CCM_HITYPE_PROCEDURE;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_INTEGER;
+      else if (param_idx == 3)
+       res = CCM_HITYPE_LOOPTAG;
+      break;
+    case CCMFMT_P1I2I3:
+      if (param_idx == 1)
+       res = CCM_HITYPE_PROCEDURE;
+      else if (param_idx == 2 || param_idx == 3)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_P1I2LL3:
+      if (param_idx == 1)
+       res = CCM_HITYPE_PROCEDURE;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_INTEGER;
+      else
+       res = CCM_HITYPE_LOOPTAG;
+      break;
+    case CCMFMT_PP1:
+      res = CCM_HITYPE_PROCEDURE;
+      break;
+    case CCMFMT_V1:
+      if (param_idx == 1)
+       res = CCM_HITYPE_VARIABLE;
+      break;
+    case CCMFMT_V1V2:
+      if (param_idx == 1 || param_idx == 2)
+       res = CCM_HITYPE_VARIABLE;
+      break;
+    case CCMFMT_V1L2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_VARIABLE;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_LOOPTAG;
+      break;
+    case CCMFMT_VV1:
+      res = CCM_HITYPE_VARIABLE;
+      break;
+    case CCMFMT_L1:
+      if (param_idx == 1)
+       res = CCM_HITYPE_LOOPTAG;
+      break;
+    case CCMFMT_L1S2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_LOOPTAG;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_STRING;
+      break;
+    case CCMFMT_L1S2L3:
+      if (param_idx == 1 || param_idx == 3)
+       res = CCM_HITYPE_LOOPTAG;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_STRING;
+      break;
+    case CCMFMT_L1P2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_LOOPTAG;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_PROCEDURE;
+      break;
+    case CCMFMT_L1P2I3:
+      if (param_idx == 1)
+       res = CCM_HITYPE_LOOPTAG;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_PROCEDURE;
+      else if (param_idx == 3)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_L1PP2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_LOOPTAG;
+      else
+       res = CCM_HITYPE_PROCEDURE;
+      break;
+    case CCMFMT_L1VV2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_LOOPTAG;
+      else
+       res = CCM_HITYPE_VARIABLE;
+      break;
+    case CCMFMT_L1L2:
+      if (param_idx == 1 || param_idx == 2)
+       res = CCM_HITYPE_LOOPTAG;
+      break;
+    case CCMFMT_L1L2L3:
+      if (param_idx >= 1 && param_idx <= 3)
+       res = CCM_HITYPE_LOOPTAG;
+      break;
+    case CCMFMT_LL1:
+      res = CCM_HITYPE_LOOPTAG;
+      break;
+    case CCMFMT_L1R2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_LOOPTAG;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_REGIONTAG;
+      break;
+    case CCMFMT_L1I2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_LOOPTAG;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_L1I2L3:
+      if (param_idx == 1 || param_idx == 3)
+       res = CCM_HITYPE_LOOPTAG;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_L1I2LL3:
+      if (param_idx == 2)
+       res = CCM_HITYPE_INTEGER;
+      else
+       res = CCM_HITYPE_LOOPTAG;
+      break;
+    case CCMFMT_L1I2I3L4:
+      if (param_idx == 1 || param_idx == 4)
+       res = CCM_HITYPE_LOOPTAG;
+      else if (param_idx == 2 || param_idx == 3)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_L1I2I3I4I5:
+      if (param_idx == 1)
+       res = CCM_HITYPE_LOOPTAG;
+      else if (param_idx >= 2 && param_idx <= 5)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_L1I2I3I4I5I6I7:
+      if (param_idx == 1)
+       res = CCM_HITYPE_LOOPTAG;
+      else if (param_idx >= 2 && param_idx <= 7)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_L1I2I3I4I5I6I7I8I9:
+      if (param_idx == 1)
+       res = CCM_HITYPE_LOOPTAG;
+      else if (param_idx >= 2 && param_idx <= 9)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_L1II2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_LOOPTAG;
+      else
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_R1:
+      if (param_idx == 1)
+       res = CCM_HITYPE_REGIONTAG;
+      break;
+    case CCMFMT_R1VV2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_REGIONTAG;
+      else
+       res = CCM_HITYPE_VARIABLE;
+      break;
+    case CCMFMT_I1:
+      if (param_idx == 1)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_I1P2I3:
+      if (param_idx == 1 || param_idx == 3)
+       res = CCM_HITYPE_INTEGER;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_PROCEDURE;
+      break;
+    case CCMFMT_I1V2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_INTEGER;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_VARIABLE;
+      break;
+    case CCMFMT_I1V2V3:
+      if (param_idx == 1)
+       res = CCM_HITYPE_INTEGER;
+      else if (param_idx == 2 || param_idx == 3)
+       res = CCM_HITYPE_VARIABLE;
+      break;
+    case CCMFMT_I1L2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_INTEGER;
+      else if (param_idx == 2)
+       res = CCM_HITYPE_LOOPTAG;
+      break;
+    case CCMFMT_I1LL2:
+      if (param_idx == 1)
+       res = CCM_HITYPE_INTEGER;
+      else
+       res = CCM_HITYPE_LOOPTAG;
+      break;
+    case CCMFMT_I1I2I3I4:
+      if (param_idx >= 1 && param_idx <= 4)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_I1I2I3I4I5I6:
+      if (param_idx >= 1 && param_idx <= 6)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_I1I2I3I4I5I6I7I8:
+      if (param_idx >= 1 && param_idx <= 8)
+       res = CCM_HITYPE_INTEGER;
+      break;
+    case CCMFMT_LAST:
+    default:
+      /* programming failure */
+      /* if(1) is hack to get around warning from C++ compiler */
+      if (1)
+       assert (0);
+      break;
+    }
+  return res;
+}
+
+static void
+ccm_vis_init ()
+{
+  int size, vindex;
+  static int done = 0;
+  if (done)
+    return;
+  done = 1;
+  size = ccm_vis_index ((COMPMSG_ID) (CCMV_BASIC << 8));
+  ccm_attrs = (Ccm_Attr_t *) calloc (size, sizeof (Ccm_Attr_t));
+  if (ccm_attrs == NULL)
+    exit (1);
+  vindex = ccm_vis_index (CCM_MODDATE);
+  ccm_attrs[vindex].vis = CCMV_VER | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_MODDATE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Source file %s, last modified on date %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1S2;
+
+  vindex = ccm_vis_index (CCM_COMPVER);
+  ccm_attrs[vindex].vis = CCMV_VER | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_COMPVER";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Component %s, version %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1S2;
+
+  vindex = ccm_vis_index (CCM_COMPDATE);
+  ccm_attrs[vindex].vis = CCMV_VER | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_COMPDATE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Compilation date %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_COMPOPT);
+  ccm_attrs[vindex].vis = CCMV_VER | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_COMPOPT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Compilation options %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_ACOMPOPT);
+  ccm_attrs[vindex].vis = CCMV_VER | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_ACOMPOPT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Actual Compilation options %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_VAR_ALIAS);
+  ccm_attrs[vindex].vis = CCMV_WARN | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_VAR_ALIAS";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variable %s aliased to %s");
+  ccm_attrs[vindex].fmt = CCMFMT_V1V2;
+
+  vindex = ccm_vis_index (CCM_FBIRDIFF);
+  ccm_attrs[vindex].vis = CCMV_WARN | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_FBIRDIFF";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Profile feedback data inconsistent with"
+                                  " intermediate representation file; check compiler"
+                                  " version, flags and source file");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_OPTRED_SWAP);
+  ccm_attrs[vindex].vis = CCMV_WARN | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_OPTRED_SWAP";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Optimization level for %s reduced from %d to"
+                                  " %d due to insufficient swap space");
+  ccm_attrs[vindex].fmt = CCMFMT_P1I2I3;
+
+  vindex = ccm_vis_index (CCM_OPTRED_CPLX);
+  ccm_attrs[vindex].vis = CCMV_WARN | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_OPTRED_CPLX";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Optimization level for %s reduced from %d to"
+                                  " %d due to program complexity");
+  ccm_attrs[vindex].fmt = CCMFMT_P1I2I3;
+
+  vindex = ccm_vis_index (CCM_UNKNOWN);
+  ccm_attrs[vindex].vis = CCMV_WARN | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNKNOWN";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Unexpected compiler comment %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_CALL);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_CALL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below not parallelized because it contains a"
+                                  " call to %s");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_PAR_SER);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_PAR_SER";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Both serial and parallel versions generated for"
+                                  " loop below");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_PAR_SER_VER);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_PAR_SER_VER";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Both serial and parallel versions generated for"
+                                  " loop below; with parallel version used if %s,"
+                                  " serial otherwise");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_PAR_DRECTV);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_PAR_DRECTV";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below parallelized by explicit user"
+                                  " directive");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_APAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_APAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below autoparallelized");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_AUTOPAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_AUTOPAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below autoparallelized; equivalent"
+                                  " explict directive is %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_DD);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_DD";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below could not be parallelized because of a"
+                                  " data dependency on %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_DDA);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_DDA";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below could not be parallelized because of a"
+                                  " data dependency or aliasing of %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_ANONDD);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_ANONDD";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below could not be parallelized because of"
+                                  " an anonymous data dependency");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_UNPAR_ANONDDA);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_ANONDDA";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below could not be parallelized because of"
+                                  " an anonymous data dependency or aliasing");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_PAR_WORK);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_PAR_WORK";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below parallelized, but might not contain"
+                                  " enough work to be efficiently run in parallel");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_UNPAR_EXIT);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_EXIT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below not parallelized because it contains"
+                                  " multiple exit points");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_UNPAR_STRNG);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_STRNG";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below not parallelized because it contains a"
+                                  " strange flow of control");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_UNPAR_IO);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_IO";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below not parallelized because it contains"
+                                  " I/O or other MT-unsafe calls");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_PAR_BODY_NAME);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_PAR_BODY_NAME";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Parallel loop-body code is in function %s");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_NLOOPIDX);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_NLOOPIDX";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below not parallelized because loop index"
+                                  " not found");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_UNPAR_DRECTV);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_DRECTV";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below not parallelized because of explicit"
+                                  " user directive");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_UNPAR_NOTPROFIT);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_NOTPROFIT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below not parallelized because it was not"
+                                  " profitable to do so");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_UNPAR_NEST);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_NEST";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below not parallelized because it was"
+                                  " nested in a parallel loop");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_UNPAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below not parallelized");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_UNPAR_NOAUTO);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_NOAUTO";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below not parallelized because"
+                                  " autoparallelization is not enabled");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_PR_L_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_PR_L_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Private variables in loop below:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_SH_L_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_SH_L_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Shared variables in loop below:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_TP_L_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_TP_L_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Threadprivate variables in loop below:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_RV_L_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_RV_L_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Reduction variables in loop below:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_IM_L_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_IM_L_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Implicit variables in loop below:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_PR_O_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_PR_O_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Private variables in OpenMP construct below:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_SH_O_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_SH_O_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Shared variables in OpenMP construct below:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_TP_O_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_TP_O_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Threadprivate variables in OpenMP construct"
+                                  " below: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_RV_O_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_RV_O_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Reduction variables in OpenMP construct below:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_IM_O_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_IM_O_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Implicit variables in OpenMP construct below:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_IN_OMP);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_IN_OMP";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below not parallelized because it is inside"
+                                  " an OpenMP region");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_FP_O_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_FP_O_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Firstprivate variables in OpenMP construct below:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_LP_O_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LP_O_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Lastprivate variables in OpenMP construct below:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_CP_O_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_CP_O_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Copyprivate variables in OpenMP construct below:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_PR_OAS_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_PR_OAS_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variables autoscoped as PRIVATE in OpenMP"
+                                  " construct below: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_SH_OAS_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_SH_OAS_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variables autoscoped as SHARED in OpenMP"
+                                  " construct below: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_FP_OAS_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_FP_OAS_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variables autoscoped as FIRSTPRIVATE in OpenMP"
+                                  " construct below: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_LP_OAS_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LP_OAS_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variables autoscoped as LASTPRIVATE in OpenMP"
+                                  " construct below: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_RV_OAS_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_RV_OAS_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variables autoscoped as REDUCTION in OpenMP"
+                                  " construct below: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_FAIL_OAS_VAR);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_WARN | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_FAIL_OAS_VAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variables cannot be autoscoped in OpenMP"
+                                  " construct below: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_VV1;
+
+  vindex = ccm_vis_index (CCM_SERIALIZE_OAS);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_WARN | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_SERIALIZE_OAS";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "OpenMP parallel region below is serialized"
+                                  " because autoscoping has failed");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_UNPAR_CALL_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNPAR_CALL_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s not parallelized because it contains calls"
+                                  " to: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1PP2;
+
+  vindex = ccm_vis_index (CCM_PAR_DRECTV_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_PAR_DRECTV_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s parallelized by explicit user directive");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_APAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_APAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s autoparallelized");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_AUTOPAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_AUTOPAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s autoparallelized; equivalent"
+                                  " explict directive is %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1S2;
+
+  vindex = ccm_vis_index (CCM_UNPAR_DD_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNPAR_DD_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be parallelized because of"
+                                  " data dependences on: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1VV2;
+
+  vindex = ccm_vis_index (CCM_UNPAR_DDA_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNPAR_DDA_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be parallelized because of a"
+                                  " data dependence or aliasing of: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1VV2;
+
+  vindex = ccm_vis_index (CCM_UNPAR_ANONDD_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNPAR_ANONDD_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be parallelized because of an"
+                                  " anonymous data dependence");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_ANONDDA_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNPAR_ANONDDA_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be parallelized because of an"
+                                  " anonymous data dependence or aliasing");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_PAR_WORK_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_PAR_WORK_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s parallelized, but might not contain"
+                                  " enough work to run efficiently in parallel");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_EXIT_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNPAR_EXIT_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s not parallelized because it contains"
+                                  " multiple exit points");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_STRANGE_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNPAR_STRANGE_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s not parallelized because it contains a"
+                                  " strange flow of control");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_IO_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNPAR_IO_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s not parallelized because it contains"
+                                  " I/O or other MT-unsafe calls");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_PAR_BODY_NAME_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP;
+  ccm_attrs[vindex].name = "CCM_PAR_BODY_NAME_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s parallel loop-body code placed in"
+                                  " function %s along with %d inner loops");
+  ccm_attrs[vindex].fmt = CCMFMT_L1P2I3;
+
+  vindex = ccm_vis_index (CCM_UNPAR_NLOOPIDX_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNPAR_NLOOPIDX_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s not parallelized because loop index not"
+                                  " found");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_DRECTV_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNPAR_DRECTV_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s not parallelized because of explicit"
+                                  " user directive");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_NOTPROFIT_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNPAR_NOTPROFIT_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s not parallelized because it was not"
+                                  " profitable to do so");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_NEST_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNPAR_NEST_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s not parallelized because it was"
+                                  " nested within a parallel loop");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s not parallelized");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_UNPAR_NOAUTO_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNPAR_NOAUTO_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s not parallelized because"
+                                  " autoparallelization is not enabled");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_PR_L_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_PR_L_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Private variables in %s:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1VV2;
+
+  vindex = ccm_vis_index (CCM_SH_L_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_SH_L_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Shared variables in %s:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1VV2;
+
+  vindex = ccm_vis_index (CCM_TP_L_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_TP_L_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Threadprivate variables in %s:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1VV2;
+
+  vindex = ccm_vis_index (CCM_RV_L_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_RV_L_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Reduction variables of operator %s in %s:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1L2VV3;
+
+  vindex = ccm_vis_index (CCM_IM_L_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_IM_L_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Implicit variables in %s:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1VV2;
+
+  vindex = ccm_vis_index (CCM_PR_O_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_PR_O_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Private variables in %s: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+  vindex = ccm_vis_index (CCM_SH_O_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_SH_O_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Shared variables in %s: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+  vindex = ccm_vis_index (CCM_TP_O_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_TP_O_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Threadprivate variables in %s: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+  vindex = ccm_vis_index (CCM_RV_O_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_RV_O_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Reduction variables of operator %s in %s:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1R2VV3;
+
+  vindex = ccm_vis_index (CCM_IM_O_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_IM_O_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Implicit variables in %s: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+  vindex = ccm_vis_index (CCM_UNPAR_IN_OMP_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNPAR_IN_OMP_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s not parallelized because it is inside"
+                                  " OpenMP region %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1R2;
+
+  vindex = ccm_vis_index (CCM_FP_O_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_FP_O_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Firstprivate variables in %s: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+  vindex = ccm_vis_index (CCM_LP_O_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LP_O_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Lastprivate variables in %s: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+  vindex = ccm_vis_index (CCM_CP_O_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_CP_O_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Copyprivate variables in %s:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+  vindex = ccm_vis_index (CCM_PR_OAS_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_PR_OAS_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variables autoscoped as PRIVATE in %s:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+  vindex = ccm_vis_index (CCM_SH_OAS_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_SH_OAS_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variables autoscoped as SHARED in %s: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+  vindex = ccm_vis_index (CCM_FP_OAS_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_FP_OAS_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variables autoscoped as FIRSTPRIVATE in %s:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+  vindex = ccm_vis_index (CCM_LP_OAS_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LP_OAS_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variables autoscoped as LASTPRIVATE in %s:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+  vindex = ccm_vis_index (CCM_RV_OAS_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_RV_OAS_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variables autoscoped as REDUCTION of operator"
+                                  " %s in %s: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1R2VV3;
+
+  vindex = ccm_vis_index (CCM_FAIL_OAS_VAR_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_WARN;
+  ccm_attrs[vindex].name = "CCM_FAIL_OAS_VAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variables treated as shared because they cannot"
+                                  " be autoscoped in %s: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_R1VV2;
+
+  vindex = ccm_vis_index (CCM_SERIALIZE_OAS_2);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC | CCMV_WARN;
+  ccm_attrs[vindex].name = "CCM_SERIALIZE_OAS_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s will be executed by a single thread because"
+                                  " autoscoping for some variables was not successful");
+  ccm_attrs[vindex].fmt = CCMFMT_R1;
+
+  vindex = ccm_vis_index (CCM_QPERMVEC);
+  ccm_attrs[vindex].vis = CCMV_QUERY | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_QPERMVEC";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Is %s a permutation vector during execution of"
+                                  " %s?");
+  ccm_attrs[vindex].fmt = CCMFMT_V1L2;
+
+  vindex = ccm_vis_index (CCM_QEXPR);
+  ccm_attrs[vindex].vis = CCMV_QUERY | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_QEXPR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Is expression %s true for %s?");
+  ccm_attrs[vindex].fmt = CCMFMT_S1L2;
+
+  vindex = ccm_vis_index (CCM_QSAFECALL);
+  ccm_attrs[vindex].vis = CCMV_QUERY | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_QSAFECALL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Is subroutine %s MP-safe as used in %s?");
+  ccm_attrs[vindex].fmt = CCMFMT_P1L2;
+
+  vindex = ccm_vis_index (CCM_LCOST);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LCOST";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below estimated to cost %d cycles per"
+                                  " iteration");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_UNROLL);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_UNROLL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below unrolled %d times");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_IMIX);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_IMIX";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below has %d loads, %d stores,"
+                                  " %d prefetches, %d FPadds, %d FPmuls, and"
+                                  " %d FPdivs per iteration");
+  ccm_attrs[vindex].fmt = CCMFMT_I1I2I3I4I5I6;
+
+  vindex = ccm_vis_index (CCM_SPILLS);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_UNIMPL | CCMV_WANT | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_SPILLS";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below required %d integer register spills,"
+                                  " %d FP register spills, and used"
+                                  " %d integer registers and %d FP registers");
+  ccm_attrs[vindex].fmt = CCMFMT_I1I2I3I4;
+
+  vindex = ccm_vis_index (CCM_LFISSION);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LFISSION";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below fissioned into %d loops");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_LPEEL);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LPEEL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below had iterations peeled off for better"
+                                  " unrolling and/or parallelization");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_LBLOCKED);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LBLOCKED";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below blocked by %d for improved cache"
+                                  " performance");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_LTILED);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LTILED";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below tiled for better performance");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_LUNRJAM);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LUNRJAM";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below unrolled and jammed");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_LWHILE2DO);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LWHILE2DO";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Bounds test for loop below moved to top of loop");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_L2CALL);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_L2CALL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below replaced by a call to %s");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_LDEAD);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LDEAD";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below deleted as dead code");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_LINTRCHNG);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LINTRCHNG";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below interchanged with loop on line %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_FUSEDTO);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_FUSEDTO";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below fused with loop on line %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_FUSEDFROM);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_FUSEDFROM";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop from line %d fused with loop below");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_VECINTRNSC);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_VECINTRNSC";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below transformed to use calls to vector"
+                                  " intrinsic %s");
+  ccm_attrs[vindex].fmt = CCMFMT_PP1;
+
+  vindex = ccm_vis_index (CCM_LSTRIPMINE);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LSTRIPMINE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below strip-mined");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_LNEST2LOOPS);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LNEST2LOOPS";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below collapsed with loop on line %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_LREVERSE);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LREVERSE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below has had its iteration direction"
+                                  " reversed");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_IMIX2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_IMIX2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below has %d loads, %d stores,"
+                                  " %d prefetches, %d FPadds, %d FPmuls,"
+                                  " %d FPdivs, %d FPsubs, and %d FPsqrts per"
+                                  " iteration");
+  ccm_attrs[vindex].fmt = CCMFMT_I1I2I3I4I5I6I7I8;
+
+  vindex = ccm_vis_index (CCM_LUNRFULL);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_LUNRFULL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below fully unrolled");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_ELIM_NOAMORTINST);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_ELIM_NOAMORTINST";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below was eliminated as it contains no"
+                                  " non-amortizable instructions");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_COMP_DALIGN);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_COMP_DALIGN";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Performance of loop below could be improved"
+                                  " by compiling with -dalign");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_INTIMIX);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_INTIMIX";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below has %d int-loads, %d int-stores,"
+                                  " %d alu-ops, %d muls, %d int-divs and"
+                                  " %d shifts per iteration");
+  ccm_attrs[vindex].fmt = CCMFMT_I1I2I3I4I5I6;
+
+  vindex = ccm_vis_index (CCM_LMULTI_VERSION);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LMULTI_VERSION";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s multi-versioned.  Specialized version"
+                                  " is %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1L2;
+
+  vindex = ccm_vis_index (CCM_LCOST_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LCOST_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s estimated to cost %d cycles per iteration");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+  vindex = ccm_vis_index (CCM_UNROLL_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_UNROLL_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s unrolled %d times");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+  vindex = ccm_vis_index (CCM_IMIX_B);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_IMIX_B";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s has %d loads, %d stores,"
+                                  " %d prefetches, %d FPadds, %d FPmuls, and"
+                                  " %d FPdivs per iteration");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2I3I4I5I6I7;
+
+  vindex = ccm_vis_index (CCM_SPILLS_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_SPILLS_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s required %d integer register spills,"
+                                  " %d FP register spills, and used"
+                                  " %d integer registers and %d FP registers");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2I3I4I5;
+
+  vindex = ccm_vis_index (CCM_LFISSION_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LFISSION_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s fissioned into %d loops, generating:"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2LL3;
+
+  vindex = ccm_vis_index (CCM_LFISSION_FRAG);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LFISSION_FRAG";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s contains code from lines: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1II2;
+
+  vindex = ccm_vis_index (CCM_LPEEL_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LPEEL_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s had iterations peeled off for better"
+                                  " unrolling and/or parallelization");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_LBLOCKED_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LBLOCKED_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s blocked by %d for improved memory"
+                                  " hierarchy performance, new inner loop %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2L3;
+
+  vindex = ccm_vis_index (CCM_LOUTER_UNROLL);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LOUTER_UNROLL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s is outer-unrolled %d times as part"
+                                  " of unroll and jam");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+  vindex = ccm_vis_index (CCM_LJAMMED);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LJAMMED";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "All %d copies of %s are fused together"
+                                  " as part of unroll and jam");
+  ccm_attrs[vindex].fmt = CCMFMT_I1L2;
+
+  vindex = ccm_vis_index (CCM_LWHILE2DO_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LWHILE2DO_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Bounds test for %s moved to top of loop");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_L2CALL_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_L2CALL_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s replaced by a call to %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1P2;
+
+  vindex = ccm_vis_index (CCM_LDEAD_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LDEAD_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s deleted as dead code");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_LINTRCHNG_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LINTRCHNG_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s interchanged with %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1L2;
+
+  vindex = ccm_vis_index (CCM_LINTRCHNG_ORDER);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LINTRCHNG_ORDER";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "For loop nest below, the final order of loops"
+                                  " after interchanging and subsequent"
+                                  " transformations is: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_LL1;
+
+  vindex = ccm_vis_index (CCM_FUSED_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_FUSED_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s fused with %s, new loop %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1L2L3;
+
+  vindex = ccm_vis_index (CCM_VECINTRNSC_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_VECINTRNSC_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s transformed to use calls to vector"
+                                  " intrinsics: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1PP2;
+
+  vindex = ccm_vis_index (CCM_LSTRIPMINE_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LSTRIPMINE_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s strip-mined by %d, new inner loop %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2L3;
+
+  vindex = ccm_vis_index (CCM_LNEST2LOOPS_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LNEST2LOOPS_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s collapsed with %s, new loop %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1L2L3;
+
+  vindex = ccm_vis_index (CCM_LREVERSE_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LREVERSE_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s has had its iteration direction reversed");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_IMIX2_B);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_IMIX2_B";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s has %d loads, %d stores,"
+                                  " %d prefetches, %d FPadds, %d FPmuls,"
+                                  " %d FPdivs, %d FPsubs, and %d FPsqrts per"
+                                  " iteration");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2I3I4I5I6I7I8I9;
+
+  vindex = ccm_vis_index (CCM_LUNRFULL_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LUNRFULL_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s fully unrolled");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_ELIM_NOAMORTINST_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_ELIM_NOAMORTINST_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s was eliminated as it contains no"
+                                  " non-amortizable instructions");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_COMP_DALIGN_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_COMP_DALIGN_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Performance of %s could be improved by"
+                                  " compiling with -dalign");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_INTIMIX_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_INTIMIX_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s has %d int-loads, %d int-stores,"
+                                  " %d alu-ops, %d muls, %d int-divs and"
+                                  " %d shifts per iteration");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2I3I4I5I6I7;
+
+  vindex = ccm_vis_index (CCM_OMP_REGION);
+  ccm_attrs[vindex].vis = CCMV_PAR | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_OMP_REGION";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Source OpenMP region below has tag %s");
+  ccm_attrs[vindex].fmt = CCMFMT_R1;
+
+  vindex = ccm_vis_index (CCM_LMICROVECTORIZE);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LMICROVECTORIZE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s is micro-vectorized");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_LMULTI_VERSION_2);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LMULTI_VERSION_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s multi-versioned for %s."
+                                  " Specialized version is %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1S2L3;
+
+  vindex = ccm_vis_index (CCM_LCLONED);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LCLONED";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s cloned for %s.  Clone is %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1S2L3;
+
+  vindex = ccm_vis_index (CCM_LUNSWITCHED);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LUNSWITCHED";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s is unswitched.  New loops"
+                                  " are %s and %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1L2L3;
+
+  vindex = ccm_vis_index (CCM_LRESWITCHED);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LRESWITCHED";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loops %s and %s and their surrounding"
+                                  " conditional code have been merged to"
+                                  " form loop %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1L2L3;
+
+  vindex = ccm_vis_index (CCM_LSKEWBLOCKED);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LSKEWBLOCKED";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s skew-blocked by %d with slope"
+                                  " %d for improved memory hierarchy"
+                                  " performance, new inner loop %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2I3L4;
+
+  vindex = ccm_vis_index (CCM_IVSUB);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_IVSUB";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Induction variable substitution performed on %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_ONEITER_REPLACED);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_ONEITER_REPLACED";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s determined to have a trip count of 1;"
+                                  " converted to straight-line code");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_IMIX3_B);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_IMIX3_B";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s has %d loads, %d stores,"
+                                  " %d prefetches, %d FPadds, %d FPmuls,"
+                                  " %d FPmuladds, %d FPdivs, and %d FPsqrts per"
+                                  " iteration");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2I3I4I5I6I7I8I9;
+
+  vindex = ccm_vis_index (CCM_PIPELINE);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_PIPELINE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below pipelined");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_PIPESTATS);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_PIPESTATS";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below scheduled with steady-state cycle"
+                                  " count = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_CALL);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_CALL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined because it contains"
+                                  " calls");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_INTCC);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_INTCC";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined because it sets"
+                                  " multiple integer condition codes.");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_MBAR);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_MBAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined because it contains a"
+                                  " memory barrier instruction");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_MNMX);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_MNMX";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined because it contains"
+                                  " a minimum or a maximum operation");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_U2FLT);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_U2FLT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined because it contains"
+                                  " an unsigned to float conversion");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_GOT);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_GOT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined because it sets the"
+                                  " Global Offset Table pointer");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_IDIV);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_IDIV";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined because it contains"
+                                  " an integer divide");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_PRFTCH);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_PRFTCH";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined because it contains"
+                                  " a prefetch operation");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_EXIT);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_EXIT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined because it contains"
+                                  " an exit operation");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_REG);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_REG";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined because it contains"
+                                  " instructions that set the %%gsr or %%fsr register");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_UNS);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_UNS";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined because it has an"
+                                  " unsigned loop counter");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_UNSUIT);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_UNSUIT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop was unsuitable for pipelining");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_INTRINSIC);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_INTRINSIC";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined because it has an"
+                                  " intrinsic call to %s");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_BIG);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_BIG";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined as it is too big");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_INVINTPR);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_INVINTPR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined as it contains too"
+                                  " many loop invariant integers = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_INVFLTPR);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_INVFLTPR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined as it contains too"
+                                  " many loop invariant floats = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_INVDBLPR);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_INVDBLPR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined as it contains too"
+                                  " many loop invariant doubles = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_PIPE_SCHEDAFIPR);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_PIPE_SCHEDAFIPR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below was adversely affected by high"
+                                  " integer register pressure = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_PIPE_SCHEDAFDPR);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_PIPE_SCHEDAFDPR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below was adversely affected by high"
+                                  " double register pressure = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_PIPE_SCHEDAFFPR);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_PIPE_SCHEDAFFPR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop below was adversely affected by high"
+                                  " float register pressure = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_INTPR);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_INTPR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined due to high"
+                                  " integer register pressure = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_DBLPR);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_DBLPR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined due to high"
+                                  " double register pressure = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_FLTPR);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_FLTPR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop could not be pipelined due to high"
+                                  " float register pressure = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_PIPELINE_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_PIPELINE_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s pipelined");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_PIPESTATS_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_PIPESTATS_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s scheduled with steady-state cycle"
+                                  " count = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_CALL_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_CALL_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined because it contains"
+                                  " calls");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_INTCC_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_INTCC_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined because it sets"
+                                  " multiple integer condition codes.");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_MBAR_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_MBAR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined because it contains"
+                                  " a memory barrier instruction");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_MNMX_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_MNMX_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined because it contains"
+                                  " a minimum or a maximum operation");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_U2FLT_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_U2FLT_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined because it contains"
+                                  " an unsigned to float conversion");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_GOT_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_GOT_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined because it sets the"
+                                  " Global Offset Table pointer");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_IDIV_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_IDIV_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined because it contains"
+                                  " an integer divide");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_PRFTCH_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_PRFTCH_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined because it contains"
+                                  " a prefetch operation");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_EXIT_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_EXIT_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined because it contains"
+                                  " an exit operation");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_REG_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_REG_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined because it contains"
+                                  " instructions that set the %%gsr or %%fsr register");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_UNS_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_UNS_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined because it has an"
+                                  " unsigned loop counter");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_UNSUIT_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_UNSUIT_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s is unsuitable for pipelining");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_INTRINSIC_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_INTRINSIC_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined because it contains"
+                                  " a call to intrinsic %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1P2;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_BIG_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_BIG_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined as it is too big");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_INVINTPR_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_INVINTPR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined as it contains too"
+                                  " many loop invariant integers = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_INVFLTPR_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_INVFLTPR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined as it contains too"
+                                  " many loop invariant floats = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_INVDBLPR_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_INVDBLPR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined as it contains too"
+                                  " many loop invariant doubles = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+  vindex = ccm_vis_index (CCM_PIPE_SCHEDAFIPR_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_PIPE_SCHEDAFIPR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s was adversely affected by high"
+                                  " integer register pressure = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+  vindex = ccm_vis_index (CCM_PIPE_SCHEDAFDPR_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_PIPE_SCHEDAFDPR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s was adversely affected by high"
+                                  " double register pressure = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+  vindex = ccm_vis_index (CCM_PIPE_SCHEDAFFPR_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_PIPE_SCHEDAFFPR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s was adversely affected by high"
+                                  " float register pressure = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_INTPR_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_INTPR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined due to high"
+                                  " integer register pressure = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_DBLPR_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_DBLPR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined due to high"
+                                  " double register pressure = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+  vindex = ccm_vis_index (CCM_NOPIPE_FLTPR_2);
+  ccm_attrs[vindex].vis = CCMV_PIPE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NOPIPE_FLTPR_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "%s could not be pipelined due to high"
+                                  " float register pressure = %d");
+  ccm_attrs[vindex].fmt = CCMFMT_L1I2;
+
+  vindex = ccm_vis_index (CCM_INLINE);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_INLINE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s inlined from source file %s into"
+                                  " the code for the following line");
+  ccm_attrs[vindex].fmt = CCMFMT_P1S2;
+
+  vindex = ccm_vis_index (CCM_INLINE2);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_INLINE2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s inlined from source file %s into"
+                                  " inline copy of function %s");
+  ccm_attrs[vindex].fmt = CCMFMT_P1S2P3;
+
+  vindex = ccm_vis_index (CCM_INLINE_TMPLT);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_INLINE_TMPLT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s inlined from template file %s"
+                                  " into the code for the following line");
+  ccm_attrs[vindex].fmt = CCMFMT_P1S2;
+
+  vindex = ccm_vis_index (CCM_INLINE_TMPLT2);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_INLINE_TMPLT2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s inlined from template file %s"
+                                  " into inline copy of function %s");
+  ccm_attrs[vindex].fmt = CCMFMT_P1S2P3;
+
+  vindex = ccm_vis_index (CCM_INLINE_OUT_COPY);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_INLINE_OUT_COPY";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Out-of-line copy of inlined function %s from"
+                                  " source file %s generated");
+  ccm_attrs[vindex].fmt = CCMFMT_P1S2;
+
+  vindex = ccm_vis_index (CCM_NINLINE_REC);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_REC";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Recursive function %s inlined only up to"
+                                  " depth %d");
+  ccm_attrs[vindex].fmt = CCMFMT_P1I2;
+
+  vindex = ccm_vis_index (CCM_NINLINE_NEST);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_NEST";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because inlining is"
+                                  " already nested too deeply");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_CMPLX);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_CMPLX";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it contains"
+                                  " too many operations");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_FB);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_FB";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because the"
+                                  " profile-feedback execution count is too low");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_PAR);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_PAR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it contains"
+                                  " explicit parallel pragmas");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_OPT);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_OPT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it is"
+                                  " compiled with optimization level <= 2");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_USR);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_USR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because either command"
+                                  " line option or source code pragma prohibited it,"
+                                  " or it's not safe to inline it");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_AUTO);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_AUTO";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because doing so"
+                                  " would make automatic storage for %s too large");
+  ccm_attrs[vindex].fmt = CCMFMT_P1P2;
+
+  vindex = ccm_vis_index (CCM_NINLINE_CALLS);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_CALLS";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it contains"
+                                  " too many calls");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_ACTUAL);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_ACTUAL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it has more"
+                                  " actual parameters than formal parameters");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_FORMAL);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_FORMAL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it has more"
+                                  " formal parameters than actual parameters");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_TYPE);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_TYPE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because formal"
+                                  " argument type does not match actual type");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_ATYPE);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_ATYPE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because array formal"
+                                  " argument does not match reshaped array actual"
+                                  " argument type");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_RETTYPE);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_RETTYPE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because return type"
+                                  " does not match");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_EXCPT);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_EXCPT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it"
+                                  " guarded by an exception handler");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_UNSAFE);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_UNSAFE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it might be"
+                                  " unsafe (call alloca(), etc)");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_ALIAS);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_ALIAS";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because inlining it"
+                                  " will make the alias analysis in the calling"
+                                  " function more conservative");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_FEMARK);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_FEMARK";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it contains"
+                                  " setjmp/longjmp, or indirect goto, etc");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_RAREX);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_RAREX";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it is known"
+                                  " to be rarely executed");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_CLONING);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_CLONING";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s from source file %s cloned,"
+                                  " creating cloned function %s; constant"
+                                  " parameters propagated to clone");
+  ccm_attrs[vindex].fmt = CCMFMT_P1S2P3;
+
+  vindex = ccm_vis_index (CCM_INLINE_B);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_INLINE_B";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s inlined from source file %s into"
+                                  " the code for the following line.  %d loops"
+                                  " inlined");
+  ccm_attrs[vindex].fmt = CCMFMT_P1S2I3;
+
+  vindex = ccm_vis_index (CCM_INLINE2_B);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_INLINE2_B";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s inlined from source file %s into"
+                                  " inline copy of function %s.  %d loops inlined");
+  ccm_attrs[vindex].fmt = CCMFMT_P1S2P3I4;
+
+  vindex = ccm_vis_index (CCM_INLINE_LOOP);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_LOOP | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_INLINE_LOOP";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Loop in function %s, line %d has"
+                                  " tag %s");
+  ccm_attrs[vindex].fmt = CCMFMT_P1I2L3;
+
+  vindex = ccm_vis_index (CCM_NINLINE_MULTIENTRY);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_MULTIENTRY";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it"
+                                  " contains an ENTRY statement");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_VARARGS);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_VARARGS";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because variable"
+                                  " argument routines cannot be inlined");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_UNSEEN_BODY);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_UNSEEN_BODY";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because the compiler"
+                                  " has not seen the body of the function.  Use"
+                                  " -xcrossfile or -xipo in order to inline it");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_UPLEVEL);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_UPLEVEL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it is a"
+                                  " nested routine containing references to"
+                                  " variables defined in an outer function");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_CMDLINE);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_CMDLINE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because either"
+                                  " -xinline or source code pragma prohibited it");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_CALL_CMPLX);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_CALL_CMPLX";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Call to %s not inlined because of the"
+                                  " complexity of the calling routine");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_LANG_MISMATCH);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_LANG_MISMATCH";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Call to %s not inlined because it is in"
+                                  " a different language");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_RTN_WEAK);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_RTN_WEAK";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it"
+                                  " is marked weak");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_CALL_WEAKFILE);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_CALL_WEAKFILE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Call to %s not inlined because it is"
+                                  " in a different file and it contains a"
+                                  " call to a weak routine");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_CALL_TRYCATCH);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_CALL_TRYCATCH";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Call to %s not inlined because it is"
+                                  " in a different file and contains an"
+                                  " explicit try/catch");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_CALL_REGP);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_CALL_REGP";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Call to %s not inlined because it would"
+                                  " cause excessive register pressure");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_RTN_REGP);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_RTN_REGP";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it would"
+                                  " cause excessive register pressure");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_CALL_XPENSV);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_CALL_XPENSV";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Call to %s not inlined because analysis"
+                                  " exceeds the compilation time limit");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_READONLYIR);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_READONLYIR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it is in a file"
+                                  " specified as read-only by -xipo_archive=readonly"
+                                  " and it contains calls to static functions");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_CALL_THUNK);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_CALL_THUNK";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Call to %s not inlined because it is in a"
+                                  " compiler-generated function that does not"
+                                  " permit inlining");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_CALL_XTARGETS);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_CALL_XTARGETS";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Indirect callsite has too many targets;"
+                                  " callsite marked do not inline");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NINLINE_SELFTAIL_RECURSIVE);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_SELFTAIL_RECURSIVE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because"
+                                  " of a recursive tail-call to itself");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_PRAGMA);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_PRAGMA";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it contains"
+                                  " explicit parallel or alias pragmas");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_CMPLX2);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_CMPLX2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it contains too"
+                                  " many operations.  Increase max_inst_hard in order"
+                                  " to inline it: -xinline_param=max_inst_hard:n");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_RARE);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_RARE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because the call"
+                                  " is rarely executed");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_PAR2);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_PAR2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it is called"
+                                  " within a region guarded by an explicit"
+                                  " parallel pragmas");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_G_LIMIT);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_G_LIMIT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it would exceed"
+                                  " the permitted global code size growth limit.  Try"
+                                  " to increase max_growth in order to inline it:"
+                                  " -xinline_param=max_growth:n");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_L_LIMIT);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_L_LIMIT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it would exceed"
+                                  " the maximum function size growth limit.  Increase"
+                                  " max_function_inst in order to inline it:"
+                                  " -xinline_param=max_function_inst:n");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_REC2);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_REC2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Recursive function %s is inlined only up to"
+                                  " %d levels and up to %d size.  Increase"
+                                  " max_recursive_deptha or max_recursive_inst in"
+                                  " order to inline it:"
+                                  " -xinline_param=max_recursive_depth:n,"
+                                  " -xinline_param=max_recursive_inst:n");
+  ccm_attrs[vindex].fmt = CCMFMT_P1I2I3;
+
+  vindex = ccm_vis_index (CCM_NINLINE_FB2);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_FB2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because the"
+                                  " profile-feedback execution count is too"
+                                  " low.  Decrease min_counter in order to inline it:"
+                                  " -xinline_param:min_counter:n");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_CS_CMPLX);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_CS_CMPLX";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because called"
+                                  " function's size is too big.  Increase"
+                                  " max_inst_soft in order to inline it:"
+                                  " -xinline_param=max_inst_soft:n");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_R_EXCPT);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_R_EXCPT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it contains"
+                                  " an exception handler");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_ASM);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_ASM";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because"
+                                  " it contains asm statements");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_R_READONLYIR);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_R_READONLYIR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it is in a file"
+                                  " specified as read-only by -xipo_archive=readonly"
+                                  " and it is a static function");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_C_READONLYIR);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_C_READONLYIR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Call to %s not inlined because the calling"
+                                  " function is in a file specified as read-only"
+                                  " by -xipo_archive=readonly");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NINLINE_NEVERRETURN);
+  ccm_attrs[vindex].vis = CCMV_INLINE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NINLINE_NEVERRETURN";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it"
+                                  " never returns");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_MPREFETCH);
+  ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_MPREFETCH";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Prefetch of %s inserted");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_MPREFETCH_LD);
+  ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_MPREFETCH_LD";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Prefetch of %s inserted for load at %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1X2;
+
+  vindex = ccm_vis_index (CCM_MPREFETCH_ST);
+  ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_MPREFETCH_ST";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Prefetch of %s inserted for store at %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1X2;
+
+  vindex = ccm_vis_index (CCM_MPREFETCH_FB);
+  ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_MPREFETCH_FB";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Prefetch of %s inserted based on feedback data");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_MPREFETCH_FB_LD);
+  ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_MPREFETCH_FB_LD";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Prefetch of %s inserted for load at %s based"
+                                  " on feedback data");
+  ccm_attrs[vindex].fmt = CCMFMT_S1X2;
+
+  vindex = ccm_vis_index (CCM_MPREFETCH_FB_ST);
+  ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_MPREFETCH_FB_ST";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Prefetch of %s inserted for store at %s based"
+                                  " on feedback data");
+  ccm_attrs[vindex].fmt = CCMFMT_S1X2;
+
+  vindex = ccm_vis_index (CCM_MLOAD);
+  ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_MLOAD";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Load below refers to %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_MSTORE);
+  ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_MSTORE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Store below refers to %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_MLOAD_P);
+  ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_MLOAD_P";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Load below refers to %s, and was prefetched"
+                                  " at %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1X2;
+
+  vindex = ccm_vis_index (CCM_MSTORE_P);
+  ccm_attrs[vindex].vis = CCMV_MEMOPS | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_MSTORE_P";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Store below refers to %s, and was prefetched"
+                                  " at %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1X2;
+
+  vindex = ccm_vis_index (CCM_COPYIN);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_COPYIN";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Parameter %d caused a copyin in the following"
+                                  " call");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_COPYOUT);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_COPYOUT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Parameter %d caused a copyout in the following"
+                                  " call");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_COPYINOUT);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_COPYINOUT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Parameter %d caused both a copyin and copyout"
+                                  " in the following call");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_PADDING);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_PADDING";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Padding of %d bytes inserted before"
+                                  " array %s");
+  ccm_attrs[vindex].fmt = CCMFMT_I1V2;
+
+  vindex = ccm_vis_index (CCM_PADCOMMON);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_PADCOMMON";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Padding of %d bytes inserted before"
+                                  " array %s in common block %s");
+  ccm_attrs[vindex].fmt = CCMFMT_I1V2V3;
+
+  vindex = ccm_vis_index (CCM_ALIGN_EQ);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_ALIGN_EQ";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Variable/array %s can not be double-aligned,"
+                                  " because it is equivalenced");
+  ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+  vindex = ccm_vis_index (CCM_ALIGN_PERF);
+  ccm_attrs[vindex].vis = CCMV_FE;
+  ccm_attrs[vindex].name = "CCM_ALIGN_PERF";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Alignment of variables in common block may cause"
+                                  " performance degradation");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_ALIGN_STRUCT);
+  ccm_attrs[vindex].vis = CCMV_FE;
+  ccm_attrs[vindex].name = "CCM_ALIGN_STRUCT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Alignment of component %s in numeric sequence"
+                                  " structure %s may cause performance degradation");
+  ccm_attrs[vindex].fmt = CCMFMT_S1S2;
+
+  vindex = ccm_vis_index (CCM_TMP_COPY);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_TMP_COPY";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Argument %s copied to a temporary");
+  ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+  vindex = ccm_vis_index (CCM_TMP_COPYM);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_TMP_COPYM";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Argument %s might be copied to a temporary;"
+                                  " runtime decision made");
+  ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+  vindex = ccm_vis_index (CCM_PROC_MISMATCH);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_PROC_MISMATCH";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Argument %d to subprogram %s differs from"
+                                  " reference on line %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1P2I3;
+
+  vindex = ccm_vis_index (CCM_PROC_MISMATCH2);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_PROC_MISMATCH2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Scalar argument %d to subprogram %s is"
+                                  " referred to as an array on line %d");
+  ccm_attrs[vindex].fmt = CCMFMT_I1P2I3;
+
+  vindex = ccm_vis_index (CCM_PROC_MISMATCH3);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_PROC_MISMATCH3";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Return type/rank from subprogram %s differs"
+                                  " from return on line %d");
+  ccm_attrs[vindex].fmt = CCMFMT_P1I2;
+
+  vindex = ccm_vis_index (CCM_DO_EXPR);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_DO_EXPR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "DO statement bounds lead to no executions of the"
+                                  " loop");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_AUTO_BND);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_AUTO_BND";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "The bounds for automatic variable %s are not"
+                                  " available at all entry points; zero-length"
+                                  " variable might be allocated");
+  ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+  vindex = ccm_vis_index (CCM_LIT_PAD);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_LIT_PAD";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "The character string literal %s padded"
+                                  " to the length specified for the dummy argument");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_ARRAY_LOOP);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_ARRAY_LOOP";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Array statement below generated a loop");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_ARRAY_LOOPNEST);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_OBS;
+  ccm_attrs[vindex].name = "CCM_ARRAY_LOOPNEST";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Array statement below generated %d nested loops");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_ALIGN_PERF2);
+  ccm_attrs[vindex].vis = CCMV_FE;
+  ccm_attrs[vindex].name = "CCM_ALIGN_PERF2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Alignment of variable %s in common block %s"
+                                  " may cause a performance degradation");
+  ccm_attrs[vindex].fmt = CCMFMT_V1V2;
+
+  vindex = ccm_vis_index (CCM_ALIGN_PERF3);
+  ccm_attrs[vindex].vis = CCMV_FE;
+  ccm_attrs[vindex].name = "CCM_ALIGN_PERF3";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Alignment of variable %s in blank common may"
+                                  " cause a performance degradation");
+  ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+  vindex = ccm_vis_index (CCM_IO_LOOP_ARRAY);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_IO_LOOP_ARRAY";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "I/O implied do item below generated an array"
+                                  " section");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_TMPCONST);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_TMPCONST";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Implicit invocation of class %s constructor for"
+                                  " temporary");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_TMPDEST);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_TMPDEST";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Implicit invocation of class %s destructor for"
+                                  " temporary");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_DBL_CONST);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_DBL_CONST";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Double constant %s used in float expression");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_MINLINE);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_MINLINE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s inlined from source file %s by"
+                                  " front-end");
+  ccm_attrs[vindex].fmt = CCMFMT_P1S2;
+
+  vindex = ccm_vis_index (CCM_MINLINE2);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_MINLINE2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s from source file %s inlined into"
+                                  " inline copy of method %s by front-end");
+  ccm_attrs[vindex].fmt = CCMFMT_P1S2P3;
+
+  vindex = ccm_vis_index (CCM_MINLINE3);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_MINLINE3";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it uses keyword"
+                                  " %s");
+  ccm_attrs[vindex].fmt = CCMFMT_P1S2;
+
+  vindex = ccm_vis_index (CCM_MINLINE4);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC | CCMV_UNIMPL;
+  ccm_attrs[vindex].name = "CCM_MINLINE4";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s not inlined because it is too"
+                                  " complex");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_TMP_COPYOUT);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_TMP_COPYOUT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Argument %s copied from a temporary");
+  ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+  vindex = ccm_vis_index (CCM_TMP_COPYOUTM);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_TMP_COPYOUTM";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Argument %s might be copied from a temporary;"
+                                  " runtime decision made");
+  ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+  vindex = ccm_vis_index (CCM_TMP_COPYINOUT);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_TMP_COPYINOUT";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Argument %s copied in and out of a temporary");
+  ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+  vindex = ccm_vis_index (CCM_TMP_COPYINOUTM);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_TMP_COPYINOUTM";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Argument %s might be copied in and out of"
+                                  " a temporary; runtime decision made");
+  ccm_attrs[vindex].fmt = CCMFMT_V1;
+
+  vindex = ccm_vis_index (CCM_ARRAY_LOOP_2);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_ARRAY_LOOP_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Array statement below generated loop %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_ARRAY_LOOPNEST_2);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_ARRAY_LOOPNEST_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Array statement below generated %d nested"
+                                  " loops: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_I1LL2;
+
+  vindex = ccm_vis_index (CCM_IO_LOOP_ARRAY_2);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_IO_LOOP_ARRAY_2";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "I/O implied do item below generated an array"
+                                  " section: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_USER_LOOP);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_USER_LOOP";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Source loop below has tag %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_FOUND_LOOP);
+  ccm_attrs[vindex].vis = CCMV_FE | CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_FOUND_LOOP";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Discovered loop below has tag %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_MFUNCTION_LOOP);
+  ccm_attrs[vindex].vis = CCMV_LOOP | CCMV_BASIC | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_MFUNCTION_LOOP";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Copy in M-function of loop below has tag %s");
+  ccm_attrs[vindex].fmt = CCMFMT_L1;
+
+  vindex = ccm_vis_index (CCM_FSIMPLE);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_FSIMPLE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Transformations for fsimple=%d applied");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_STACK);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_STACK";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Function %s requires %d Mbytes of stack"
+                                  " storage");
+  ccm_attrs[vindex].fmt = CCMFMT_P1I2;
+
+  vindex = ccm_vis_index (CCM_TAILRECUR);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_TAILRECUR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Recursive tail call in %s optimized to jump to"
+                                  " entry point");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_TAILCALL);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC | CCMV_UNIMPL | CCMV_WANT;
+  ccm_attrs[vindex].name = "CCM_TAILCALL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Call to function %s was tail-call optimized");
+  ccm_attrs[vindex].fmt = CCMFMT_P1;
+
+  vindex = ccm_vis_index (CCM_NI_EXIT_OR_PSEUDO);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_EXIT_OR_PSEUDO";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because it"
+                                  " contains the pseudo instruction %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_NI_BAD_UNARY_OPC);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_BAD_UNARY_OPC";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because it"
+                                  " contains the instruction opcode %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_NI_INT_LDD_ON_V9);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_INT_LDD_ON_V9";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because it"
+                                  " contains integer ldd instructions, which are"
+                                  " deprecated in the v9 architecture");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NI_LATE_INL_OPC);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_LATE_INL_OPC";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because it"
+                                  " contains the instruction opcode %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_NI_BAD_IMM_OP);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_BAD_IMM_OP";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because the"
+                                  " relocation or immediate operand %s is not well"
+                                  " understood by the optimizer");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_NI_BAD_STATELEAF);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_BAD_STATELEAF";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because it"
+                                  " references the state register %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_NI_BAD_ASR_19);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_BAD_ASR_19";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because"
+                                  " %%asr19 is not supported in pre v8plus code");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NI_BAD_FSR_USE);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_BAD_FSR_USE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because"
+                                  " references to %%fsr can only be optimized when the"
+                                  " -iaopts flag is used");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NI_BAD_REGISTER);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_BAD_REGISTER";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because it"
+                                  " references the register %s");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+
+  vindex = ccm_vis_index (CCM_NI_NO_RET_VAL);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_NO_RET_VAL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because it"
+                                  " does not return the value declared");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NI_DELAY);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_DELAY";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because it"
+                                  " contains a non nop delay slot");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NI_SCALL);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_SCALL";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because it"
+                                  " calls a function which returns a structure");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_CASE_POSITION);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_CASE_POSITION";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Case block below was placed at position %d"
+                                  " based on execution frequency");
+  ccm_attrs[vindex].fmt = CCMFMT_I1;
+
+  vindex = ccm_vis_index (CCM_CALL_WITH_CODE);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_CALL_WITH_CODE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Call to %s replaced with inline code.  %d"
+                                  " loops created: %s");
+  ccm_attrs[vindex].fmt = CCMFMT_P1I2LL3;
+
+  vindex = ccm_vis_index (CCM_NI_BAD_SP_ADDR);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_BAD_SP_ADDR";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because it"
+                                  " contains a %%sp+reg address");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NI_BAD_SP_USAGE);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_BAD_SP_USAGE";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because it"
+                                  " uses/defines the stack pointer in a non-load/store instruction");
+  ccm_attrs[vindex].fmt = CCMFMT_NONE;
+
+  vindex = ccm_vis_index (CCM_NI_MIXED_REG_TYPES);
+  ccm_attrs[vindex].vis = CCMV_CG | CCMV_BASIC;
+  ccm_attrs[vindex].name = "CCM_NI_MIXED_REG_TYPES";
+  ccm_attrs[vindex].msg = catgets (ccm_catd, 99, vindex,
+                                  "Template could not be early inlined because it"
+                                  " contains register %s used as both x-register and register pair");
+  ccm_attrs[vindex].fmt = CCMFMT_S1;
+}
diff --git a/gprofng/src/comp_com.h b/gprofng/src/comp_com.h
new file mode 100644 (file)
index 0000000..e410924
--- /dev/null
@@ -0,0 +1,903 @@
+/* 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 _COMP_COM_H
+#define _COMP_COM_H
+
+#include <sys/types.h>
+#include <nl_types.h>
+
+/*
+ * This file describes format for the compiler-commentary
+ * section to be added to .o's and propagated to the a.out.  It reflects
+ * information the compiler can expose to the user about his or her
+ * program.  The section should be generated for all compiles where
+ * the user has specified -g on the compile line.
+ *
+ * In the analyzer, display of the messages will be governed by a user UI
+ * that sets a vis_bits bitmap, and matches it against a show_bits
+ * bitmap table, which is maintained separately from the producer
+ * code.  For any message, if (vis_bits&show_bits) is  non-zero, the
+ * message is shown.  If zero, the message is not shown.  A similar
+ * mechanism would be used for a stand-alone source or disassembly browser.
+ *
+ *
+ * The .compcom Section
+ * --------------------
+ * The section will be named ".compcom"; it is generated for each
+ * .o, and aggregated into a single section in the a.out.  In that
+ * section, each .o's data is separate, and the tools will loop
+ * over the data for each .o in order to find the subsection for
+ * the particular .o being annotated.
+ *
+ *
+ * Since the header is fixed-length, and the total size of the section
+ * can be easily determined as:
+ *
+ *     sizeof(stuct compcomhdr)
+ *     + msgcount * sizeof(struct compmsg)
+ *     + paramcount * sizeof(int32_t)
+ *     + stringlen
+ *
+ * there is no need to have the size in the header.
+ */
+
+typedef struct
+{ /* Header describing the section */
+  int32_t srcname;          /* index into strings of source file path */
+  int32_t version;          /* a version number for the .compcom format */
+  int32_t msgcount;         /* count of messages in the section */
+  int32_t paramcount;       /* count of parameters in the section */
+  int32_t stringcount;      /* count of strings in the section */
+  int32_t stringlen;        /* count of total bytes in strings */
+} compcomhdr;
+
+/*
+ * The data for the .o after the header as:
+ *
+ *    compmsg  msgs[msgcount];         the array of messages
+ *    int32_t  param[paramcount];      the parameters used in the messages
+ *                                     parameters are either integers or
+ *                                     string-indices
+ *    char     msgstrings[stringlen];  the strings used in the messages
+ */
+
+/*
+ * Message Classes and Visualization Bits
+ * --------------------------------------
+ * Each of the messages above may belong to zero or more visualization
+ * classes, governed by a table using zero or more of the following symbolic
+ * names for the classes:
+ */
+typedef enum {
+CCMV_WANT   = 0x000,           /* High-priority RFE -- used only for human */
+                               /*   reading of message list */
+CCMV_UNIMPL = 0x000,           /* Unimplemented -- used only for human */
+                               /*   reading of message list */
+CCMV_OBS    = 0x000,           /* Obsolete -- to be replaced by a different */
+                               /*   message with different parameters -- */
+                               /*   used only for human reading of message */
+                               /*   list */
+CCMV_VER    = 0x001,           /* Versioning messages */
+CCMV_WARN   = 0x002,           /* Warning messages */
+CCMV_PAR    = 0x004,           /* Parallelization messages */
+CCMV_QUERY  = 0x008,           /* Compiler queries */
+CCMV_LOOP   = 0x010,           /* Loop detail messages */
+CCMV_PIPE   = 0x020,           /* Pipelining messages */
+CCMV_INLINE = 0x040,           /* Inlining information */
+CCMV_MEMOPS = 0x080,           /* Messages concerning memory operations */
+CCMV_FE     = 0x100,           /* Front-end messages (all compilers) */
+CCMV_CG     = 0x200,           /* Code-generator messages (all compilers) */
+CCMV_BASIC  = 0x400,           /* for default messages */
+CCMV_ALL    = 0x7FFFFFFF       /* for all messages */
+} COMPCLASS_ID;
+
+typedef enum ccm_msgid
+{
+  /*   Group: Versioning Messages */
+  /*   All of these are global to the .o, and will */
+  /*   have lineno = pcoffset = 0 */
+
+CCM_MODDATE=0x00100,           /* Source file <s1>, last modified on date <s2> */
+CCM_COMPVER,                   /* Component <s1>, version <s2> */
+                       /* [Emitted for each component of the compiler.] */
+CCM_COMPDATE,                  /* Compilation date <s1> */
+                       /* [<s1> is an I18n string with the date and time] */
+CCM_COMPOPT,                   /* Compilation options <s1> */
+                       /* [As specified by the user] */
+CCM_ACOMPOPT,                  /* Actual Compilation options <s1> */
+                       /* [As expanded by the driver] */
+
+  /* Group: Warning Messages */
+CCM_VAR_ALIAS=0x00200,         /* Variable <v1> aliased to <v2> */
+CCM_FBIRDIFF,                  /* Profile feedback data inconsistent with */
+                       /* intermediate representation file; check compiler */
+                       /* version, flags and source file */
+CCM_OPTRED_SWAP,               /* Optimization level for <p1> reduced from <i2> to */
+                       /* <i3> due to insufficient swap space */
+CCM_OPTRED_CPLX,               /* Optimization level for <p1> reduced from <i2> to */
+                       /* <i3> due to program complexity */
+CCM_UNKNOWN,                   /* Unexpected compiler comment <i1> */
+
+  /* Group: Parallelization Messages */
+CCM_UNPAR_CALL=0x00400,        /* Loop below not parallelized because it contains a */
+                       /* call to <p1> */
+
+  /* CCMV_WANT: Don't generate CCM_PAR_SER; always use CCM_PAR_SER_VER */
+CCM_PAR_SER,                   /* Both serial and parallel versions generated for */
+                       /* loop below */
+CCM_PAR_SER_VER,               /* Both serial and parallel versions generated for */
+                       /* loop below; with parallel version used if <s1>, */
+                       /* serial otherwise */
+CCM_PAR_DRECTV,                /* Loop below parallelized by explicit user */
+                       /* directive */
+CCM_APAR,                      /* Loop below autoparallelized */
+CCM_AUTOPAR,                   /* Loop below autoparallelized; equivalent */
+                       /* explict directive is <s1> */
+CCM_UNPAR_DD,                  /* Loop below could not be parallelized because of a */
+                       /* data dependency on <v1>, <v2>, ... */
+                       /* [The number of parameters will determine how many */
+                       /* names appear, and the formatter will get the */
+                       /* commas right.] */
+CCM_UNPAR_DDA,                 /* Loop below could not be parallelized because of a */
+                       /* data dependency or aliasing of <v1>, <v2>, ... */
+CCM_UNPAR_ANONDD,              /* Loop below could not be parallelized because of */
+                       /* an anonymous data dependency */
+CCM_UNPAR_ANONDDA,             /* Loop below could not be parallelized because of */
+                       /* an anonymous data dependency or aliasing */
+CCM_PAR_WORK,                  /* Loop below parallelized, but might not contain */
+                       /* enough work to be efficiently run in parallel */
+CCM_UNPAR_EXIT,                /* Loop below not parallelized because it contains */
+                       /* multiple exit points */
+CCM_UNPAR_STRNG,               /* Loop below not parallelized because it contains a */
+                       /* strange flow of control */
+CCM_UNPAR_IO,                  /* Loop below not parallelized because it contains */
+                       /* I/O or other MT-unsafe calls */
+CCM_PAR_BODY_NAME,             /* Parallel loop-body code is in function <p1> */
+CCM_UNPAR_NLOOPIDX,            /* Loop below not parallelized because loop index */
+                       /* not found */
+CCM_UNPAR_DRECTV,              /* Loop below not parallelized because of explicit */
+                       /* user directive */
+CCM_UNPAR_NOTPROFIT,           /* Loop below not parallelized because it was not */
+                       /* profitable to do so */
+CCM_UNPAR_NEST,                /* Loop below not parallelized because it was */
+                       /* nested in a parallel loop */
+CCM_UNPAR,                     /* Loop below not parallelized */
+CCM_UNPAR_NOAUTO,              /* Loop below not parallelized because */
+                       /* autoparallelization is not enabled */
+CCM_PR_L_VAR,                  /* Private variables in loop below: */
+                       /* <v1>, <v2>, ... */
+                       /* [The number of parameters will determine how many */
+                       /* names appear, and the formatter will get the */
+                       /* commas right.] */
+CCM_SH_L_VAR,                  /* Shared variables in loop below: */
+                       /* <v1>, <v2>, ... */
+CCM_TP_L_VAR,                  /* Threadprivate variables in loop below: */
+                       /* <v1>, <v2>, ... */
+CCM_RV_L_VAR,                  /* Reduction variables in loop below: */
+                       /* <v1>, <v2>, ... */
+CCM_IM_L_VAR,                  /* Implicit variables in loop below: */
+                       /* <v1>, <v2>, ... */
+CCM_PR_O_VAR,                  /* Private variables in OpenMP construct below: */
+                       /* <v1>, <v2>, ... */
+CCM_SH_O_VAR,                  /* Shared variables in OpenMP construct below: */
+                       /* <v1>, <v2>, ... */
+CCM_TP_O_VAR,                  /* Threadprivate variables in OpenMP construct */
+                       /* below: <v1>, <v2>, ... */
+CCM_RV_O_VAR,                  /* Reduction variables in OpenMP construct below: */
+                       /* <v1>, <v2>, ... */
+CCM_IM_O_VAR,                  /* Implicit variables in OpenMP construct below: */
+                       /* <v1>, <v2>, ... */
+CCM_UNPAR_IN_OMP,              /* Loop below not parallelized because it is inside */
+                       /* an OpenMP region */
+CCM_FP_O_VAR,                  /* Firstprivate variables in OpenMP construct below: */
+                       /* <v1>, <v2>, ... */
+CCM_LP_O_VAR,                  /* Lastprivate variables in OpenMP construct below: */
+                       /* <v1>, <v2>, ... */
+CCM_CP_O_VAR,                  /* Copyprivate variables in OpenMP construct below: */
+                       /* <v1>, <v2>, ... */
+CCM_PR_OAS_VAR,                /* Variables autoscoped as PRIVATE in OpenMP */
+                       /* construct below: <v1>, <v2>, ... */
+CCM_SH_OAS_VAR,                /* Variables autoscoped as SHARED in OpenMP */
+                       /* construct below: <v1>, <v2>, ... */
+CCM_FP_OAS_VAR,                /* Variables autoscoped as FIRSTPRIVATE in OpenMP */
+                       /* construct below: <v1>, <v2>, ... */
+CCM_LP_OAS_VAR,                /* Variables autoscoped as LASTPRIVATE in OpenMP */
+                       /* construct below: <v1>, <v2>, ... */
+CCM_RV_OAS_VAR,                /* Variables autoscoped as REDUCTION in OpenMP */
+                       /* construct below: <v1>, <v2>, ... */
+CCM_FAIL_OAS_VAR,              /* Variables cannot be autoscoped in OpenMP */
+                       /* construct below: <v1>, <v2>, ... */
+CCM_SERIALIZE_OAS,             /* OpenMP parallel region below is serialized */
+                       /* because autoscoping has failed */
+CCM_UNPAR_CALL_2,              /* <l1> not parallelized because it contains calls */
+                       /* to: <p2>, <p3>, ... */
+CCM_PAR_DRECTV_2,              /* <l1> parallelized by explicit user directive */
+CCM_APAR_2,                    /* <l1> autoparallelized */
+CCM_AUTOPAR_2,                 /* <l1> autoparallelized; equivalent */
+                       /* explict directive is <s2> */
+CCM_UNPAR_DD_2,                /* <l1> could not be parallelized because of */
+                       /* data dependences on: <v2>, <v3>, ... */
+                       /* [The number of parameters will determine how many */
+                       /* names appear, and the formatter will get the */
+                       /* commas right.] */
+CCM_UNPAR_DDA_2,               /* <l1> could not be parallelized because of a */
+                       /* data dependence or aliasing of: <v2>, <v3>, ... */
+CCM_UNPAR_ANONDD_2,            /* <l1> could not be parallelized because of an */
+                       /* anonymous data dependence */
+CCM_UNPAR_ANONDDA_2,           /* <l1> could not be parallelized because of an */
+                       /* anonymous data dependence or aliasing */
+CCM_PAR_WORK_2,                /* <l1> parallelized, but might not contain */
+                       /* enough work to run efficiently in parallel */
+CCM_UNPAR_EXIT_2,              /* <l1> not parallelized because it contains */
+                       /* multiple exit points */
+CCM_UNPAR_STRANGE_2,           /* <l1> not parallelized because it contains a */
+                       /* strange flow of control */
+CCM_UNPAR_IO_2,                /* <l1> not parallelized because it contains */
+                       /* I/O or other MT-unsafe calls */
+CCM_PAR_BODY_NAME_2,           /* <l1> parallel loop-body code placed in */
+                       /* function <p2> along with <i3> inner loops */
+CCM_UNPAR_NLOOPIDX_2,          /* <l1> not parallelized because loop index not */
+                       /* found */
+CCM_UNPAR_DRECTV_2,            /* <l1> not parallelized because of explicit */
+                       /* user directive */
+CCM_UNPAR_NOTPROFIT_2,         /* <l1> not parallelized because it was not */
+                       /* profitable to do so */
+CCM_UNPAR_NEST_2,              /* <l1> not parallelized because it was */
+                       /* nested within a parallel loop */
+CCM_UNPAR_2,                   /* <l1> not parallelized */
+CCM_UNPAR_NOAUTO_2,            /* <l1> not parallelized because */
+                       /* autoparallelization is not enabled */
+CCM_PR_L_VAR_2,                /* Private variables in <l1>: */
+                       /* <v2>, <v3>, ... */
+                       /* [The number of parameters will determine how many */
+                       /* names appear, and the formatter will get the */
+                       /* commas right.] */
+CCM_SH_L_VAR_2,                /* Shared variables in <l1>: */
+                       /* <v2>, <v3>, ... */
+CCM_TP_L_VAR_2,                /* Threadprivate variables in <l1>: */
+                       /* <v2>, <v3>, ... */
+CCM_RV_L_VAR_2,                /* Reduction variables of operator <s1> in <l2>: */
+                       /* <v3>, <v4>, ... */
+CCM_IM_L_VAR_2,                /* Implicit variables in <l1>: */
+                       /* <v2>, <v3>, ... */
+CCM_PR_O_VAR_2,                /* Private variables in <r1>: */
+                       /* <v2>, <v3>, ... */
+CCM_SH_O_VAR_2,                /* Shared variables in <r1>: */
+                       /* <v2>, <v3>, ... */
+CCM_TP_O_VAR_2,                /* Threadprivate variables in <r1>: */
+                       /* <v2>, <v3>, ... */
+CCM_RV_O_VAR_2,                /* Reduction variables of operator <s1> in <r2>: */
+                       /* <v3>, <v4>, ... */
+CCM_IM_O_VAR_2,                /* Implicit variables in <r1>: */
+                       /* <v2>, <v3>, ... */
+CCM_UNPAR_IN_OMP_2,            /* <l1> not parallelized because it is inside */
+                       /* OpenMP region <r2> */
+CCM_FP_O_VAR_2,                /* Firstprivate variables in <r1>: */
+                       /* <v2>, <v3>, ... */
+CCM_LP_O_VAR_2,                /* Lastprivate variables in <r1>: */
+                       /* <v2>, <v3>, ... */
+CCM_CP_O_VAR_2,                /* Copyprivate variables in <r1>: */
+                       /* <v2>, <v3>, ... */
+CCM_PR_OAS_VAR_2,              /* Variables autoscoped as PRIVATE in <r1>: */
+                       /* <v2>, <v3>, ... */
+CCM_SH_OAS_VAR_2,              /* Variables autoscoped as SHARED in <r1>: */
+                       /* <v2>, <v3>, ... */
+CCM_FP_OAS_VAR_2,              /* Variables autoscoped as FIRSTPRIVATE in <r1>: */
+                       /* <v2>, <v3>, ... */
+CCM_LP_OAS_VAR_2,              /* Variables autoscoped as LASTPRIVATE in <r1>: */
+                       /* <v2>, <v3>, ... */
+CCM_RV_OAS_VAR_2,              /* Variables autoscoped as REDUCTION of operator */
+                       /* <s1> in <r2>: <v3>, <v4>, ... */
+CCM_FAIL_OAS_VAR_2,            /* Variables treated as shared because they cannot */
+                       /* be autoscoped in <r1>: <v2>, <v3>, ... */
+CCM_SERIALIZE_OAS_2,           /* <r1> will be executed by a single thread because */
+                       /* autoscoping for some variables was not successful */
+
+  /* Group: Parallelization Questions asked of the user */
+  /*   How will the user answer these questions? */
+CCM_QPERMVEC=0x00800,          /* Is <v1> a permutation vector during execution of */
+                       /* <l2>? */
+CCM_QEXPR,                     /* Is expression <s1> true for <l2>? */
+CCM_QSAFECALL,                 /* Is subroutine <p1> MP-safe as used in <l2>? */
+
+  /* Group: Loop Optimization Messages */
+CCM_LCOST=0x01000,             /* Loop below estimated to cost <i1> cycles per */
+                       /* iteration */
+CCM_UNROLL,                    /* Loop below unrolled <i1> times */
+  /* CCMV_WANT: the next one should be replaced by CCM_IMIX2 */
+CCM_IMIX,                      /* Loop below has <i1> loads, <i2> stores, */
+                       /* <i3> prefetches, <i4> FPadds, <i5> FPmuls, and */
+                       /* <i6> FPdivs per iteration */
+CCM_SPILLS,                    /* Loop below required <i1> integer register spills, */
+                       /* <i2> FP register spills, and used */
+                       /* <i3> integer registers and <i4> FP registers */
+CCM_LFISSION,                  /* Loop below fissioned into <i1> loops */
+CCM_LPEEL,                     /* Loop below had iterations peeled off for better */
+                       /* unrolling and/or parallelization */
+CCM_LBLOCKED,                  /* Loop below blocked by <i1> for improved cache */
+                       /* performance */
+CCM_LTILED,                    /* Loop below tiled for better performance */
+CCM_LUNRJAM,                   /* Loop below unrolled and jammed */
+CCM_LWHILE2DO,                 /* Bounds test for loop below moved to top of loop */
+CCM_L2CALL,                    /* Loop below replaced by a call to <p1> */
+CCM_LDEAD,                     /* Loop below deleted as dead code */
+CCM_LINTRCHNG,                 /* Loop below interchanged with loop on line <i1> */
+CCM_FUSEDTO,                   /* Loop below fused with loop on line <i1> */
+CCM_FUSEDFROM,                 /* Loop from line <i1> fused with loop below */
+CCM_VECINTRNSC,                /* Loop below transformed to use calls to vector */
+                       /* intrinsic <p1>, <p2>, ... */
+                       /* [The number of parameters will determine how many */
+                       /* names appear, and the formatter will get the */
+                       /* commas right.] */
+CCM_LSTRIPMINE,                /* Loop below strip-mined */
+CCM_LNEST2LOOPS,               /* Loop below collapsed with loop on line <i1> */
+CCM_LREVERSE,                  /* Loop below has had its iteration direction */
+                       /* reversed */
+CCM_IMIX2,                     /* Loop below has <i1> loads, <i2> stores, */
+                       /* <i3> prefetches, <i4> FPadds, <i5> FPmuls, */
+                       /* <i6> FPdivs, <i7> FPsubs, and <i8> FPsqrts per */
+                       /* iteration */
+CCM_LUNRFULL,                  /* Loop below fully unrolled */
+CCM_ELIM_NOAMORTINST,          /* Loop below was eliminated as it contains no */
+                       /* non-amortizable instructions */
+CCM_COMP_DALIGN,               /* Performance of loop below could be improved */
+                       /* by compiling with -dalign */
+CCM_INTIMIX,                   /* Loop below has <i1> int-loads, <i2> int-stores, */
+                       /* <i3> alu-ops, <i4> muls, <i5> int-divs and */
+                       /* <i6> shifts per iteration */
+CCM_LMULTI_VERSION,            /* <l1> multi-versioned.  Specialized version */
+                       /* is <l2> */
+CCM_LCOST_2,                   /* <l1> estimated to cost <i2> cycles per iteration */
+CCM_UNROLL_2,                  /* <l1> unrolled <i2> times */
+
+  /* CCMV_WANT: the next one should be replaced by CCM_IMIX2_B or CCM_IMIX3_B */
+CCM_IMIX_B,                    /* <l1> has <i2> loads, <i3> stores, */
+                       /* <i4> prefetches, <i5> FPadds, <i6> FPmuls, and */
+                       /* <i7> FPdivs per iteration */
+CCM_SPILLS_2,                  /* <l1> required <i2> integer register spills, */
+                       /* <i3> FP register spills, and used */
+                       /* <i4> integer registers and <i5> FP registers */
+CCM_LFISSION_2,                /* <l1> fissioned into <i2> loops, generating: */
+                       /* <l3>, <l4>, ... */
+                       /* [The number of parameters will determine how many */
+                       /* names appear, and the formatter will get the */
+                       /* commas right.] */
+CCM_LFISSION_FRAG,             /* <l1> contains code from lines: <i2>, <i3>, ... */
+CCM_LPEEL_2,                   /* <l1> had iterations peeled off for better */
+                       /* unrolling and/or parallelization */
+CCM_LBLOCKED_2,                /* <l1> blocked by <i2> for improved memory */
+                       /* hierarchy performance, new inner loop <l3> */
+CCM_LOUTER_UNROLL,             /* <l1> is outer-unrolled <i2> times as part */
+                       /* of unroll and jam */
+CCM_LJAMMED,                   /* All <i1> copies of <l2> are fused together */
+                       /* as part of unroll and jam */
+CCM_LWHILE2DO_2,               /* Bounds test for <l1> moved to top of loop */
+CCM_L2CALL_2,                  /* <l1> replaced by a call to <p2> */
+CCM_LDEAD_2,                   /* <l1> deleted as dead code */
+CCM_LINTRCHNG_2,               /* <l1> interchanged with <l2> */
+CCM_LINTRCHNG_ORDER,           /* For loop nest below, the final order of loops */
+                       /* after interchanging and subsequent */
+                       /* transformations is: <l1>, <l2>, ... */
+                       /* [The number of parameters will determine how many */
+                       /* names appear, and the formatter will get the */
+                       /* commas right.] */
+CCM_FUSED_2,                   /* <l1> fused with <l2>, new loop <l3> */
+CCM_VECINTRNSC_2,              /* <l1> transformed to use calls to vector */
+                       /* intrinsics: <p2>, <p3>, ... */
+CCM_LSTRIPMINE_2,              /* <l1> strip-mined by <i2>, new inner loop <l3> */
+CCM_LNEST2LOOPS_2,             /* <l1> collapsed with <l2>, new loop <l3> */
+CCM_LREVERSE_2,                /* <l1> has had its iteration direction reversed */
+CCM_IMIX2_B,                   /* <l1> has <i2> loads, <i3> stores, */
+                       /* <i4> prefetches, <i5> FPadds, <i6> FPmuls, */
+                       /* <i7> FPdivs, <i8> FPsubs, and <i9> FPsqrts per */
+                       /* iteration */
+CCM_LUNRFULL_2,                /* <l1> fully unrolled */
+CCM_ELIM_NOAMORTINST_2,        /* <l1> was eliminated as it contains no */
+                       /* non-amortizable instructions */
+CCM_COMP_DALIGN_2,             /* Performance of <l1> could be improved by */
+                       /* compiling with -dalign */
+CCM_INTIMIX_2,                 /* <l1> has <i2> int-loads, <i3> int-stores, */
+                       /* <i4> alu-ops, <i5> muls, <i6> int-divs and */
+                       /* <i7> shifts per iteration */
+CCM_OMP_REGION,                /* Source OpenMP region below has tag <r1> */
+CCM_LMICROVECTORIZE,           /* <l1> is micro-vectorized */
+CCM_LMULTI_VERSION_2,          /* <l1> multi-versioned for <s2>. */
+                       /* Specialized version is <l3> */
+CCM_LCLONED,                   /* <l1> cloned for <s2>.  Clone is <l3> */
+CCM_LUNSWITCHED,               /* <l1> is unswitched.  New loops */
+                       /* are <l2> and <l3> */
+CCM_LRESWITCHED,               /* Loops <l1> and <l2> and their surrounding */
+                       /* conditional code have been merged to */
+                       /* form loop <l3> */
+CCM_LSKEWBLOCKED,              /* <l1> skew-blocked by <i2> with slope */
+                       /* <i3> for improved memory hierarchy */
+                       /* performance, new inner loop <l4> */
+CCM_IVSUB,                     /* Induction variable substitution performed on <l1> */
+CCM_ONEITER_REPLACED,          /* <l1> determined to have a trip count of 1; */
+                       /* converted to straight-line code */
+CCM_IMIX3_B,                   /* <l1> has <i2> loads, <i3> stores, */
+                       /* <i4> prefetches, <i5> FPadds, <i6> FPmuls, */
+                       /* <i7> FPmuladds, <i8> FPdivs, and <i9> FPsqrts per */
+                       /* iteration */
+
+  /* Group: Pipelining Messages */
+CCM_PIPELINE=0x02000,          /* Loop below pipelined */
+CCM_PIPESTATS,                 /* Loop below scheduled with steady-state cycle */
+                       /* count = <i1> */
+CCM_NOPIPE_CALL,               /* Loop could not be pipelined because it contains */
+                       /* calls */
+CCM_NOPIPE_INTCC,              /* Loop could not be pipelined because it sets */
+                       /* multiple integer condition codes. */
+CCM_NOPIPE_MBAR,               /* Loop could not be pipelined because it contains a */
+                       /* memory barrier instruction */
+CCM_NOPIPE_MNMX,               /* Loop could not be pipelined because it contains */
+                       /* a minimum or a maximum operation */
+CCM_NOPIPE_U2FLT,              /* Loop could not be pipelined because it contains */
+                       /* an unsigned to float conversion */
+CCM_NOPIPE_GOT,                /* Loop could not be pipelined because it sets the */
+                       /* Global Offset Table pointer */
+CCM_NOPIPE_IDIV,               /* Loop could not be pipelined because it contains */
+                       /* an integer divide */
+CCM_NOPIPE_PRFTCH,             /* Loop could not be pipelined because it contains */
+                       /* a prefetch operation */
+CCM_NOPIPE_EXIT,               /* Loop could not be pipelined because it contains */
+                       /* an exit operation */
+CCM_NOPIPE_REG,                /* Loop could not be pipelined because it contains */
+                       /* instructions that set the %gsr or %fsr register */
+CCM_NOPIPE_UNS,                /* Loop could not be pipelined because it has an */
+                       /* unsigned loop counter */
+CCM_NOPIPE_UNSUIT,             /* Loop was unsuitable for pipelining */
+CCM_NOPIPE_INTRINSIC,          /* Loop could not be pipelined because it has an */
+                       /* intrinsic call to <p1> */
+CCM_NOPIPE_BIG,                /* Loop could not be pipelined as it is too big */
+CCM_NOPIPE_INVINTPR,           /* Loop could not be pipelined as it contains too */
+                       /* many loop invariant integers = <i1> */
+CCM_NOPIPE_INVFLTPR,           /* Loop could not be pipelined as it contains too */
+                       /* many loop invariant floats = <i1> */
+CCM_NOPIPE_INVDBLPR,           /* Loop could not be pipelined as it contains too */
+                       /* many loop invariant doubles = <i1> */
+CCM_PIPE_SCHEDAFIPR,           /* Loop below was adversely affected by high */
+                       /* integer register pressure = <i1> */
+CCM_PIPE_SCHEDAFDPR,           /* Loop below was adversely affected by high */
+                       /* double register pressure = <i1> */
+CCM_PIPE_SCHEDAFFPR,           /* Loop below was adversely affected by high */
+                       /* float register pressure = <i1> */
+CCM_NOPIPE_INTPR,              /* Loop could not be pipelined due to high */
+                       /* integer register pressure = <i1> */
+CCM_NOPIPE_DBLPR,              /* Loop could not be pipelined due to high */
+                       /* double register pressure = <i1> */
+CCM_NOPIPE_FLTPR,              /* Loop could not be pipelined due to high */
+                       /* float register pressure = <i1> */
+CCM_PIPELINE_2,                /* <l1> pipelined */
+CCM_PIPESTATS_2,               /* <l1> scheduled with steady-state cycle */
+                       /* count = <i2> */
+CCM_NOPIPE_CALL_2,             /* <l1> could not be pipelined because it contains */
+                       /* calls */
+CCM_NOPIPE_INTCC_2,            /* <l1> could not be pipelined because it sets */
+                       /* multiple integer condition codes. */
+CCM_NOPIPE_MBAR_2,             /* <l1> could not be pipelined because it contains */
+                       /* a memory barrier instruction */
+CCM_NOPIPE_MNMX_2,             /* <l1> could not be pipelined because it contains */
+                       /* a minimum or a maximum operation */
+CCM_NOPIPE_U2FLT_2,            /* <l1> could not be pipelined because it contains */
+                       /* an unsigned to float conversion */
+CCM_NOPIPE_GOT_2,              /* <l1> could not be pipelined because it sets the */
+                       /* Global Offset Table pointer */
+CCM_NOPIPE_IDIV_2,             /* <l1> could not be pipelined because it contains */
+                       /* an integer divide */
+CCM_NOPIPE_PRFTCH_2,           /* <l1> could not be pipelined because it contains */
+                       /* a prefetch operation */
+CCM_NOPIPE_EXIT_2,             /* <l1> could not be pipelined because it contains */
+                       /* an exit operation */
+CCM_NOPIPE_REG_2,              /* <l1> could not be pipelined because it contains */
+                       /* instructions that set the %gsr or %fsr register */
+CCM_NOPIPE_UNS_2,              /* <l1> could not be pipelined because it has an */
+                       /* unsigned loop counter */
+CCM_NOPIPE_UNSUIT_2,           /* <l1> is unsuitable for pipelining */
+CCM_NOPIPE_INTRINSIC_2,        /* <l1> could not be pipelined because it contains */
+                       /* a call to intrinsic <p2> */
+CCM_NOPIPE_BIG_2,              /* <l1> could not be pipelined as it is too big */
+CCM_NOPIPE_INVINTPR_2,         /* <l1> could not be pipelined as it contains too */
+                       /* many loop invariant integers = <i2> */
+CCM_NOPIPE_INVFLTPR_2,         /* <l1> could not be pipelined as it contains too */
+                       /* many loop invariant floats = <i2> */
+CCM_NOPIPE_INVDBLPR_2,         /* <l1> could not be pipelined as it contains too */
+                       /* many loop invariant doubles = <i2> */
+CCM_PIPE_SCHEDAFIPR_2,         /* <l1> was adversely affected by high */
+                       /* integer register pressure = <i2> */
+CCM_PIPE_SCHEDAFDPR_2,         /* <l1> was adversely affected by high */
+                       /* double register pressure = <i2> */
+CCM_PIPE_SCHEDAFFPR_2,         /* <l1> was adversely affected by high */
+                       /* float register pressure = <i2> */
+CCM_NOPIPE_INTPR_2,            /* <l1> could not be pipelined due to high */
+                       /* integer register pressure = <i2> */
+CCM_NOPIPE_DBLPR_2,            /* <l1> could not be pipelined due to high */
+                       /* double register pressure = <i2> */
+CCM_NOPIPE_FLTPR_2,            /* <l1> could not be pipelined due to high */
+                       /* float register pressure = <i2> */
+
+  /* Group: Inlining Messages */
+CCM_INLINE=0x04000,            /* Function <p1> inlined from source file <s2> into */
+                       /* the code for the following line */
+CCM_INLINE2,                   /* Function <p1> inlined from source file <s2> into */
+                       /* inline copy of function <p3> */
+CCM_INLINE_TMPLT,              /* Function <p1> inlined from template file <s2> */
+                       /* into the code for the following line */
+CCM_INLINE_TMPLT2,             /* Function <p1> inlined from template file <s2> */
+                       /* into inline copy of function <p3> */
+CCM_INLINE_OUT_COPY,           /* Out-of-line copy of inlined function <p1> from */
+                       /* source file <s2> generated */
+CCM_NINLINE_REC,               /* Recursive function <p1> inlined only up to */
+                       /* depth <i2> */
+CCM_NINLINE_NEST,              /* Function <p1> not inlined because inlining is */
+                       /* already nested too deeply */
+CCM_NINLINE_CMPLX,             /* Function <p1> not inlined because it contains */
+                       /* too many operations */
+CCM_NINLINE_FB,                /* Function <p1> not inlined because the */
+                       /* profile-feedback execution count is too low */
+CCM_NINLINE_PAR,               /* Function <p1> not inlined because it contains */
+                       /* explicit parallel pragmas */
+CCM_NINLINE_OPT,               /* Function <p1> not inlined because it is */
+                       /* compiled with optimization level <= 2 */
+CCM_NINLINE_USR,               /* Function <p1> not inlined because either command */
+                       /* line option or source code pragma prohibited it, */
+                       /* or it's not safe to inline it */
+CCM_NINLINE_AUTO,              /* Function <p1> not inlined because doing so */
+                       /* would make automatic storage for <p2> too large */
+CCM_NINLINE_CALLS,             /* Function <p1> not inlined because it contains */
+                       /* too many calls */
+CCM_NINLINE_ACTUAL,            /* Function <p1> not inlined because it has more */
+                       /* actual parameters than formal parameters */
+CCM_NINLINE_FORMAL,            /* Function <p1> not inlined because it has more */
+                       /* formal parameters than actual parameters */
+CCM_NINLINE_TYPE,              /* Function <p1> not inlined because formal */
+                       /* argument type does not match actual type */
+CCM_NINLINE_ATYPE,             /* Function <p1> not inlined because array formal */
+                       /* argument does not match reshaped array actual */
+                       /* argument type */
+CCM_NINLINE_RETTYPE,           /* Function <p1> not inlined because return type */
+                       /* does not match */
+CCM_NINLINE_EXCPT,             /* Function <p1> not inlined because it */
+                       /* guarded by an exception handler */
+CCM_NINLINE_UNSAFE,            /* Function <p1> not inlined because it might be */
+                       /* unsafe (call alloca(), etc) */
+CCM_NINLINE_ALIAS,             /* Function <p1> not inlined because inlining it */
+                       /* will make the alias analysis in the calling */
+                       /* function more conservative */
+CCM_NINLINE_FEMARK,            /* Function <p1> not inlined because it contains */
+                       /* setjmp/longjmp, or indirect goto, etc */
+CCM_NINLINE_RAREX,             /* Function <p1> not inlined because it is known */
+                       /* to be rarely executed */
+CCM_CLONING,                   /* Function <p1> from source file <s2> cloned, */
+                       /* creating cloned function <p3>; constant */
+                       /* parameters propagated to clone */
+CCM_INLINE_B,                  /* Function <p1> inlined from source file <s2> into */
+                       /* the code for the following line.  <i3> loops */
+                       /* inlined */
+CCM_INLINE2_B,                 /* Function <p1> inlined from source file <s2> into */
+                       /* inline copy of function <p3>.  <i4> loops inlined */
+CCM_INLINE_LOOP,               /* Loop in function <p1>, line <i2> has */
+                       /* tag <l3> */
+CCM_NINLINE_MULTIENTRY,        /* Function <p1> not inlined because it */
+                       /* contains an ENTRY statement */
+CCM_NINLINE_VARARGS,           /* Function <p1> not inlined because variable */
+                       /* argument routines cannot be inlined */
+CCM_NINLINE_UNSEEN_BODY,       /* Function <p1> not inlined because the compiler */
+                       /* has not seen the body of the function.  Use */
+                       /* -xcrossfile or -xipo in order to inline it */
+CCM_NINLINE_UPLEVEL,           /* Function <p1> not inlined because it is a */
+                       /* nested routine containing references to */
+                       /* variables defined in an outer function */
+CCM_NINLINE_CMDLINE,           /* Function <p1> not inlined because either */
+                       /* -xinline or source code pragma prohibited it */
+CCM_NINLINE_CALL_CMPLX,        /* Call to <p1> not inlined because of the */
+                       /* complexity of the calling routine */
+CCM_NINLINE_LANG_MISMATCH,     /* Call to <p1> not inlined because it is in */
+                       /* a different language */
+CCM_NINLINE_RTN_WEAK,          /* Function <p1> not inlined because it */
+                       /* is marked weak */
+CCM_NINLINE_CALL_WEAKFILE,     /* Call to <p1> not inlined because it is */
+                       /* in a different file and it contains a */
+                       /* call to a weak routine */
+CCM_NINLINE_CALL_TRYCATCH,     /* Call to <p1> not inlined because it is */
+                       /* in a different file and contains an */
+                       /* explicit try/catch */
+CCM_NINLINE_CALL_REGP,         /* Call to <p1> not inlined because it would */
+                       /* cause excessive register pressure */
+CCM_NINLINE_RTN_REGP,          /* Function <p1> not inlined because it would */
+                       /* cause excessive register pressure */
+CCM_NINLINE_CALL_XPENSV,       /* Call to <p1> not inlined because analysis */
+                       /* exceeds the compilation time limit */
+CCM_NINLINE_READONLYIR,        /* Function <p1> not inlined because it is in a file */
+                       /* specified as read-only by -xipo_archive=readonly */
+                       /* and it contains calls to static functions */
+CCM_NINLINE_CALL_THUNK,        /* Call to <p1> not inlined because it is in a */
+                       /* compiler-generated function that does not */
+                       /* permit inlining */
+CCM_NINLINE_CALL_XTARGETS,     /* Indirect callsite has too many targets; */
+                       /* callsite marked do not inline */
+CCM_NINLINE_SELFTAIL_RECURSIVE,        /* Function <p1> not inlined because */
+                       /* of a recursive tail-call to itself */
+CCM_NINLINE_PRAGMA,            /* Function <p1> not inlined because it contains */
+                       /* explicit parallel or alias pragmas */
+CCM_NINLINE_CMPLX2,            /* Function <p1> not inlined because it contains too */
+                       /* many operations.  Increase max_inst_hard in order */
+                       /* to inline it: -xinline_param=max_inst_hard:n */
+CCM_NINLINE_RARE,              /* Function <p1> not inlined because the call */
+                       /* is rarely executed */
+CCM_NINLINE_PAR2,              /* Function <p1> not inlined because it is called */
+                       /* within a region guarded by an explicit */
+                       /* parallel pragmas */
+CCM_NINLINE_G_LIMIT,           /* Function <p1> not inlined because it would exceed */
+                       /* the permitted global code size growth limit.  Try */
+                       /* to increase max_growth in order to inline it: */
+                       /* -xinline_param=max_growth:n */
+CCM_NINLINE_L_LIMIT,           /* Function <p1> not inlined because it would exceed */
+                       /* the maximum function size growth limit.  Increase */
+                       /* max_function_inst in order to inline it: */
+                       /* -xinline_param=max_function_inst:n */
+CCM_NINLINE_REC2,              /* Recursive function <p1> is inlined only up to */
+                       /* <i2> levels and up to <i3> size.  Increase */
+                       /* max_recursive_deptha or max_recursive_inst in */
+                       /* order to inline it: */
+                       /* -xinline_param=max_recursive_depth:n, */
+                       /* -xinline_param=max_recursive_inst:n */
+CCM_NINLINE_FB2,               /* Function <p1> not inlined because the */
+                       /* profile-feedback execution count is too */
+                       /* low.  Decrease min_counter in order to inline it: */
+                       /* -xinline_param:min_counter:n */
+CCM_NINLINE_CS_CMPLX,          /* Function <p1> not inlined because called */
+                       /* function's size is too big.  Increase */
+                       /* max_inst_soft in order to inline it: */
+                       /* -xinline_param=max_inst_soft:n */
+CCM_NINLINE_R_EXCPT,           /* Function <p1> not inlined because it contains */
+                       /* an exception handler */
+CCM_NINLINE_ASM,               /* Function <p1> not inlined because */
+                       /* it contains asm statements */
+CCM_NINLINE_R_READONLYIR,      /* Function <p1> not inlined because it is in a file */
+                       /* specified as read-only by -xipo_archive=readonly */
+                       /* and it is a static function */
+CCM_NINLINE_C_READONLYIR,      /* Call to <p1> not inlined because the calling */
+                       /* function is in a file specified as read-only */
+                       /* by -xipo_archive=readonly */
+CCM_NINLINE_NEVERRETURN,       /* Function <p1> not inlined because it */
+                       /* never returns */
+
+  /* Group: Messages Concerning Memory Operations */
+  /*   Notes: */
+  /*   a.  In all of these, <s1> is a string that is something like */
+  /*   "A(i+5*k)" or "structure.field", giving the high-level */
+  /*   construct that is being loaded or stored. */
+  /*    */
+  /*   b.  In all of these, <x2> refers to an instruction offset, */
+  /*   expressed as a 32-bit signed integer.  It is assumed */
+  /*   that any prefetches will be within this range of the */
+  /*   load/store they are prefetching for. */
+CCM_MPREFETCH=0x08000,         /* Prefetch of <s1> inserted */
+                       /* [This message has a lineno for the source, */
+                       /* but no instaddr for the disassembly.] */
+CCM_MPREFETCH_LD,              /* Prefetch of <s1> inserted for load at <x2> */
+                       /* [This message has lineno = -1, */
+                       /* and is for disassembly only] */
+CCM_MPREFETCH_ST,              /* Prefetch of <s1> inserted for store at <x2> */
+                       /* [This message has lineno = -1, */
+                       /* and is for disassembly only] */
+CCM_MPREFETCH_FB,              /* Prefetch of <s1> inserted based on feedback data */
+                       /* [This message has a lineno for the source, */
+                       /* but no instaddr for the disassembly.] */
+CCM_MPREFETCH_FB_LD,           /* Prefetch of <s1> inserted for load at <x2> based */
+                       /* on feedback data */
+                       /* [This message has lineno = -1, */
+                       /* and is for disassembly only] */
+CCM_MPREFETCH_FB_ST,           /* Prefetch of <s1> inserted for store at <x2> based */
+                       /* on feedback data */
+                       /* [This message has lineno = -1, */
+                       /* and is for disassembly only] */
+CCM_MLOAD,                     /* Load below refers to <s1> */
+                       /* [This message has lineno = -1, */
+                       /* and is for disassembly only] */
+CCM_MSTORE,                    /* Store below refers to <s1> */
+                       /* [This message has lineno = -1, */
+                       /* and is for disassembly only] */
+CCM_MLOAD_P,                   /* Load below refers to <s1>, and was prefetched */
+                       /* at <x2> */
+                       /* [This message has lineno = -1, */
+                       /* and is for disassembly only] */
+CCM_MSTORE_P,                  /* Store below refers to <s1>, and was prefetched */
+                       /* at <x2> */
+                       /* [This message has lineno = -1, */
+                       /* and is for disassembly only] */
+
+  /* Group: Front-end messages [all compilers] */
+  /* Group: F95 Front-end Messages */
+CCM_COPYIN=0x10000,            /* Parameter <i1> caused a copyin in the following */
+                       /* call */
+CCM_COPYOUT,                   /* Parameter <i1> caused a copyout in the following */
+                       /* call */
+CCM_COPYINOUT,                 /* Parameter <i1> caused both a copyin and copyout */
+                       /* in the following call */
+CCM_PADDING,                   /* Padding of <i1> bytes inserted before */
+                       /* array <v2> */
+CCM_PADCOMMON,                 /* Padding of <i1> bytes inserted before */
+                       /* array <v2> in common block <v3> */
+CCM_ALIGN_EQ,                  /* Variable/array <v1> can not be double-aligned, */
+                       /* because it is equivalenced */
+CCM_ALIGN_PERF,                /* Alignment of variables in common block may cause */
+                       /* performance degradation */
+CCM_ALIGN_STRUCT,              /* Alignment of component <s1> in numeric sequence */
+                       /* structure <s2> may cause performance degradation */
+CCM_TMP_COPY,                  /* Argument <v1> copied to a temporary */
+CCM_TMP_COPYM,                 /* Argument <v1> might be copied to a temporary; */
+                       /* runtime decision made */
+CCM_PROC_MISMATCH,             /* Argument <i1> to subprogram <p2> differs from */
+                       /* reference on line <i3> */
+CCM_PROC_MISMATCH2,            /* Scalar argument <i1> to subprogram <p2> is */
+                       /* referred to as an array on line <i3> */
+CCM_PROC_MISMATCH3,            /* Return type/rank from subprogram <p1> differs */
+                       /* from return on line <i2> */
+CCM_DO_EXPR,                   /* DO statement bounds lead to no executions of the */
+                       /* loop */
+CCM_AUTO_BND,                  /* The bounds for automatic variable <v1> are not */
+                       /* available at all entry points; zero-length */
+                       /* variable might be allocated */
+CCM_LIT_PAD,                   /* The character string literal <s1> padded */
+                       /* to the length specified for the dummy argument */
+CCM_ARRAY_LOOP,                /* Array statement below generated a loop */
+CCM_ARRAY_LOOPNEST,            /* Array statement below generated <i1> nested loops */
+CCM_ALIGN_PERF2,               /* Alignment of variable <v1> in common block <v2> */
+                       /* may cause a performance degradation */
+CCM_ALIGN_PERF3,               /* Alignment of variable <v1> in blank common may */
+                       /* cause a performance degradation */
+CCM_IO_LOOP_ARRAY,             /* I/O implied do item below generated an array */
+                       /* section */
+
+  /* Group: C++ Front-end Messages */
+CCM_TMPCONST,                  /* Implicit invocation of class <s1> constructor for */
+                       /* temporary */
+CCM_TMPDEST,                   /* Implicit invocation of class <s1> destructor for */
+                       /* temporary */
+CCM_DBL_CONST,                 /* Double constant <s1> used in float expression */
+CCM_MINLINE,                   /* Function <p1> inlined from source file <s2> by */
+                       /* front-end */
+                       /* [This refers to front-end inlining, */
+                       /* not the backend inlining above.] */
+CCM_MINLINE2,                  /* Function <p1> from source file <s2> inlined into */
+                       /* inline copy of method <p3> by front-end */
+                       /* [This refers to front-end inlining, */
+                       /* not the backend inlining above.] */
+CCM_MINLINE3,                  /* Function <p1> not inlined because it uses keyword */
+                       /* <s2> */
+CCM_MINLINE4,                  /* Function <p1> not inlined because it is too */
+                       /* complex */
+CCM_TMP_COPYOUT,               /* Argument <v1> copied from a temporary */
+CCM_TMP_COPYOUTM,              /* Argument <v1> might be copied from a temporary; */
+                       /* runtime decision made */
+CCM_TMP_COPYINOUT,             /* Argument <v1> copied in and out of a temporary */
+CCM_TMP_COPYINOUTM,            /* Argument <v1> might be copied in and out of */
+                       /* a temporary; runtime decision made */
+
+  /* Group: C Front-end Messages */
+  /* Group: NJC Front-end Messages */
+  /* Group: Updated F95 Front-end Messages */
+CCM_ARRAY_LOOP_2,              /* Array statement below generated loop <l1> */
+CCM_ARRAY_LOOPNEST_2,          /* Array statement below generated <i1> nested */
+                       /* loops: <l2>, <l3>, ... */
+                       /* [The number of parameters will determine how many */
+                       /* names appear, and the formatter will get the */
+                       /* commas right.] */
+CCM_IO_LOOP_ARRAY_2,           /* I/O implied do item below generated an array */
+                       /* section: <l1> */
+CCM_USER_LOOP,                 /* Source loop below has tag <l1> */
+CCM_FOUND_LOOP,                /* Discovered loop below has tag <l1> */
+CCM_MFUNCTION_LOOP,            /* Copy in M-function of loop below has tag <l1> */
+
+  /* Group: Code-generator Messages */
+CCM_FSIMPLE=0x20000,           /* Transformations for fsimple=<i1> applied */
+CCM_STACK,                     /* Function <p1> requires <i2> Mbytes of stack */
+                       /* storage */
+CCM_TAILRECUR,                 /* Recursive tail call in <p1> optimized to jump to */
+                       /* entry point */
+CCM_TAILCALL,                  /* Call to function <p1> was tail-call optimized */
+CCM_NI_EXIT_OR_PSEUDO,         /* Template could not be early inlined because it */
+                       /* contains the pseudo instruction <s1> */
+CCM_NI_BAD_UNARY_OPC,          /* Template could not be early inlined because it */
+                       /* contains the instruction opcode <s1> */
+CCM_NI_INT_LDD_ON_V9,          /* Template could not be early inlined because it */
+                       /* contains integer ldd instructions, which are */
+                       /* deprecated in the v9 architecture */
+CCM_NI_LATE_INL_OPC,           /* Template could not be early inlined because it */
+                       /* contains the instruction opcode <s1> */
+CCM_NI_BAD_IMM_OP,             /* Template could not be early inlined because the */
+                       /* relocation or immediate operand <s1> is not well */
+                       /* understood by the optimizer */
+CCM_NI_BAD_STATELEAF,          /* Template could not be early inlined because it */
+                       /* references the state register <s1> */
+CCM_NI_BAD_ASR_19,             /* Template could not be early inlined because */
+                       /* %asr19 is not supported in pre v8plus code */
+CCM_NI_BAD_FSR_USE,            /* Template could not be early inlined because */
+                       /* references to %fsr can only be optimized when the */
+                       /* -iaopts flag is used */
+CCM_NI_BAD_REGISTER,           /* Template could not be early inlined because it */
+                       /* references the register <s1> */
+CCM_NI_NO_RET_VAL,             /* Template could not be early inlined because it */
+                       /* does not return the value declared */
+CCM_NI_DELAY,                  /* Template could not be early inlined because it */
+                       /* contains a non nop delay slot */
+CCM_NI_SCALL,                  /* Template could not be early inlined because it */
+                       /* calls a function which returns a structure */
+CCM_CASE_POSITION,             /* Case block below was placed at position <i1> */
+                       /* based on execution frequency */
+CCM_CALL_WITH_CODE,            /* Call to <p1> replaced with inline code.  <i2> */
+                       /* loops created: <l3>, <l4>, ... */
+CCM_NI_BAD_SP_ADDR,            /* Template could not be early inlined because it */
+                       /* contains a %sp+reg address */
+CCM_NI_BAD_SP_USAGE,           /* Template could not be early inlined because it */
+                       /* uses/defines the stack pointer in a non-load/store instruction */
+CCM_NI_MIXED_REG_TYPES,        /* Template could not be early inlined because it */
+                       /* contains register <s1> used as both x-register and register pair */
+CCM_LAST
+} COMPMSG_ID;
+/*
+ * The Message Structure
+ * Each message is a fixed-length structure as follows:
+ */
+typedef struct
+{
+  int64_t instaddr;     /* the PC offset, relative to the .o .text section */
+  int32_t lineno;       /* the source line to which it refers */
+  COMPMSG_ID msg_type;  /* the specific message index */
+  int32_t nparam;       /* number of parameters to this message */
+  int32_t param_index;  /* the index of the first parameter */
+} compmsg;
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+  /*
+   * Initializes the data structures, converts the source name to a string,
+   * and fills in srcname and version in the header
+   */
+  void compcom_p_open (char *srcname, int32_t version);
+
+  /*
+   * Finds or enters the string s into the string table, and returns the index
+   * of the string
+   */
+  int32_t compcom_p_string (char *s);
+
+  /*
+   * Enter the single message.  Any string parameters should have been converted
+   * to int32's by calling compcom_p_string()
+   */
+  void compcom_p_putmsg (int32_t show_bits, int64_t pcoffset, int32_t lineno,
+                        COMPMSG_ID m, int32_t nparams);
+
+  /*
+   * Whatever is needed to close the section and write it out to the .o
+   */
+  void compcom_p_finalize ();
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _COMP_COM_H */
diff --git a/gprofng/src/count.cc b/gprofng/src/count.cc
new file mode 100644 (file)
index 0000000..6005a49
--- /dev/null
@@ -0,0 +1,237 @@
+/* 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 <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <i18n.h>
+#include <Elf.h>
+#include <collctrl.h>
+#include <StringBuilder.h>
+#include "collect.h"
+
+/* get_count_data -- format exec of bit to do the real work */
+void
+collect::get_count_data ()
+{
+  char command[8192];
+  char *s;
+  struct stat statbuf;
+
+  // reserve space for original args, plus 30 arguments to bit
+  nargs = origargc + 30;
+  char **narglist = (char **) calloc (nargs, sizeof (char *));
+  arglist = narglist;
+
+  // construct the command for bit
+  snprintf (command, sizeof (command), NTXT ("%s"), run_dir);
+  s = strstr_r (command, NTXT ("/bin"));
+  if (s != NULL)
+    {
+      // build command line for launching it
+      snprintf (s, sizeof (command) - (s - command), NTXT ("/lib/compilers/bit"));
+      if (stat (command, &statbuf) == -1)
+       {
+         // if bit command does not exist there
+         char *first_look = strdup (command);
+         snprintf (command, sizeof (command), NTXT ("%s"), run_dir);
+         s = strstr (command, NTXT ("/bin"));
+         snprintf (s, sizeof (command) - (s - command), NTXT ("/prod/bin/bit"));
+         if (stat (command, &statbuf) == -1)
+           {
+             // if bit command does not exist
+             dbe_write (2, GTXT ("bit is not installed as `%s' or `%s'\nNo experiment is possible\n"), first_look, command);
+             exit (2);
+           }
+         free (first_look);
+       }
+      *arglist++ = strdup (command);
+    }
+  else
+    {
+      dbe_write (2, GTXT ("collect can't find install bin directory\n"));
+      exit (1);
+    }
+
+  // Tell it to collect data
+  *arglist++ = NTXT ("collect");
+
+  // add the flag for real-data vs. static data
+  switch (cc->get_count ())
+    {
+    case -1:
+      *arglist++ = NTXT ("-i");
+      *arglist++ = NTXT ("static");
+      *arglist++ = NTXT ("-M");
+      break;
+    case 1:
+      *arglist++ = NTXT ("-M");
+      *arglist++ = NTXT ("-u");
+      break;
+    default:
+      abort ();
+    }
+
+  // tell bit to produce an experiment
+  *arglist++ = NTXT ("-e");
+
+  // now copy an edited list of collect options to the arglist
+  char **oargv = origargv;
+
+  // skip the "collect"
+  oargv++;
+  int argc = 1;
+  while (argc != targ_index)
+    {
+      char *p = *oargv;
+      switch (p[1])
+       {
+         // pass these arguments along, with parameter
+       case 'o':
+       case 'd':
+       case 'g':
+       case 'A':
+       case 'C':
+       case 'O':
+       case 'N':
+         *arglist++ = *oargv++;
+         *arglist++ = *oargv++;
+         argc = argc + 2;
+         break;
+       case 'I':
+         *arglist++ = *oargv++; // set the -I flag
+         *arglist++ = *oargv; // and the directory name
+         *arglist++ = NTXT ("-d"); // and the -d flag
+         *arglist++ = *oargv++; // to the same directory name
+         argc = argc + 2;
+         break;
+       case 'n':
+       case 'v':
+         // pass these arguments along as is
+         *arglist++ = *oargv++;
+         argc = argc + 1;
+         break;
+       case 'x':
+         // skip one argument
+         oargv++;
+         argc++;
+         break;
+       case 'c':
+       case 'L':
+       case 'y':
+       case 'l':
+       case 'F':
+       case 'j':
+       case 'J':
+       case 'p':
+       case 's':
+       case 'h':
+       case 'S':
+       case 'm':
+       case 'M':
+       case 'H':
+       case 'r':
+       case 'i':
+         // skip two arguments
+         oargv++;
+         oargv++;
+         argc = argc + 2;
+         break;
+       case 'R':
+       case 'Z':
+       default:
+         // these should never get this far
+         dbe_write (2, GTXT ("unexpected argument %s\n"), p);
+         abort ();
+       }
+    }
+
+  // now copy the target and its arguments
+  if (access (prog_name, X_OK) != 0)    // not found
+    *arglist++ = *oargv++;
+  else
+    {
+      oargv++;
+      *arglist++ = prog_name;
+    }
+  while (*oargv != NULL)
+    *arglist++ = *oargv++;
+
+  /* now we have the full argument list composed; if verbose, print it */
+  if ((verbose == 1) || (disabled))
+    {
+      /* describe the experiment */
+      char *ccret = cc->show (0);
+      if (ccret != NULL)
+       {
+         writeStr (2, ccret);
+         free (ccret);
+       }
+      ccret = cc->show_expt ();
+      if (ccret != NULL)
+       {
+         /* write this to stdout */
+         writeStr (1, ccret);
+         free (ccret);
+       }
+      /* print the arguments to bit */
+      arglist = narglist;
+      StringBuilder sb;
+      sb.append (NTXT ("Exec argv[] = "));
+      for (int ret = 0; ret < nargs; ret++)
+       {
+         if (narglist[ret] == NULL)
+           break;
+         if (ret > 0)
+           sb.append (NTXT (" "));
+         sb.append (narglist[ret]);
+       }
+      sb.append (NTXT ("\n\n"));
+      write (2, sb.toString (), sb.length ());
+    }
+
+  /* check for dry run */
+  if (disabled)
+    exit (0);
+
+  /* ensure original outputs restored for target */
+  reset_output ();
+
+  /* now exec the bit to instrument and run the target ... */
+  // (void) execve( *narglist, narglist, origenvp);
+  (void) execvp (*narglist, narglist);
+
+  /* exec failed; no experiment to delete */
+  /* restore output for collector */
+  set_output ();
+  char *em = strerror (errno);
+  if (em == NULL)
+    dbe_write (2, GTXT ("execve of %s failed: errno = %d\n"), narglist[0], errno);
+  else
+    dbe_write (2, GTXT ("execve of %s failed: %s\n"), narglist[0], em);
+  exit (1);
+}
diff --git a/gprofng/src/data_pckts.h b/gprofng/src/data_pckts.h
new file mode 100644 (file)
index 0000000..93d0307
--- /dev/null
@@ -0,0 +1,595 @@
+/* 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 _DATA_PCKTS_H
+#define _DATA_PCKTS_H
+
+/*
+ * This file contains structure definitions for the binary file formats
+ * used in the experiment.  It is implemented as C header file so that
+ * it can be processed by both ANSI-C and C++.
+ */
+
+#include <pthread.h>
+#include <stdint.h>
+
+#include "gp-defs.h"
+#include "gp-time.h"
+
+#if WSIZE(64)
+typedef uint64_t Vaddr_type;    /* process address for 64 bit apps */
+typedef uint64_t Size_type;     /* size_t for 64 bit apps */
+#else
+typedef uint32_t Vaddr_type;    /* process address */
+typedef uint32_t Size_type;     /* size_t for 32 bit apps */
+#endif
+
+/* marker to indicate dump of O7 register on stack (support for leaf routines) */
+#define SP_LEAF_CHECK_MARKER    ((uint64_t)(-1))
+
+/* marker to indicate truncated stack */
+#define SP_TRUNC_STACK_MARKER   ((uint64_t)(-2))
+
+/* marker to indicate failed stack unwind */
+#define SP_FAILED_UNWIND_MARKER ((uint64_t)(-3))
+
+#define PROFILE_BUFFER_CHUNK    16384
+
+typedef enum
+{
+  MASTER_SMPL = 0,
+  PROGRAM_SMPL,
+  PERIOD_SMPL,
+  MANUAL_SMPL
+} Smpl_type;
+
+typedef enum
+{ /* values for "profpckt kind" stored in log.xml */
+  EMPTY_PCKT = 0,
+  PROF_PCKT,
+  SYNC_PCKT,
+  HW_PCKT,
+  XHWC_PCKT,
+  HEAP_PCKT,
+  MPI_PCKT,
+  MHWC_PCKT,
+  OPROF_PCKT,
+  OMP_PCKT,
+  RACE_PCKT,
+  FRAME_PCKT,
+  OMP2_PCKT,
+  DEADLOCK_PCKT,
+  OMP3_PCKT,
+  OMP4_PCKT,
+  OMP5_PCKT,
+  UID_PCKT,
+  FRAME2_PCKT,
+  IOTRACE_PCKT,
+  LAST_PCKT,            /* last data packet type */
+  CLOSED_PCKT = 65535   /*  -1, this packet closes a block */
+} Pckt_type;
+
+typedef enum
+{
+  EMPTY_INFO = 0,
+  STACK_INFO,
+  JAVA_INFO,
+  OMP_INFO,
+  MPI_INFO,
+  OMP2_INFO,
+  LAST_INFO             /* keep this one last */
+} Info_type;
+
+#define COMPRESSED_INFO 0x80000000
+
+#define JAVA_PCKT       0x80
+#define OMPS_PCKT       0x40  /* packet contains OMP state info */
+#define PCKT_TYPE(x)    ((x) & 0x1f)
+
+typedef struct CommonHead_packet
+{
+  unsigned int tsize : 16;
+  unsigned int type : 16;
+} CommonHead_packet;
+
+// All collector modules record their packets as extensions of CM_Packet
+typedef struct CM_Packet
+{
+  unsigned int tsize : 16;
+  unsigned int type : 16;
+} CM_Packet;
+
+typedef struct Common_packet
+{
+  unsigned int tsize : 16; /* packet size  */
+  unsigned int type : 16;
+  pthread_t    lwp_id;
+  pthread_t    thr_id;
+  uint32_t     cpu_id;
+  hrtime_t     tstamp;
+  uint64_t     frinfo;
+} Common_packet;
+
+/* Definition of values stored in the experiment PROP_MSTATE field */
+/* They include:
+ *   LWP microstates (copied from msacct.h).  Also see PrUsage class.
+ *   Linux's CPU time
+ *   er_kernel time
+ */
+/*   Can be used with LMS_STATE_STRINGS (below) */
+#define LMS_USER        0   /* running in user mode */
+#define LMS_SYSTEM      1   /* running in sys call or page fault */
+#define LMS_TRAP        2   /* running in other trap */
+#define LMS_TFAULT      3   /* asleep in user text page fault */
+#define LMS_DFAULT      4   /* asleep in user data page fault */
+#define LMS_KFAULT      5   /* asleep in kernel page fault */
+#define LMS_USER_LOCK   6   /* asleep waiting for user-mode lock */
+#define LMS_SLEEP       7   /* asleep for any other reason */
+#define LMS_WAIT_CPU    8   /* waiting for CPU (latency) */
+#define LMS_STOPPED     9   /* stopped (/proc, jobcontrol, or lwp_stop) */
+#define LMS_LINUX_CPU   10  /* LINUX timer_create(CLOCK_THREAD_CPUTIME_ID) */
+#define LMS_KERNEL_CPU  11  /* LINUX timer_create(CLOCK_THREAD_CPUTIME_ID) */
+#define LMS_NUM_STATES  12  /* total number of above states */
+#define LMS_NUM_SOLARIS_MSTATES     10  /* LMS microstates thru LMS_STOPPED */
+
+// Magic value stored in experiments that identifies which LMS states are valid
+#define LMS_MAGIC_ID_SOLARIS        10  // Solaris: LMS_USER thru LMS_STOPPED
+#define LMS_MAGIC_ID_ERKERNEL_USER   2  // er_kernel user: LMS_USER, LMS_SYSTEM
+#define LMS_MAGIC_ID_ERKERNEL_KERNEL 3  // er_kernel kernel: LMS_KERNEL_CPU
+#define LMS_MAGIC_ID_LINUX           1  // Linux: LMS_LINUX_CPU
+
+#define LMS_STATE_STRINGS \
+{ \
+  NTXT("USER"),         /* LMS_USER */ \
+  NTXT("SYSTEM"),       /* LMS_SYSTEM */ \
+  NTXT("TRAP"),         /* LMS_TRAP */ \
+  NTXT("TFAULT"),       /* LMS_TFAULT */ \
+  NTXT("DFAULT"),       /* LMS_DFAULT */ \
+  NTXT("KFAULT"),       /* LMS_KFAULT */ \
+  NTXT("USER_LOCK"),    /* LMS_USER_LOCK */ \
+  NTXT("SLEEP"),        /* LMS_SLEEP */ \
+  NTXT("WAIT_CPU"),     /* LMS_WAIT_CPU */ \
+  NTXT("STOPPED"),      /* LMS_STOPPED */ \
+  NTXT("LINUX_CPU"),    /* LMS_LINUX_CPU */ \
+  NTXT("KERNEL_CPU")    /* LMS_KERNEL_CPU */ \
+}
+#define LMS_STATE_USTRINGS \
+{ \
+  GTXT("User CPU"),             /* LMS_USER */ \
+  GTXT("System CPU"),           /* LMS_SYSTEM */ \
+  GTXT("Trap CPU"),             /* LMS_TRAP */ \
+  GTXT("Text Page Fault"),      /* LMS_TFAULT */ \
+  GTXT("Data Page Fault"),      /* LMS_DFAULT */ \
+  GTXT("Kernel Page Fault"),    /* LMS_KFAULT */ \
+  GTXT("User Lock"),            /* LMS_USER_LOCK */ \
+  GTXT("Sleep"),                /* LMS_SLEEP */ \
+  GTXT("Wait CPU"),             /* LMS_WAIT_CPU */ \
+  GTXT("Stopped"),              /* LMS_STOPPED */ \
+  GTXT("User+System CPU"),      /* LMS_LINUX_CPU */ \
+  GTXT("Kernel CPU")            /* LMS_KERNEL_CPU */ \
+}
+
+typedef enum
+{
+  MALLOC_TRACE = 0,
+  FREE_TRACE,
+  REALLOC_TRACE,
+  MMAP_TRACE,
+  MUNMAP_TRACE,
+  HEAPTYPE_LAST
+} Heap_type;
+
+#define HEAPTYPE_STATE_STRINGS \
+{ \
+    NTXT("MALLOC"), \
+    NTXT("FREE"), \
+    NTXT("REALLOC"), \
+    NTXT("MMAP"), \
+    NTXT("MUNMAP") \
+}
+#define HEAPTYPE_STATE_USTRINGS \
+{ \
+    GTXT("malloc"), \
+    GTXT("free"), \
+    GTXT("realloc"), \
+    GTXT("mmap"), \
+    GTXT("munmap") \
+}
+
+typedef enum
+{
+  ZFS_TYPE = 0,
+  NFS_TYPE,
+  UFS_TYPE,
+  UDFS_TYPE,
+  LOFS_TYPE,
+  VXFS_TYPE,
+  TMPFS_TYPE,
+  PCFS_TYPE,
+  HSFS_TYPE,
+  PROCFS_TYPE,
+  FIFOFS_TYPE,
+  SWAPFS_TYPE,
+  CACHEFS_TYPE,
+  AUTOFS_TYPE,
+  SPECFS_TYPE,
+  SOCKFS_TYPE,
+  FDFS_TYPE,
+  MNTFS_TYPE,
+  NAMEFS_TYPE,
+  OBJFS_TYPE,
+  SHAREFS_TYPE,
+  EXT2FS_TYPE,
+  EXT3FS_TYPE,
+  EXT4FS_TYPE,
+  UNKNOWNFS_TYPE,
+  FSTYPE_LAST
+} FileSystem_type;
+
+typedef enum
+{
+  READ_TRACE = 0,
+  WRITE_TRACE,
+  OPEN_TRACE,
+  CLOSE_TRACE,
+  OTHERIO_TRACE,
+  READ_TRACE_ERROR,
+  WRITE_TRACE_ERROR,
+  OPEN_TRACE_ERROR,
+  CLOSE_TRACE_ERROR,
+  OTHERIO_TRACE_ERROR,
+  IOTRACETYPE_LAST
+} IOTrace_type;
+
+#define IOTRACETYPE_STATE_STRINGS \
+{ \
+  NTXT("READ"), \
+  NTXT("WRITE"), \
+  NTXT("OPEN"), \
+  NTXT("CLOSE"), \
+  NTXT("OTHERIO"), \
+  NTXT("READERROR"), \
+  NTXT("WRITEERROR"), \
+  NTXT("OPENERROR"), \
+  NTXT("CLOSEERROR"), \
+  NTXT("OTHERIOERROR") \
+}
+#define IOTRACETYPE_STATE_USTRINGS \
+{ \
+  GTXT("Read"), \
+  GTXT("Write"), \
+  GTXT("Open"), \
+  GTXT("Close"), \
+  GTXT("Other I/O"), \
+  GTXT("Read error"), \
+  GTXT("Write error"), \
+  GTXT("Open error"), \
+  GTXT("Close error"), \
+  GTXT("Other I/O error") \
+}
+
+// the type of racing memory access with redundance flag
+typedef enum
+{
+  WRITE_RACE = 0,
+  WRITE_RACE_RED,
+  READ_RACE,
+  READ_RACE_RED,
+  RACETYPE_LAST
+} Race_type;
+
+typedef struct Frame_packet
+{
+  unsigned int tsize : 16; /* packet size */
+  unsigned int type : 16;
+  uint32_t hsize;           /* header size */
+  uint64_t uid;             /* unique id (experiment wide) */
+} Frame_packet;
+
+typedef struct Uid_packet
+{
+  unsigned int tsize : 16;  /* packet size */
+  unsigned int type : 16;
+  uint32_t flags;
+  uint64_t uid;             /* unique id (experiment wide) */
+} Uid_packet;
+
+/*
+ * Components of the variable part of Frame_packet
+ */
+typedef struct Common_info
+{
+  unsigned int hsize;   /* size of this info */
+  unsigned int kind;
+  uint64_t uid;         /* unique id of this info if any */
+} Common_info;
+
+typedef struct Stack_info
+{ /* Native call stack */
+  unsigned int hsize;
+  unsigned int kind;
+  uint64_t uid;
+} Stack_info;
+
+typedef struct Java_info
+{ /* Java call stack */
+  unsigned int hsize;
+  unsigned int kind;
+  uint64_t uid;
+} Java_info;
+
+typedef struct OMP_info
+{ /* OMP thread state */
+  unsigned int hsize;
+  unsigned int kind;
+  uint32_t omp_state;
+  uint32_t pad;
+} OMP_info;
+
+typedef struct OMP2_info
+{ /* OpenMP user call stack */
+  unsigned int hsize;
+  unsigned int kind;
+  uint32_t omp_state;
+  uint32_t pad;
+  uint64_t uid;
+} OMP2_info;
+
+/* OMP thread states as recorded in the experiment */
+/*   Definition of values stored in the experiment PROP_OMPSTATE field */
+
+/*   Can be used with OMP_THR_STATE_STRINGS (below) */
+typedef enum
+{
+  OMP_NO_STATE = 0, /* Not initialized */
+  OMP_OVHD_STATE, /* Overhead */
+  OMP_WORK_STATE, /* Useful work, excluding reduction, master, single, critical */
+  OMP_IBAR_STATE, /* In an implicit barrier */
+  OMP_EBAR_STATE, /* In an explicit barrier */
+  OMP_IDLE_STATE, /* Slave waiting */
+  OMP_SERL_STATE, /* User OMPead not in any OMP parallel region */
+  OMP_RDUC_STATE, /* Reduction */
+  OMP_LKWT_STATE, /* Waiting for lock */
+  OMP_CTWT_STATE, /* Waiting to enter critical section */
+  OMP_ODWT_STATE, /* Waiting to execute an ordered section */
+  OMP_ATWT_STATE, /* Wait for atomic */
+  OMP_TSKWT_STATE, /* Task wait */
+  OMP_LAST_STATE
+} OMP_THR_STATE;
+#define OMP_THR_STATE_STRINGS \
+{ \
+  NTXT("NO"),       /* OMP_NO_STATE */ \
+  NTXT("OVHD"),     /* OMP_OVHD_STATE */ \
+  NTXT("WORK"),     /* OMP_WORK_STATE */ \
+  NTXT("IBAR"),     /* OMP_IBAR_STATE */ \
+  NTXT("EBAR"),     /* OMP_EBAR_STATE */ \
+  NTXT("IDLE"),     /* OMP_IDLE_STATE */ \
+  NTXT("SERL"),     /* OMP_SERL_STATE */ \
+  NTXT("RDUC"),     /* OMP_RDUC_STATE */ \
+  NTXT("LKWT"),     /* OMP_LKWT_STATE */ \
+  NTXT("CTWT"),     /* OMP_CTWT_STATE */ \
+  NTXT("ODWT"),     /* OMP_ODWT_STATE */ \
+  NTXT("ATWT"),     /* OMP_ATWT_STATE */ \
+  NTXT("TSKWT")     /* OMP_TSKWT_STATE */ \
+}
+#define OMP_THR_STATE_USTRINGS \
+{ \
+  GTXT("None"),                 /* OMP_NO_STATE */ \
+  GTXT("Overhead"),             /* OMP_OVHD_STATE */ \
+  GTXT("Work"),                 /* OMP_WORK_STATE */ \
+  GTXT("Implicit Barrier"),     /* OMP_IBAR_STATE */ \
+  GTXT("Explicit Barrier"),     /* OMP_EBAR_STATE */ \
+  GTXT("Idle"),                 /* OMP_IDLE_STATE */ \
+  GTXT("Serial"),               /* OMP_SERL_STATE */ \
+  GTXT("Reduction"),            /* OMP_RDUC_STATE */ \
+  GTXT("Lock Wait"),            /* OMP_LKWT_STATE */ \
+  GTXT("Critical Section Wait"), /* OMP_CTWT_STATE */ \
+  GTXT("Ordered Section Wait"), /* OMP_ODWT_STATE */ \
+  GTXT("Atomic Wait"),          /* OMP_ATWT_STATE */ \
+  GTXT("Task Wait")             /* OMP_TSKWT_STATE */ \
+}
+
+/* sub-packet for MPI state information */
+typedef struct MPI_info
+{ /* MPI thread state */
+  unsigned int hsize;
+  unsigned int kind;
+  uint32_t mpi_state;
+  uint32_t pad;
+} MPI_info;
+
+/* MPI thread states, as recorded in the experiment */
+typedef enum
+{
+  MPI_NO_STATE = 0,     /* Not initialized */
+  MPI_USER,             /* Executing user code, not in MPI */
+  MPI_PROG,             /* Executing in the MPI library (progressing) */
+  MPI_WAIT              /* Waiting in the MPI library */
+} MPI_THR_STATE;
+
+/*
+ *     Dyntext file structure
+ */
+typedef enum
+{
+  DT_HEADER = 1,
+  DT_CODE,
+  DT_LTABLE,
+  DT_SRCFILE
+} DT_type;
+
+typedef struct DT_common
+{
+  DT_type type;
+  unsigned int size;
+} DT_common;
+
+typedef struct DT_header
+{
+  DT_type type;
+  unsigned int size;
+  hrtime_t time; /* time of loading */
+  uint64_t vaddr;
+} DT_header;
+
+typedef struct DT_code
+{
+  DT_type type;
+  unsigned int size;
+} DT_code;
+
+typedef struct DT_ltable
+{
+  DT_type type;
+  unsigned int size;
+} DT_ltable;
+
+typedef struct DT_lineno
+{
+  unsigned int offset;
+  unsigned int lineno;
+} DT_lineno;
+
+typedef struct DT_srcfile
+{
+  DT_type type;
+  unsigned int size;
+} DT_srcfile;
+
+/*
+ *     Archive file structure
+ */
+#define ARCH_VERSION 0x100 /* version 1.0 */
+
+/* For compatibility with older archives append new types only */
+typedef enum
+{
+  ARCH_SEGMENT_TYPE = 1,
+  ARCH_MSG_TYPE,
+  ARCH_PLT_TYPE,
+  ARCH_MODULE_TYPE,
+  ARCH_FUNCTION_TYPE,
+  ARCH_LDINSTR_TYPE,
+  ARCH_STINSTR_TYPE,
+  ARCH_PREFETCH_TYPE,
+  ARCH_BRTARGET_TYPE,
+  ARCH_JCLASS_TYPE,
+  ARCH_JMETHOD_TYPE,
+  ARCH_JUNLOAD_TYPE,
+  ARCH_INF_TYPE,
+  ARCH_JCLASS_LOCATION_TYPE
+} ARCH_type;
+
+#define ARCH_TYPE(x,y)      ((ARCH_##x##_TYPE<<8)|y)
+
+typedef struct
+{
+  unsigned int type : 16;
+  unsigned int size : 16;
+} ARCH_common;
+
+/* The maximum value that fits into ARCH_common.size */
+#define ARCH_MAX_SIZE 0xffff
+
+#define ARCH_SEGMENT ARCH_TYPE(SEGMENT, 0)
+
+typedef struct
+{
+  ARCH_common common;
+  int version;
+  uint32_t inode;
+  uint32_t textsz;      /* text segment size */
+  uint32_t platform;    /* sparc, intel, etc. */
+} ARCH_segment;
+
+#define ARCH_MSG ARCH_TYPE(MSG, 0)
+
+typedef struct
+{
+  ARCH_common common;
+  uint32_t errcode;
+} ARCH_message;
+
+#define ARCH_INF ARCH_TYPE(INF, 0)
+
+typedef struct
+{
+  ARCH_common common;
+} ARCH_info;
+
+#define ARCH_MODULE ARCH_TYPE(MODULE, 0)
+
+typedef struct
+{
+  ARCH_common common;
+  unsigned int lang_code;
+  unsigned int fragmented;
+} ARCH_module;
+
+#define ARCH_FUNCTION ARCH_TYPE(FUNCTION, 0)
+
+typedef struct
+{
+  ARCH_common common;
+  uint32_t offset;
+  uint32_t size;
+  uint32_t save_addr;
+} ARCH_function;
+
+#define ARCH_LDINSTR  ARCH_TYPE(LDINSTR, 0)
+#define ARCH_STINSTR  ARCH_TYPE(STINSTR, 0)
+#define ARCH_PREFETCH ARCH_TYPE(PREFETCH, 0)
+#define ARCH_BRTARGET ARCH_TYPE(BRTARGET, 0)
+
+typedef struct
+{
+  ARCH_common common;
+} ARCH_aninfo;
+
+#define ARCH_JCLASS_LOCATION ARCH_TYPE(JCLASS_LOCATION, 3)
+
+typedef struct
+{
+  CM_Packet comm;
+  uint32_t pad;
+  uint64_t class_id;
+} ARCH_jclass_location;
+
+#define ARCH_JCLASS ARCH_TYPE(JCLASS, 3)
+
+typedef struct
+{
+  CM_Packet comm;
+  uint32_t pad;
+  uint64_t class_id;
+  hrtime_t tstamp;
+} ARCH_jclass;
+
+#define ARCH_JMETHOD ARCH_TYPE(JMETHOD, 3)
+
+typedef struct
+{
+  CM_Packet comm;
+  uint32_t pad;
+  uint64_t class_id;
+  uint64_t method_id;
+} ARCH_jmethod;
+
+#endif /* _DATA_PCKTS_H */
diff --git a/gprofng/src/dbe_collctrl.cc b/gprofng/src/dbe_collctrl.cc
new file mode 100644 (file)
index 0000000..9219a8e
--- /dev/null
@@ -0,0 +1,28 @@
+/* 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 "config.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "i18n.h"
+
+#include "collctrl.cc"
diff --git a/gprofng/src/dbe_hwc.h b/gprofng/src/dbe_hwc.h
new file mode 100644 (file)
index 0000000..74b6838
--- /dev/null
@@ -0,0 +1,38 @@
+/* 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 dbe_hwc_h
+#define dbe_hwc_h
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "i18n.h"
+
+#define HWC_TRACELEVEL -1
+#if HWC_TRACELEVEL < 0
+#define TprintfT(x1,...)
+#define Tprintf(x1,...)
+#else
+#define TprintfT(x1,...) if( x1<=HWC_TRACELEVEL ) fprintf(stderr,__VA_ARGS__)
+#define Tprintf(x1,...)  if( x1<=HWC_TRACELEVEL ) fprintf(stderr,__VA_ARGS__)
+#endif
+
+#endif
diff --git a/gprofng/src/dbe_hwcdrv.c b/gprofng/src/dbe_hwcdrv.c
new file mode 100644 (file)
index 0000000..a471c3e
--- /dev/null
@@ -0,0 +1,23 @@
+/* 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 "dbe_hwc.h"
+#include "hwcdrv.c"
diff --git a/gprofng/src/dbe_hwcfuncs.c b/gprofng/src/dbe_hwcfuncs.c
new file mode 100644 (file)
index 0000000..66d371a
--- /dev/null
@@ -0,0 +1,23 @@
+/* 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 "dbe_hwc.h"
+#include "hwcfuncs.c"
diff --git a/gprofng/src/dbe_hwctable.c b/gprofng/src/dbe_hwctable.c
new file mode 100644 (file)
index 0000000..ce077a1
--- /dev/null
@@ -0,0 +1,23 @@
+/* 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 "dbe_hwc.h"
+#include "hwctable.c"
diff --git a/gprofng/src/dbe_memmgr.c b/gprofng/src/dbe_memmgr.c
new file mode 100644 (file)
index 0000000..2c2e2b4
--- /dev/null
@@ -0,0 +1,118 @@
+/* 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 "util.h"
+
+#define CHECK_OUT_OF_MEM(ptr, size) if (ptr == NULL) err_out_of_memory(size)
+
+/* Report Out of Memory error and exit */
+static void
+err_out_of_memory (unsigned nbytes)
+{
+  char *nm = get_prog_name (1);
+  if (nm)
+    fprintf (stderr, GTXT ("%s: Error: Memory capacity exceeded.\n"), nm);
+  else
+    fprintf (stderr, GTXT ("Error: Memory capacity exceeded.\n"));
+  fprintf (stderr, GTXT ("  Requested %u bytes.\n"), nbytes);
+  exit (16);
+}
+
+#define CALL_REAL(x) (__real_##x)
+#define NULL_PTR(x) ( __real_##x == NULL )
+
+static void *(*__real_malloc)(size_t) = NULL;
+static void (*__real_free)(void *) = NULL;
+static void *(*__real_realloc)(void *, size_t) = NULL;
+static void *(*__real_calloc)(size_t, size_t) = NULL;
+static char *(*__real_strdup)(const char*) = NULL;
+static volatile int in_init = 0;
+
+static int
+init_heap_intf ()
+{
+  in_init = 1;
+  __real_malloc = (void*(*)(size_t))dlsym (RTLD_NEXT, "malloc");
+  __real_free = (void(*)(void *))dlsym (RTLD_NEXT, "free");
+  __real_realloc = (void*(*)(void *, size_t))dlsym (RTLD_NEXT, "realloc");
+  __real_calloc = (void*(*)(size_t, size_t))dlsym (RTLD_NEXT, "calloc");
+  __real_strdup = (char*(*)(const char*))dlsym (RTLD_NEXT, "strdup");
+  in_init = 0;
+  return 0;
+}
+
+/* --------------------------------------------------------------------------- */
+/* libc's memory management functions substitutions */
+
+/* Allocate memory and make sure we got some */
+void *
+malloc (size_t size)
+{
+  if (NULL_PTR (malloc))
+    init_heap_intf ();
+  void *ptr = CALL_REAL (malloc)(size);
+  CHECK_OUT_OF_MEM (ptr, size);
+  return ptr;
+}
+
+
+/* Implement a workaround for a libdl recursion problem */
+void *
+calloc (size_t nelem, size_t size)
+{
+  if (NULL_PTR (calloc))
+    {
+      /* If a program is linked with libpthread then the following
+       * calling sequence occurs:
+       * init_heap_intf -> dlsym -> calloc -> malloc -> init_heap_intf
+       * We break some performance improvement in libdl by returning
+       * NULL but preserve functionality.
+       */
+      if (in_init)
+       return NULL;
+      init_heap_intf ();
+    }
+  return CALL_REAL (calloc)(nelem, size);
+}
+
+/* Free the storage associated with data */
+void
+free (void *ptr)
+{
+  if (ptr == NULL)
+    return;
+  if (NULL_PTR (free))
+    init_heap_intf ();
+  CALL_REAL (free)(ptr);
+  return;
+}
+
+/* Reallocate buffer */
+void *
+realloc (void *ptr, size_t size)
+{
+  if (NULL_PTR (realloc))
+    init_heap_intf ();
+  ptr = CALL_REAL (realloc)(ptr, size);
+  CHECK_OUT_OF_MEM (ptr, size);
+  return ptr;
+}
diff --git a/gprofng/src/dbe_structs.h b/gprofng/src/dbe_structs.h
new file mode 100644 (file)
index 0000000..e6eaed6
--- /dev/null
@@ -0,0 +1,219 @@
+/* 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 _DBE_STRUCTS_H
+#define _DBE_STRUCTS_H
+
+#include "dbe_types.h"
+#include "enums.h"
+
+typedef enum
+{
+  Sp_lang_unknown   = 0,
+  Sp_lang_asm       = 1,
+  Sp_lang_c         = 2,
+  Sp_lang_ansic     = 3,
+  Sp_lang_cplusplus = 4,
+  Sp_lang_fortran   = 5,
+  Sp_lang_pascal    = 6,
+  Sp_lang_fortran90 = 7,
+  Sp_lang_java      = 8,
+  Sp_lang_c99       = 9,
+  Sp_lang_gcc       = 16,
+  Sp_lang_KAI_KPTS  = 32,
+  Sp_lang_KAI_KCC   = 33,
+  Sp_lang_KAI_Kcc   = 34
+} Sp_lang_code;
+
+struct Value
+{
+  union
+  {
+    short s;
+    int i;
+    float f;
+    double d;
+    timestruc_t t;
+    char *l;                // Label
+    unsigned long long ll;  // address
+  };
+};
+
+// sync enum changes with both AnMetric.java and AnVariable.java
+enum ValueTag
+{
+  VT_SHORT = 1,
+  VT_INT,
+  VT_LLONG,
+  VT_FLOAT,
+  VT_DOUBLE,
+  VT_HRTIME,
+  VT_LABEL,
+  VT_ADDRESS,
+  VT_OFFSET,
+  VT_ULLONG
+};
+
+// Tagged numeric value
+struct TValue
+{
+  ValueTag tag;
+  bool sign;    // The print result will always begin with a sign (+ or -).
+  union
+  {
+    short s;
+    int i;
+    float f;
+    double d;
+    char *l;
+    void *p;
+    long long ll;
+    unsigned long long ull;
+  };
+  double to_double ();
+  int to_int ();
+  char *to_str (char *str, size_t strsz);
+  size_t get_len ();
+  void make_delta (TValue *v1, TValue *v2);
+  void make_ratio (TValue *v1, TValue *v2);
+  int compare (TValue *v);
+};
+
+// XXX MAX_HWCOUNT may need to be managed dynamically, not #defined
+#define MAX_HWCOUNT 64
+
+// Experiment collection parameters
+struct Collection_params
+{
+  int profile_mode;     // if clock-profiling is on
+  long long ptimer_usec; // Clock profile timer interval (microseconds)
+  int lms_magic_id;     // identifies which LMS_* states are live
+  int sync_mode;        // if synctrace is on
+  int sync_threshold;   // value of synctrace threshold, in microseconds
+  int sync_scope;       // value of synctrace scope: Java and/or native
+
+  int heap_mode;        // if heaptrace is on
+  int io_mode;          // if iotrace is on
+  int race_mode;        // if race-detection is on
+  int race_stack;       // setting for stack data collection
+  int deadlock_mode;    // if deadlock-detection is on
+  int omp_mode;         // if omptrace is on
+
+  int hw_mode;          // if hw-counter profiling is on
+  int xhw_mode;    // if extended (true-PC) HW counter profiling for any counter
+
+  char *hw_aux_name[MAX_HWCOUNT];
+  char *hw_username[MAX_HWCOUNT];
+  int hw_interval[MAX_HWCOUNT];     // nominal interval for count
+  int hw_tpc[MAX_HWCOUNT];          // non-zero, if aggressive TPC/VA requested
+  int hw_metric_tag[MAX_HWCOUNT];   // tag as used for finding metrics
+  int hw_cpu_ver[MAX_HWCOUNT];      // Chip version number for this metric
+
+  int sample_periodic;      // if periodic sampling is on
+  int sample_timer;         // Sample timer (sec)
+  int limit;                // experiment size limit
+  const char *pause_sig;    // Pause/resume signal string
+  const char *sample_sig;   // Sampling signal string
+  const char *start_delay;  // Data collect start delay string
+  const char *terminate;    // Data collection termination time string
+  char *linetrace;
+};
+
+const hrtime_t ZERO_TIME = (hrtime_t) 0;
+const hrtime_t MAX_TIME = (hrtime_t) 0x7fffffffffffffffLL;
+
+#define PCInvlFlag              ((int) 0x8LL)
+#define PCLineFlag              ((int) 0x4LL)
+#define PCTrgtFlag              ((int) 0x2LL)
+#define MAKE_ADDRESS(idx, off)  (((unsigned long long)(idx)<<32) | off)
+#define ADDRESS_SEG(x)          ((unsigned int)(((x)>>32) & 0xffffffff))
+#define ADDRESS_OFF(x)          ((unsigned int)((x) & 0xffffffff))
+
+//
+//     Analyzer info
+#define AnalyzerInfoVersion 2
+
+typedef struct
+{
+  uint64_t text_labelref;
+  int32_t entries;
+  uint32_t version;
+} AnalyzerInfoHdr;      // => header from .__analyzer_info
+
+typedef struct
+{
+  uint32_t offset;      // offset relative to text_labelref
+  uint32_t id;          // profiled instruction identifier
+  uint32_t signature;   // signature of profiled instruction
+  uint32_t datatype_id; // referenced datatype identifier
+} memop_info_t;         // => used for table_type=0,1,2
+
+typedef struct
+{
+  uint32_t offset;      // offset relative to text_labelref
+} target_info_t;        // => used for table_type=3
+
+typedef struct
+{
+  uint32_t type;
+  uint32_t offset;
+  union
+  {
+    memop_info_t *memop;
+    target_info_t *target;
+  };
+} inst_info_t;
+
+class DataObject;
+
+typedef struct
+{
+  uint32_t datatype_id; // datatype identifier (local)
+  uint32_t memop_refs;  // count of referencing memops
+  uint32_t event_data;  // count of event data
+  DataObject *dobj;     // corresponding dataobject (unique)
+} datatype_t;
+
+typedef struct
+{
+  uint32_t offset;      // entry offset in compilation unit
+  uint32_t extent;      // sibling offset
+  void *parent;         // container symbol
+  void *object;         // resolved object
+} symbol_t;
+
+typedef struct
+{
+  char *old_prefix;
+  char *new_prefix;
+} pathmap_t;
+
+typedef struct
+{
+  char *libname;
+  enum LibExpand expand;
+} lo_expand_t;
+
+typedef struct
+{
+  int index1;
+  int index2;
+} int_pair_t;
+#endif /* _DBE_STRUCTS_H */
diff --git a/gprofng/src/dbe_types.h b/gprofng/src/dbe_types.h
new file mode 100644 (file)
index 0000000..79fd6c7
--- /dev/null
@@ -0,0 +1,62 @@
+/* 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 _DBE_TYPES_H
+#define _DBE_TYPES_H
+
+#include <stdint.h>
+#include "gp-time.h"
+
+typedef unsigned long long Size;    /* object sizes in 64 bit apps */
+typedef unsigned long long Vaddr;   /* process address for 64 bit apps */
+
+typedef unsigned long long ull_t;
+typedef long long ll_t;
+typedef unsigned long ul_t;
+
+// Note: these values are stored in archive files; changing them
+// may cause old archives to become incompatible.
+enum Platform_t
+{
+  Unknown = 0,
+  Sparc,
+  Sparcv9,
+  Intel,
+  Sparcv8plus,
+  Java,
+  Amd64,
+  Aarch64
+};
+
+enum WSize_t
+{
+  Wnone,
+  W32,
+  W64
+};
+
+enum VMode
+{
+  VMODE_MACHINE = 0,
+  VMODE_USER,
+  VMODE_EXPERT
+};
+
+#endif /* _DBE_TYPES_H */
diff --git a/gprofng/src/debug.h b/gprofng/src/debug.h
new file mode 100644 (file)
index 0000000..9761f2a
--- /dev/null
@@ -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 _PERFAN_DEBUG_H
+#define _PERFAN_DEBUG_H
+
+extern unsigned int mpmt_debug_opt;
+// To set mpmt_debug_opt use:
+//   MPMT_DEBUG=4095 ; export MPMT_DEBUG
+#define DEBUG_FLAG          (mpmt_debug_opt & 1)
+#define DUMP_ELF_SEC        (mpmt_debug_opt & 2)
+#define DUMP_ELF_SYM        (mpmt_debug_opt & 4)
+#define DUMP_RELA_SEC       (mpmt_debug_opt & 8)
+#define DUMP_ELF_RELOC      DUMP_RELA_SEC
+#define DUMP_DWARFLIB       (mpmt_debug_opt & 16)
+#define DUMP_DWR_LINE_REGS  (mpmt_debug_opt & 32)
+#define DUMP_USER_LABELS    (mpmt_debug_opt & 64)
+#define DEBUG_MAPS          (mpmt_debug_opt & 128)
+#define DEBUG_DBE_FILE      (mpmt_debug_opt & 256)
+#define DEBUG_DATA_WINDOW   (mpmt_debug_opt & 512)
+#define DEBUG_STABS         (mpmt_debug_opt & 1024)
+#define DEBUG_DATAOBJ       (mpmt_debug_opt & 2048)
+#define DEBUG_LOADOBJ       (mpmt_debug_opt & 4096)
+#define DEBUG_SAXPARSER     (mpmt_debug_opt & 8192)
+#define DUMP_JAVA_CLASS     (mpmt_debug_opt & 16384)
+#define DEBUG_COMPARISON    (mpmt_debug_opt & 32768)
+#define DEBUG_READ_AR       (mpmt_debug_opt & 65536)
+#define DEBUG_ERR_MSG       (mpmt_debug_opt & 131072)
+#define DUMP_JCLASS_READER  (mpmt_debug_opt & 262144)
+#define DEBUG_DBE           (mpmt_debug_opt & 524288)
+#define DEBUG_ARCHIVE       (mpmt_debug_opt & 1048576)
+#define DEBUG_IO            (mpmt_debug_opt & 2097152)
+#define DUMP_DYN_FILE       (mpmt_debug_opt & 4194304)
+#define DUMP_JAR_FILE       (mpmt_debug_opt & 8388608)
+#define DUMP_CALL_STACK     (mpmt_debug_opt & 16777216)
+#define DEBUG_THREADS       (mpmt_debug_opt & 33554432)
+#define DBE_USE_MMAP        (mpmt_debug_opt & 67108864)
+
+#ifdef DEBUG
+
+// Turn on assertion checking whenever debugging
+#define ASSERTS 1
+
+// debug macro - provides a clean way of inserting debugging code without
+//  having the distracting #ifdef DEBUG ... #else ... #endif directives
+//  interspersed throughout the code.  It also provides an easy way
+//  to turn them off with no loss of efficiency.  It is not limited
+//  to printf() commands; any code may be inserted.  Variables
+//  needed only by the debugging code can be declared inside a
+//  debug { ... } statement.
+//
+// usage:
+//      debug <statement>
+//  or,        debug { <statements> }
+// If DEBUG is on, map "DEBUG_CODE" to nothing!
+// This results in the <statement> being executed normally
+
+#define DEBUG_CODE
+
+#else
+// If DEBUG is off, map "DEBUG_CODE" to something harmless.
+// The clever hack used here is to use a conditional with a
+// constant condition, which is optimized out by the compiler,
+// so that <statement> is not present in the compiled code!
+
+#define DEBUG_CODE if (0)
+
+#endif /*DEBUG*/
+
+#define Dprintf(x, ...) DEBUG_CODE if(x) fprintf(stderr, __VA_ARGS__)
+
+#endif /* ! _DEBUG_H */
diff --git a/gprofng/src/enums.h b/gprofng/src/enums.h
new file mode 100644 (file)
index 0000000..a2c9500
--- /dev/null
@@ -0,0 +1,195 @@
+/* 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 _PERFAN_ENUMS_H
+#define _PERFAN_ENUMS_H
+
+#include "comp_com.h"
+
+enum Cmd_status
+{
+  CMD_OK = 0,
+  CMD_BAD,
+  CMD_AMBIGUOUS,
+  CMD_BAD_ARG,
+  CMD_OUTRANGE,
+  CMD_INVALID
+};
+
+enum LibExpand
+{
+  LIBEX_SHOW    = 0,
+  LIBEX_HIDE    = 1,
+  LIBEX_API     = 2
+};
+
+enum SrcVisible
+{
+  SRC_NA        = 0,
+  SRC_CODE      = 1,
+  SRC_METRIC    = 2
+};
+
+enum MetricType
+{ // sync enum changes with Settings.java
+  MET_NORMAL = 0,   // functions, lines, pcs; src & disasm (non-compare)
+  MET_CALL,         // callers-callees
+  MET_DATA,         // dataspace
+  MET_INDX,         // index objects
+  MET_CALL_AGR,     // call tree
+  MET_COMMON,       // Analyzer uses for DSP_DISASM, DSP_SOURCE, ...
+  MET_IO,           // IO activity
+  MET_SRCDIS,       // src & disasm (non comparison mode)
+  MET_HEAP          // Heap leaked list
+};
+
+enum ValueType
+{ // Bitmask     (!) sync enum changes with AnMetric.java
+  VAL_NA        = 0,  // nothing specified (use this enum instead of 0)
+  VAL_TIMEVAL   = 1,
+  VAL_VALUE     = 2,
+  VAL_PERCENT   = 4,
+  VAL_DELTA     = 8,
+  VAL_RATIO     = 16,
+  VAL_INTERNAL  = 32,
+  VAL_HIDE_ALL  = 64  // hide all, but allows settings to be remembered
+};
+
+enum CompCom
+{ // no value here can be the same as CCMV_
+  COMP_SRC = CCMV_BASIC + 1,
+  COMP_SRC_METRIC,
+  COMP_NOSRC,
+  COMP_HEX,
+  COMP_NOHEX,
+  COMP_THRESHOLD,
+  COMP_CMPLINE,
+  COMP_FUNCLINE
+};
+
+enum TLStack_align
+{
+  TLSTACK_ALIGN_ROOT = 1,
+  TLSTACK_ALIGN_LEAF
+};
+
+enum Reorder_status
+{
+  REORDER_SUCCESS,
+  REORDER_FAIL,
+  REORDER_ZERO,
+  REORDER_ONE_FUNC,
+  REORDER_FILE_OPEN,
+  REORDER_FILE_WRITE,
+  REORDER_COMP,
+  REORDER_NO_LOAD_OBJ,
+  REORDER_NO_OBJECT,
+  REORDER_INVALID
+};
+
+enum AnUtility_state
+{
+  EXP_SUCCESS     = 0,
+  EXP_FAILURE     = 1,
+  EXP_INCOMPLETE  = 2,
+  EXP_BROKEN      = 4,
+  EXP_OBSOLETE    = 8
+};
+
+enum Presentation_align_type
+{
+  TEXT_LEFT     = 1,
+  TEXT_CENTER   = 2,
+  TEXT_RIGHT    = 3
+};
+
+enum Message_type
+{
+  ERROR_MSG     = 1,
+  WARNING_MSG   = 2,
+  PSTAT_MSG     = 3,
+  PWARN_MSG     = 4
+};
+
+enum Presentation_clock_unit
+{
+  CUNIT_NULL    = -1,
+  CUNIT_BYTES   = -2,
+  CUNIT_TIME    = -3
+};
+
+enum FuncListDisp_type
+{
+  DSP_FUNCTION      = 1,
+  DSP_LINE          = 2,
+  DSP_PC            = 3,
+  DSP_SOURCE        = 4,
+  DSP_DISASM        = 5,
+  DSP_SELF          = 6, // not a tab; ID for Callers-Callees fragment data
+  DSP_CALLER        = 7,
+  DSP_CALLEE        = 8, // not a tab; ID for Callers-Callees callees data
+  DSP_CALLTREE      = 9,
+  DSP_TIMELINE      = 10,
+  DSP_STATIS        = 11,
+  DSP_EXP           = 12,
+  DSP_LEAKLIST      = 13,
+  DSP_MEMOBJ        = 14, // requires a specific subtype to define a tab
+  DSP_DATAOBJ       = 15,
+  DSP_DLAYOUT       = 16,
+  DSP_SRC_FILE      = 17, // not a tab; Details information (?)
+  DSP_IFREQ         = 18,
+  DSP_RACES         = 19,
+  DSP_INDXOBJ       = 20, // requires a specific subtype to define a tab
+  DSP_DUALSOURCE    = 21,
+  DSP_SOURCE_DISASM = 22,
+  DSP_DEADLOCKS     = 23,
+  DSP_MPI_TL        = 24,
+  DSP_MPI_CHART     = 25,
+  //DSP_TIMELINE_CLASSIC_TBR   = 26,
+  DSP_SOURCE_V2     = 27, // comparison
+  DSP_DISASM_V2     = 28, // comparison
+  //DSP_THREADS_TL    = 29;
+  //DSP_THREADS_CHART = 30;
+  DSP_IOACTIVITY    = 31,
+  DSP_OVERVIEW      = 32,
+  DSP_IOVFD         = 33,
+  DSP_IOCALLSTACK   = 34,
+  DSP_MINICALLER    = 37,
+  DSP_HEAPCALLSTACK = 39,
+  DSP_CALLFLAME     = 40,
+  DSP_SAMPLE        = 99
+};
+
+enum CmpMode
+{
+  CMP_DISABLE   = 0,
+  CMP_ENABLE    = 1,
+  CMP_RATIO     = 2,
+  CMP_DELTA     = 4
+};
+
+enum PrintMode
+{
+  PM_TEXT = 0,
+  PM_HTML = 1,
+  PM_DELIM_SEP_LIST = 2
+};
+
+#endif // _ENUMS_H
diff --git a/gprofng/src/envsets.cc b/gprofng/src/envsets.cc
new file mode 100644 (file)
index 0000000..de06fbf
--- /dev/null
@@ -0,0 +1,420 @@
+/* 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 <assert.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+#include "gp-defs.h"
+#include "util.h"
+#include "collctrl.h"
+#include "collect.h"
+#include "StringBuilder.h"
+#include "Settings.h"
+
+#define        STDEBUFSIZE     24000
+
+#define LIBGP_COLLECTOR             "libgp-collector.so"
+#define GPROFNG_PRELOAD_LIBDIRS     "GPROFNG_PRELOAD_LIBDIRS"
+#define SP_COLLECTOR_EXPNAME        "SP_COLLECTOR_EXPNAME"
+#define SP_COLLECTOR_FOLLOW_SPEC    "SP_COLLECTOR_FOLLOW_SPEC"
+#define SP_COLLECTOR_PARAMS         "SP_COLLECTOR_PARAMS"
+#define SP_COLLECTOR_FOUNDER        "SP_COLLECTOR_FOUNDER"
+#define SP_COLLECTOR_ORIGIN_COLLECT "SP_COLLECTOR_ORIGIN_COLLECT"
+
+static const char *LD_AUDIT[] = {
+  //    "LD_AUDIT",    Do not set LD_AUDIT on Linux
+  NULL
+};
+
+static const char *LD_PRELOAD[] = {
+  "LD_PRELOAD",
+  NULL
+};
+
+static const char *SP_PRELOAD[] = {
+  "SP_COLLECTOR_PRELOAD",
+  NULL
+};
+
+static const char *LD_LIBRARY_PATH[] = {
+  "LD_LIBRARY_PATH",
+  NULL,
+};
+
+static int
+add_env (char *ev)
+{
+  int r = putenv (ev);
+  if (r != 0)
+    {
+      dbe_write (2, GTXT ("Can't putenv of %s: run aborted\n"), ev);
+      free (ev);
+    }
+  return r;
+}
+
+int
+collect::putenv_libcollector_ld_audits ()
+{
+  StringBuilder sb;
+  for (unsigned int ii = 0; ii < ARR_SIZE (LD_AUDIT) && LD_AUDIT[ii]; ++ii)
+    {
+      sb.sprintf ("%s=%s", LD_AUDIT[ii], SP_LIBAUDIT_NAME);
+      // Append the current value. Check if already set
+      char *old_val = getenv (LD_AUDIT[ii]);
+      if (old_val != NULL)
+       {
+         while (isspace (*old_val))
+           ++old_val;
+         if (*old_val != (char) 0)
+           {
+             int fromIdx = sb.length ();
+             sb.append (" ");
+             sb.append (old_val);
+             if (sb.indexOf (SP_LIBAUDIT_NAME, fromIdx) >= 0)
+               continue;       // Already set. Do nothing.
+           }
+       }
+      if (add_env (sb.toString ()))
+       return 1;
+    }
+  return 0;
+}
+
+int
+collect::putenv_libcollector_ld_preloads ()
+{
+  // for those data types that get extra libs LD_PRELOAD'd, add them
+  if (cc->get_synctrace_mode () != 0)
+    add_ld_preload ("libgp-sync.so");
+  if (cc->get_heaptrace_mode () != 0)
+    add_ld_preload ("libgp-heap.so");
+  if (cc->get_iotrace_mode () != 0)
+    add_ld_preload ("libgp-iotrace.so");
+  add_ld_preload (SP_LIBCOLLECTOR_NAME);
+
+  // --- putenv SP_COLLECTOR_PRELOAD*
+  int ii;
+  for (ii = 0; SP_PRELOAD[ii]; ii++)
+    {
+      // construct the SP_PRELOAD_* environment variables
+      // and put them into the environment
+      if (add_env (dbe_sprintf ("%s=%s", SP_PRELOAD[ii], sp_preload_list[ii])))
+       return 1;
+    }
+  // --- putenv LD_PRELOADS
+  /* purge LD_PRELOAD* of values containing contents of SP_LIBCOLLECTOR_NAME */
+  if (putenv_purged_ld_preloads (SP_LIBCOLLECTOR_NAME))
+    dbe_write (2, GTXT ("Warning: %s is already defined in one or more LD_PRELOAD environment variables\n"),
+              SP_LIBCOLLECTOR_NAME);
+  if (putenv_ld_preloads ())
+    return 1;
+  return 0;
+}
+
+int
+collect::putenv_libcollector_ld_misc ()
+{
+#if 0 // XXX 1 turns on LD_DEBUG
+  putenv (strdup ("LD_DEBUG=audit,bindings,detail"));
+#endif
+  // workaround to have the dynamic linker use absolute names
+  if (add_env (dbe_strdup ("LD_ORIGIN=yes")))
+    return 1;
+
+  // On Linux we have to provide SP_COLLECTOR_LIBRARY_PATH and LD_LIBRARY_PATH
+  // so that -agentlib:gp-collector works
+  // and so that collect -F works with 32/64-bit mix of processes
+
+  // Set GPROFNG_PRELOAD_LIBDIRS
+  char *ev = getenv (GPROFNG_PRELOAD_LIBDIRS);
+  char *libpath_list = NULL;
+  if (ev == NULL && settings->preload_libdirs == NULL)
+    {
+      settings->read_rc (false);
+      ev = settings->preload_libdirs;
+    }
+  ev = dbe_strdup (ev);
+  StringBuilder sb;
+  sb.appendf ("%s=", "SP_COLLECTOR_LIBRARY_PATH");
+  int len = sb.length ();
+  int cnt = 0;
+  for (char *s = ev; s;)
+    {
+      char *s1 = strchr (s, ':');
+      if (s1)
+       *(s1++) = 0;
+      char *fname;
+      if (*s == '/')
+       {
+         fname = dbe_sprintf ("%s/%s", s, LIBGP_COLLECTOR);
+         if (access (fname, R_OK | F_OK) == 0)
+           {
+             if (++cnt != 1)
+               sb.append (':');
+             sb.appendf ("%s", s);
+           }
+       }
+      else
+       {
+         fname = dbe_sprintf ("%s/%s/%s", run_dir, s, LIBGP_COLLECTOR);
+         if (access (fname, R_OK | F_OK) == 0)
+           {
+             if (++cnt != 1)
+               sb.append (':');
+             sb.appendf ("%s/%s", run_dir, s);
+           }
+       }
+      free (fname);
+      s = s1;
+    }
+  free (ev);
+  if (cnt == 0)
+    {
+      dbe_write (2, GTXT ("configuration error: can not find %s. run aborted\n"),
+                LIBGP_COLLECTOR);
+      return 1;
+    }
+  libpath_list = sb.toString ();
+  if (add_env (libpath_list))
+    return 1;
+  libpath_list += len;
+
+  // --- set LD_LIBRARY_PATH using libpath_list
+  char *old = getenv (LD_LIBRARY_PATH[0]);
+  if (old)
+    ev = dbe_sprintf ("%s=%s:%s", LD_LIBRARY_PATH[0], libpath_list, old);
+  else
+    ev = dbe_sprintf ("%s=%s", LD_LIBRARY_PATH[0], libpath_list);
+  if (add_env (ev))
+    return 1;
+  return 0;
+}
+
+void
+collect::add_ld_preload (const char *lib)
+{
+  for (int ii = 0; SP_PRELOAD[ii]; ii++)
+    {
+      char *old_sp = sp_preload_list[ii];
+      if (old_sp == NULL)
+       sp_preload_list[ii] = strdup (lib);
+      else
+       {
+         sp_preload_list[ii] = dbe_sprintf ("%s %s", old_sp, lib);
+         free (old_sp);
+       }
+    }
+}
+
+int
+collect::putenv_memso ()
+{
+  // Set environment variable "MEM_USE_LOG" to 1, to keep it out of stderr
+  if (add_env (dbe_strdup ("MEM_USE_LOG=1")))
+    return 1;
+  // Set environment variable "MEM_ABORT_ON_ERROR", to force a core dump
+  if (add_env (dbe_strdup ("MEM_ABORT_ON_ERROR=1")))
+    return 1;
+  add_ld_preload ("mem.so");
+  return putenv_ld_preloads ();
+}
+
+// set LD_PRELOAD and friends to prepend the given library or libraries
+
+int
+collect::putenv_ld_preloads ()
+{
+  for (int ii = 0; LD_PRELOAD[ii]; ii++)
+    {
+      char *old_val = getenv (LD_PRELOAD[ii]);
+      int sp_num = ii;
+      assert (SP_PRELOAD[sp_num]);
+      char *preload_def;
+      if (old_val)
+       preload_def = dbe_sprintf ("%s=%s %s", LD_PRELOAD[ii], sp_preload_list[sp_num], old_val);
+      else
+       preload_def = dbe_sprintf ("%s=%s", LD_PRELOAD[ii], sp_preload_list[sp_num]);
+      if (add_env (preload_def))
+       return 1;
+    }
+  return 0;
+}
+
+/* copied from linetrace.c */
+/*
+   function: env_strip()
+     Finds str in env; Removes
+     all characters from previous ':' or ' '
+     up to and including any trailing ':' or ' '.
+   params:
+     env: environment variable
+     str: substring to find
+     return: count of instances removed from env
+ */
+int
+collect::env_strip (char *env, const char *str)
+{
+  int removed = 0;
+  char *p, *q;
+  if (env == NULL || str == NULL || *str == 0)
+    return 0;
+  size_t maxlen = strlen (env);
+  size_t len = strlen (str);
+  q = env;
+  while ((p = strstr (q, str)) != NULL)
+    {
+      q = p;
+      p += len;
+      if (*p)
+       {
+         while ((*p) && (*p != ':') && (*p != ' '))
+           p++;      /* skip the rest of the name*/
+         while ((*p == ':') || (*p == ' '))
+           p++; /* strip trailing separator */
+       }
+      while (*q != ':' && *q != ' ' && *q != '=' && q != env)
+       q--; /* strip path */
+      if (*p)
+       { /* copy the rest of the string */
+         if (q != env)
+           q++; /* restore leading separator (if any) */
+         size_t n = (maxlen - (q - env));
+         strncpy (q, p, n);
+       }
+      else
+       *q = 0;
+      removed++;
+    }
+  return removed;
+}
+/*
+   function: putenv_purged_ld_preloads()
+     Remove selected preload strings from all LD_PRELOAD* env vars.
+   params:
+     var: executable name (leading characters don't have to match)
+     return: number of instances removed from all PRELOAD vars.
+ */
+int
+collect::putenv_purged_ld_preloads (const char *var)
+{
+  int total_removed = 0;
+  if (!var || *var == 0)
+    return 0;
+  for (int ii = 0; LD_PRELOAD[ii]; ii++)
+    {
+      char *ev = getenv (LD_PRELOAD[ii]);
+      int removed = 0;
+      if (!ev)
+       continue;
+      removed = env_strip (ev, var);
+      if (!removed)
+       continue;
+      if (putenv (ev) != 0)
+       dbe_write (2, GTXT ("Can't putenv of %s\n"), ev);
+      total_removed += removed;
+    }
+  return total_removed;
+}
+/*
+   function: putenv_append()
+     append string to current enviroment variable setting and then do a putenv()
+   params:
+     var: environment variable name
+     val: string to append
+ */
+int
+collect::putenv_append (const char *var, const char *val)
+{
+  char *ev;
+  if (!var || !val)
+    return 1;
+  const char *old_val = getenv (var);
+  if (old_val == NULL || *old_val == 0)
+    ev = dbe_sprintf ("%s=%s", var, val);
+  else
+    ev = dbe_sprintf ("%s=%s %s", var, old_val, val);
+
+  // now put the new variable into the environment
+  if (add_env (ev))
+    return 1;
+  return 0;
+}
+
+int
+collect::putenv_libcollector (void)
+{
+  char buf[MAXPATHLEN + 1];
+  // --- set SP_COLLECTOR_EXPNAME
+  // fetch the experiment name and CWD
+  char *exp = cc->get_experiment ();
+  char *cwd = getcwd (buf, MAXPATHLEN);
+  char *ev;
+
+  // format the environment variable for the experiment directory name
+  if (cwd != NULL && exp[0] != '/')  // experiment is a relative path
+    ev = dbe_sprintf ("%s=%s/%s", SP_COLLECTOR_EXPNAME, cwd, exp);
+  else      // getcwd failed or experiment is a fullpath
+    ev = dbe_sprintf ("%s=%s", SP_COLLECTOR_EXPNAME, exp);
+
+  // set the experiment directory name
+  if (add_env (ev))
+    return 1;
+
+  // --- set SP_COLLECTOR_PARAMS
+  // set the data descriptor
+  exp = cc->get_data_desc ();
+  if (add_env (dbe_sprintf ("%s=%s", SP_COLLECTOR_PARAMS, exp)))
+    return 1;
+
+  // --- set SP_COLLECTOR_FOLLOW_SPEC
+  const char *follow_spec = cc->get_follow_cmp_spec ();
+  if (follow_spec)
+    // selective following has been enabled
+    if (add_env (dbe_sprintf ("%s=%s", SP_COLLECTOR_FOLLOW_SPEC, follow_spec)))
+      return 1;
+
+  if (add_env (dbe_sprintf ("%s=%d", SP_COLLECTOR_FOUNDER, getpid ())))
+    return 1;
+  if (add_env (dbe_sprintf ("%s=1", SP_COLLECTOR_ORIGIN_COLLECT)))
+    return 1;
+
+  // --- set LD_*
+  if (putenv_libcollector_ld_misc ())
+    return 1;
+
+  // --- set LD_PRELOAD*
+  if (putenv_libcollector_ld_preloads () != 0)
+    return 1;
+
+  // --- set JAVA_TOOL_OPTIONS
+  if (cc->get_java_mode () == 1)
+    if (putenv_append ("JAVA_TOOL_OPTIONS", "-agentlib:gp-collector"))
+       exit (1);
+#if 0
+  // --- set LD_AUDIT*
+  if (putenv_libcollector_ld_audits () != 0)
+    return 1;
+#endif
+  return 0;
+}
diff --git a/gprofng/src/gethrtime.c b/gprofng/src/gethrtime.c
new file mode 100644 (file)
index 0000000..8ba7295
--- /dev/null
@@ -0,0 +1,166 @@
+/* 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 <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+
+#include "gp-defs.h"
+#include "gp-time.h"
+
+/* =============================================================== */
+/*
+ * Below this are the get_clock_rate() and get_ncpus() for all architectures
+ */
+
+static int clock_rate = 0;
+static int ncpus = 0;
+static char msgbuf[1024];
+
+int
+get_clock_rate (void)
+{
+  /* Linux version -- read /proc/cpuinfo
+   *   Note the parsing is different on intel-Linux and sparc-Linux
+   */
+  FILE *fp = fopen ("/proc/cpuinfo", "r");
+  if (fp != NULL)
+    {
+
+      char temp[1024];
+      while (fgets (temp, sizeof (temp), fp) != NULL)
+       {
+#if ARCH(SPARC)
+         /* cpu count for SPARC linux -- read from /proc/cpuinfo */
+         if (strncmp (temp, "ncpus active", 12) == 0)
+           {
+             char *val = strchr (temp, ':');
+             ncpus = val ? atol (val + 1) : 0;
+           }
+#endif /* ARCH(SPARC) */
+
+         if (clock_rate == 0)
+           {
+             /* pick the first line that gives a CPU clock rate */
+#if ARCH(SPARC)
+             long long clk;
+             if (strncmp (temp, "Cpu0ClkTck", 10) == 0)
+               {
+                 char *val = strchr (temp, ':');
+                 clk = val ? strtoll (val + 1, NULL, 16) : 0;
+                 clock_rate = (int) (clk / 1000000);
+               }
+#else
+             if (strncmp (temp, "cpu MHz", 7) == 0)
+               {
+                 char *val = strchr (temp, ':');
+                 clock_rate = val ? atoi (val + 1) : 0;
+               }
+#endif /* ARCH() */
+           }
+
+         /* did we get a clock rate? */
+         if (clock_rate != 0)
+           {
+#if ARCH(SPARC)
+             /* since we got a cpu count, we can break from the look */
+             break;
+#endif /* ARCH(SPARC) */
+           }
+#if ARCH(Intel)
+         /* On intel-Linux, count cpus based on "cpu MHz" lines */
+         if (strncmp (temp, "cpu MHz", 7) == 0)
+           ncpus++;
+#endif /* ARCH(Intel) */
+       }
+      fclose (fp);
+    }
+
+  if (clock_rate != 0)
+    sprintf (msgbuf,
+            "Clock rate = %d MHz (from reading /proc/cpuinfo) %d CPUs\n",
+            clock_rate, ncpus);
+
+  /* did we get a clock rate? */
+  if (clock_rate == 0)
+    {
+      clock_rate = 1000;
+      sprintf (msgbuf, "Clock rate = %d MHz (set by default) %d CPUs\n",
+              clock_rate, ncpus);
+    }
+  return clock_rate;
+}
+
+int
+get_ncpus (void)
+{
+  if (clock_rate == 0)
+    get_clock_rate ();
+  return ncpus;
+}
+
+/* gethrvtime -- generic solution, getting user time from
+ * clock_gettime(CLOCK_THREAD_CPUTIME_ID,..), and reformatting.
+ * need -lrt to compile.*/
+hrtime_t
+gethrvtime ()
+{
+  struct timespec tp;
+  hrtime_t rc = 0;
+  int r = clock_gettime (CLOCK_THREAD_CPUTIME_ID, &tp);
+  if (r == 0)
+    rc = ((hrtime_t) tp.tv_sec) * 1000000000 + (hrtime_t) tp.tv_nsec;
+  return rc;
+}
+
+/*
+ *  CLOCK_MONOTONIC
+ *  Clock that cannot be set and represents monotonic time since some
+ *           unspecified starting point.
+ */
+hrtime_t
+gethrtime (void)
+{
+  struct timespec tp;
+  hrtime_t rc = 0;
+
+  /*
+   * For er_kernel on Linux, we want to match how DTrace gets its timestamps.
+   * This is CLOCK_MONOTONIC_RAW.  It might be changing to CLOCK_MONOTONIC.
+   * For now, we change to "RAW" and can change back if DTrace changes.
+   *
+   * The two can be different.  Check the clock_gettime() man page.
+   * CLOCK_MONOTONIC_RAW is Linux-specific and introduced in 2.6.28.
+   * It is impervious to NTP or adjtime adjustments.
+   *
+   * We must match the timer used in perfan/libcollector/src/gethrtime.c.
+   *
+   * There is no issue on Solaris, where gethrtime() is provided by the kernel
+   * and used by DTrace.
+   */
+  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;
+}
diff --git a/gprofng/src/gp-archive.cc b/gprofng/src/gp-archive.cc
new file mode 100644 (file)
index 0000000..8d3fc23
--- /dev/null
@@ -0,0 +1,700 @@
+/* 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 <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <getopt.h>
+
+#include "util.h"
+#include "StringMap.h"
+#include "LoadObject.h"
+#include "DbeSession.h"
+#include "DbeFile.h"
+#include "SourceFile.h"
+#include "Elf.h"
+#include "gp-archive.h"
+#include "ArchiveExp.h"
+#include "Print.h"
+#include "Module.h"
+
+er_archive::er_archive (int argc, char *argv[]) : DbeApplication (argc, argv)
+{
+  force = 0;
+  common_archive_dir = NULL;
+  quiet = 0;
+  descendant = 1;
+  use_relative_path = 0;
+  s_option = ARCH_EXE_ONLY;
+  mask = NULL;
+}
+
+er_archive::~er_archive ()
+{
+  if (mask)
+    {
+      for (long i = 0, sz = mask->size (); i < sz; i++)
+       {
+         regex_t *regex_desc = mask->get (i);
+         regfree (regex_desc);
+         delete regex_desc;
+       }
+      delete mask;
+    }
+  delete common_archive_dir;
+}
+
+int
+er_archive::mask_is_on (const char *str)
+{
+  if (mask == NULL)
+    return 1;
+  for (long i = 0, sz = mask->size (); i < sz; i++)
+    {
+      regex_t *regex_desc = mask->get (i);
+      if (regexec (regex_desc, str, 0, NULL, 0) == 0)
+       return 1;
+    }
+  return 0;
+}
+
+void
+er_archive::usage ()
+{
+/*
+  fprintf (stderr, GTXT ("Usage: %s [-nqFV] [-a on|ldobjects|src|usedldobjects|usedsrc|off] [-m regexp] experiment\n"), whoami);
+*/
+
+/*
+  Ruud - Isolate this line because it has an argument.  Otherwise it would be at the
+  end of this long list.
+*/
+  printf ( GTXT (
+    "Usage: gprofng archive [OPTION(S)] EXPERIMENT\n"));
+
+  printf ( GTXT (
+    "\n"
+    "Archive the associated application binaries and source files in a gprofng\n"
+    "experiment to make it self contained and portable.\n"
+    "\n"
+    "Options:\n"
+    "\n"
+    " --version           print the version number and exit.\n"
+    " --help              print usage information and exit.\n"
+    " --verbose {on|off}  enable (on) or disable (off) verbose mode; the default is \"off\".\n"
+    "\n"
+    " -a {off|on|ldobjects|src|usedldobjects|usedsrc}  specify archiving of binaries and other files;\n"
+    "                    in addition to disable this feature (off), or enable archiving off all\n"
+    "                    loadobjects and sources (on), the other options support a more\n"
+    "                    refined selection. All of these options enable archiving, but the\n"
+    "                    keyword controls what exactly is selected: all load objects (ldobjects),\n"
+    "                    all source files (src), the loadobjects asscoiated with a program counter\n"
+    "                    (usedldobjects), or the source files associated with a program counter\n"
+    "                    (usedsrc); the default is \"-a ldobjects\".\n"
+    "\n"
+    " -n                 archive the named experiment only, not any of its descendants.\n"
+    "\n"
+    " -q                 do not write any warnings to stderr; messages are archived and\n"
+    "                    can be retrieved later.\n"
+    "\n"
+    " -F                 force writing or rewriting of the archive; ignored with the -n\n"
+    "                    or -m options, or if this is a subexperiment.\n"
+    "\n"
+    " -d <path>          specifies the location of a common archive; this is a directory that\n"
+    "                    contains archived files.\n"
+    "\n"
+    " -m <regex>         archive only those source, object, and debug info files whose full\n"
+    "                    path name matches the given POSIX compliant regular expression.\n"
+    "\n"
+    "Limitations:\n"
+    "\n"
+    "Default archiving does not occur in case the application profiled terminates prematurely,\n"
+    "or if archiving is disabled when collecting the performance data. In such cases, this\n"
+    "tool can be used to afterwards archive the information, but it has to run on the same \n"
+    "system where the profiling data was recorded.\n"
+    "\n"
+    "Documentation:\n"
+    "\n"
+    "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
+    "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
+    "should give you access to this document.\n"
+    "\n"
+    "See also:\n"
+    "\n"
+    "gprofng(1), gp-collect-app(1), gp-display-html(1), gp-display-src(1), gp-display-text(1)\n"));
+// Ruud
+/*
+  fprintf (stderr, GTXT ("GNU %s version %s\n"), get_basename (prog_name), VERSION);
+*/
+  exit (1);
+}
+
+Vector <LoadObject*> *
+er_archive::get_loadObjs ()
+{
+  Vector <LoadObject*> *objs = new Vector<LoadObject*>();
+  Vector <LoadObject*> *loadObjs = dbeSession->get_text_segments ();
+  if (s_option != ARCH_NOTHING)
+    {
+      for (long i = 0, sz = VecSize(loadObjs); i < sz; i++)
+       {
+         LoadObject *lo = loadObjs->get (i);
+         if ((lo->flags & SEG_FLAG_DYNAMIC) != 0)
+           continue;
+         DbeFile *df = lo->dbeFile;
+         if (df && ((df->filetype & DbeFile::F_FICTION) != 0))
+           continue;
+         if (!lo->isUsed && ((s_option & (ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY)) != 0))
+           continue;
+         objs->append (lo);
+       }
+    }
+  if (DEBUG_ARCHIVE)
+    {
+      Dprintf (DEBUG_ARCHIVE, NTXT ("get_text_segments(): %d\n"),
+              (int) (loadObjs ? loadObjs->size () : -1));
+      for (long i = 0, sz = loadObjs ? loadObjs->size () : 0; i < sz; i++)
+       {
+         LoadObject *lo = loadObjs->get (i);
+         Dprintf (DEBUG_ARCHIVE, NTXT ("%s:%d  [%2ld] %s\n"),
+                  get_basename (__FILE__), (int) __LINE__, i, STR (lo->dump ()));
+       }
+      Dprintf (DEBUG_ARCHIVE, NTXT ("\nget_loadObjs(): %d\n"),
+              (int) (objs ? objs->size () : -1));
+      for (long i = 0, sz = VecSize(objs); i < sz; i++)
+       {
+         LoadObject *lo = objs->get (i);
+         Dprintf (DEBUG_ARCHIVE, NTXT ("%s:%d  [%2ld] %s\n"),
+                  get_basename (__FILE__), (int) __LINE__, i, STR (lo->dump ()));
+       }
+    }
+  delete loadObjs;
+  return objs;
+}
+
+/**
+ * Clean old archive
+ * Except the following cases:
+ * 1. Founder experiment is an MPI experiment
+ * 2. "-n" option is passed (do not archive descendants)
+ * 3. "-m" option is passed (partial archiving)
+ * 4. Experiment name is not the founder experiment (it is a sub-experiment)
+ * @param expname
+ * @param founder_exp
+ * @return 0 - success
+ */
+int
+er_archive::clean_old_archive (char *expname, ArchiveExp *founder_exp)
+{
+  if (0 == descendant)
+    { // do not archive descendants
+      fprintf (stderr, GTXT ("Warning: Option -F is ignored because -n option is specified (do not archive descendants)\n"));
+      return 1;
+    }
+  if (NULL != mask)
+    { // partial archiving
+      fprintf (stderr, GTXT ("Warning: Option -F is ignored because -m option is specified\n"));
+      return 1;
+    }
+  // Check if the experiment is the founder
+  char *s1 = dbe_strdup (expname);
+  char *s2 = dbe_strdup (founder_exp->get_expt_name ());
+  if (!s1 || !s2)
+    {
+      fprintf (stderr, GTXT ("Cannot allocate memory\n"));
+      exit (1);
+    }
+  // remove trailing slashes
+  for (int n = strlen (s1); n > 0; n--)
+    {
+      if ('/' != s1[n - 1])
+       break;
+      s1[n - 1] = 0;
+    }
+  for (int n = strlen (s2); n > 0; n--)
+    {
+      if ('/' != s2[n - 1])
+       break;
+      s2[n - 1] = 0;
+    }
+  if (strcmp (s1, s2) != 0)
+    { // not founder
+      fprintf (stderr, GTXT ("Warning: Option -F is ignored because specified experiment name %s does not match founder experiment name %s\n"), s1, s2);
+      free (s1);
+      free (s2);
+      return 1;
+    }
+  // Remove old "archives"
+  char *arch = founder_exp->get_arch_name ();
+  fprintf (stderr, GTXT ("INFO: removing existing archive: %s\n"), arch);
+  if (dbe_stat (arch, NULL) == 0)
+    {
+      char *cmd = dbe_sprintf ("/bin/rm -rf %s", arch);
+      system (cmd);
+      free (cmd);
+      if (dbe_stat (arch, NULL) != 0)
+       { // create "archives"
+         if (!founder_exp->create_dir (founder_exp->get_arch_name ()))
+           {
+             fprintf (stderr, GTXT ("Unable to create directory `%s'\n"), founder_exp->get_arch_name ());
+             exit (1);
+           }
+       }
+    }
+  free (s1);
+  free (s2);
+  return 0;
+} // clean_old_archive_if_necessary
+
+void
+er_archive::start (int argc, char *argv[])
+{
+  int last = argc - 1;
+  if (check_args (argc, argv) != last)
+    usage ();
+  check_env_var ();
+  if (s_option == ARCH_NOTHING)
+    return;
+
+  ArchiveExp *founder_exp = new ArchiveExp (argv[last]);
+  if (founder_exp->get_status () == Experiment::FAILURE)
+    {
+      if (!quiet)
+       fprintf (stderr, GTXT ("er_archive: %s: %s\n"), argv[last],
+                pr_mesgs (founder_exp->fetch_errors (), NTXT (""), NTXT ("")));
+      exit (1);
+    }
+  if (!founder_exp->create_dir (founder_exp->get_arch_name ()))
+    {
+      fprintf (stderr, GTXT ("Unable to create directory `%s'\n"), founder_exp->get_arch_name ());
+      exit (1);
+    }
+  if (!common_archive_dir)
+    common_archive_dir = dbe_strdup (getenv ("GPROFNG_ARCHIVE_COMMON_DIR"));
+  if (common_archive_dir)
+    {
+      if (!founder_exp->create_dir (common_archive_dir))
+       if (dbe_stat (common_archive_dir, NULL) != 0)
+         {
+           fprintf (stderr, GTXT ("Unable to create directory for common archive `%s'\n"), common_archive_dir);
+           exit (1);
+         }
+    }
+  // Clean old archives if necessary
+  if (force)
+    clean_old_archive (argv[last], founder_exp);
+  Vector<ArchiveExp*> *exps = new Vector<ArchiveExp*>();
+  exps->append (founder_exp);
+  if (descendant)
+    {
+      Vector<char*> *exp_names = founder_exp->get_descendants_names ();
+      if (exp_names)
+       {
+         for (long i = 0, sz = exp_names->size (); i < sz; i++)
+           {
+             char *exp_path = exp_names->get (i);
+             ArchiveExp *exp = new ArchiveExp (exp_path);
+             if (exp->get_status () == Experiment::FAILURE)
+               {
+                 if (!quiet)
+                   fprintf (stderr, GTXT ("er_archive: %s: %s\n"), exp_path,
+                            pr_mesgs (exp->fetch_errors (), NTXT (""), NTXT ("")));
+                 delete exp;
+                 continue;
+               }
+             exps->append (exp);
+           }
+         exp_names->destroy ();
+         delete exp_names;
+       }
+    }
+  for (long i = 0, sz = exps->size (); i < sz; i++)
+    {
+      ArchiveExp *exp = exps->get (i);
+      exp->read_data (s_option);
+    }
+
+  Vector <DbeFile*> *copy_files = new Vector<DbeFile*>();
+  Vector <LoadObject*> *loadObjs = get_loadObjs ();
+  for (long i = 0, sz = VecSize(loadObjs); i < sz; i++)
+    {
+      LoadObject *lo = loadObjs->get (i);
+      if (strcmp (lo->get_pathname (), "LinuxKernel") == 0)
+       continue;
+      DbeFile *df = lo->dbeFile;
+      if ((df->filetype & DbeFile::F_FICTION) != 0)
+       continue;
+      if (df->get_location () == NULL)
+       {
+         copy_files->append (df);
+         continue;
+       }
+      if ((df->filetype & DbeFile::F_JAVACLASS) != 0)
+       {
+         if (df->container)
+           { // Found in .jar file
+             copy_files->append (df->container);
+           }
+         copy_files->append (df);
+         if ((s_option & ARCH_EXE_ONLY) != 0)
+           continue;
+       }
+      lo->sync_read_stabs ();
+      Elf *elf = lo->get_elf ();
+      if (elf && (lo->checksum != 0) && (lo->checksum != elf->elf_checksum ()))
+       {
+         if (!quiet)
+           fprintf (stderr, GTXT ("er_archive: '%s' has an unexpected checksum value; perhaps it was rebuilt. File ignored\n"),
+                      df->get_location ());
+         continue;
+       }
+      copy_files->append (df);
+      if (elf)
+       {
+         Elf *f = elf->find_ancillary_files (lo->get_pathname ());
+         if (f)
+           copy_files->append (f->dbeFile);
+         for (long i1 = 0, sz1 = VecSize(elf->ancillary_files); i1 < sz1; i1++)
+           {
+             Elf *ancElf = elf->ancillary_files->get (i1);
+             copy_files->append (ancElf->dbeFile);
+           }
+       }
+      Vector<Module*> *modules = lo->seg_modules;
+      for (long i1 = 0, sz1 = VecSize(modules); i1 < sz1; i1++)
+       {
+         Module *mod = modules->get (i1);
+         if ((mod->flags & MOD_FLAG_UNKNOWN) != 0)
+           continue;
+         else if ((s_option & (ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY)) != 0 &&
+                  !mod->isUsed)
+           continue;
+         if ((s_option & ARCH_ALL) != 0)
+           mod->read_stabs (false); // Find all Sources
+         if (mod->dot_o_file && mod->dot_o_file->dbeFile)
+           copy_files->append (mod->dot_o_file->dbeFile);
+       }
+    }
+  delete loadObjs;
+
+  int bmask = DbeFile::F_LOADOBJ | DbeFile::F_JAVACLASS | DbeFile::F_JAR_FILE |
+         DbeFile::F_DOT_O | DbeFile::F_DEBUG_FILE;
+  if ((s_option & (ARCH_USED_SRC_ONLY | ARCH_ALL)) != 0)
+    {
+      bmask |= DbeFile::F_JAVA_SOURCE | DbeFile::F_SOURCE;
+      Vector<SourceFile*> *sources = dbeSession->get_sources ();
+      for (long i = 0, sz = VecSize(sources); i < sz; i++)
+       {
+         SourceFile *src = sources->get (i);
+         if ((src->flags & SOURCE_FLAG_UNKNOWN) != 0)
+           continue;
+         else if ((s_option & ARCH_USED_SRC_ONLY) != 0)
+           {
+             if ((src->dbeFile->filetype & DbeFile::F_JAVA_SOURCE) != 0 &&
+                 !src->isUsed)
+               continue;
+           }
+         if (src->dbeFile)
+           copy_files->append (src->dbeFile);
+       }
+    }
+
+  Vector <DbeFile*> *notfound_files = new Vector<DbeFile*>();
+  for (long i = 0, sz = VecSize(copy_files); i < sz; i++)
+    {
+      DbeFile *df = copy_files->get (i);
+      char *fnm = df->get_location ();
+      char *nm = df->get_name ();
+      Dprintf (DEBUG_ARCHIVE,
+              "%s::%d copy_files[%ld] filetype=%4d inArchive=%d '%s' --> '%s'\n",
+              get_basename (__FILE__), (int) __LINE__, i,
+              df->filetype, df->inArchive ? 1 : 0, STR (nm), STR (fnm));
+      Dprintf (DEBUG_ARCHIVE && df->container,
+              "    copy_files[%ld]: Found '%s' in '%s'\n",
+              i, STR (nm), STR (df->container->get_name ()));
+      if (fnm == NULL)
+       {
+         if (!quiet)
+           notfound_files->append (df);
+         continue;
+       }
+      else if (df->inArchive)
+       {
+         Dprintf (DEBUG_ARCHIVE,
+                  "  NOT COPIED: copy_files[%ld]: inArchive=1 '%s'\n",
+                  i, STR (nm));
+         continue;
+       }
+      else if ((df->filetype & bmask) == 0)
+       {
+         Dprintf (DEBUG_ARCHIVE,
+                  "  NOT COPIED: copy_files[%ld]: container=%p filetype=%d bmask=%d '%s'\n",
+                  i, df->container, df->filetype, bmask, STR (nm));
+         continue;
+       }
+      else if (df->container &&
+              (df->filetype & (DbeFile::F_JAVA_SOURCE | DbeFile::F_SOURCE)) == 0)
+       {
+         Dprintf (DEBUG_ARCHIVE,
+                  "  NOT COPIED: copy_files[%ld]: container=%p filetype=%d bmask=%d '%s'\n",
+                  i, df->container, df->filetype, bmask, STR (nm));
+         continue;
+       }
+      else if (!mask_is_on (df->get_name ()))
+       {
+         Dprintf (DEBUG_ARCHIVE,
+                  "  NOT COPIED: copy_files[%ld]: mask is off for '%s'\n",
+                  i, STR (nm));
+         continue;
+       }
+      char *anm = founder_exp->getNameInArchive (nm, false);
+      if (force)
+       unlink (anm);
+      int res = founder_exp->copy_file (fnm, anm, quiet, common_archive_dir, use_relative_path);
+      if (0 == res)  // file successfully archived
+       df->inArchive = 1;
+      delete anm;
+    }
+  delete copy_files;
+
+  if (notfound_files->size () > 0)
+    {
+      for (long i = 0, sz = notfound_files->size (); i < sz; i++)
+       {
+         DbeFile *df = notfound_files->get (i);
+         fprintf (stderr, GTXT ("er_archive: Cannot find file: `%s'\n"), df->get_name ());
+       }
+      fprintf (stderr, GTXT ("\n If you know the correct location of the missing file(s)"
+                            " you can help %s to find them by manually editing the .gprofng.rc file."
+                            " See %s man pages for more details.\n"),
+              whoami, whoami);
+    }
+  delete notfound_files;
+}
+
+int
+er_archive::check_args (int argc, char *argv[])
+{
+  int opt;
+  int rseen = 0;
+  int dseen = 0;
+  // Parsing the command line
+  opterr = 0;
+  optind = 1;
+  static struct option long_options[] = {
+    {"help",    no_argument,        0, 'h'},
+    {"version", no_argument,        0, 'V'},
+    {"whoami",  required_argument,  0, 'w'},
+    {"outfile", required_argument,  0, 'O'},
+    {NULL, 0, 0, 0}
+  };
+  while (1)
+    {
+      int option_index = 0;
+      opt = getopt_long (argc, argv, NTXT (":VFa:d:qnr:m:"),
+                        long_options, &option_index);
+      if (opt == EOF)
+       break;
+      switch (opt)
+       {
+       case 'F':
+         force = 1;
+         break;
+       case 'd': // Common archive directory (absolute path)
+         if (rseen)
+           {
+             fprintf (stderr, GTXT ("Error: invalid combination of options: -r and -d are in conflict.\n"));
+             return -1;
+           }
+         if (dseen)
+           fprintf (stderr, GTXT ("Warning: option -d was specified several times. Last value is used.\n"));
+         free (common_archive_dir);
+         common_archive_dir = strdup (optarg);
+         dseen = 1;
+         break;
+       case 'q':
+         quiet = 1;
+         break;
+       case 'n':
+         descendant = 0;
+         break;
+       case 'r': // Common archive directory (relative path)
+         if (dseen)
+           {
+             fprintf (stderr, GTXT ("Error: invalid combination of options: -d and -r are in conflict.\n"));
+             return -1;
+           }
+         if (rseen)
+           fprintf (stderr, GTXT ("Warning: option -r was specified several times. Last value is used.\n"));
+         free (common_archive_dir);
+         common_archive_dir = strdup (optarg);
+         use_relative_path = 1;
+         rseen = 1;
+         break;
+       case 'a':
+         if (strcmp (optarg, "off") == 0)
+           s_option = ARCH_NOTHING;
+         else if (strcmp (optarg, "on") == 0 ||
+                  strcmp (optarg, "ldobjects") == 0)
+           s_option = ARCH_EXE_ONLY;
+         else if (strcmp (optarg, "usedldobjects") == 0)
+           s_option = ARCH_USED_EXE_ONLY;
+         else if (strcmp (optarg, "usedsrc") == 0)
+           s_option = ARCH_USED_EXE_ONLY | ARCH_USED_SRC_ONLY;
+         else if (strcmp (optarg, "all") == 0 || strcmp (optarg, "src") == 0)
+           s_option = ARCH_ALL;
+         else
+           {
+             fprintf (stderr, GTXT ("Error: invalid option: `-%c %s'\n"),
+                      optopt, optarg);
+             return -1;
+           }
+         break;
+       case 'm':
+         {
+           regex_t *regex_desc = new regex_t ();
+           if (regcomp (regex_desc, optarg, REG_EXTENDED | REG_NOSUB | REG_NEWLINE))
+             {
+               delete regex_desc;
+               fprintf (stderr, GTXT ("Error: invalid option: `-%c %s'\n"),
+                        optopt, optarg);
+               return -1;
+             }
+           if (mask == NULL)
+             mask = new Vector<regex_t *>();
+           mask->append (regex_desc);
+           break;
+         }
+       case 'O':
+         {
+           int fd = open (optarg, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+           if (fd == -1)
+             {
+               fprintf (stderr, GTXT ("er_archive: Can't open %s: %s\n"),
+                        optarg, strerror (errno));
+               break;
+             }
+           if (dup2 (fd, 2) == -1)
+             {
+               close (fd);
+               fprintf (stderr, GTXT ("er_archive: Can't divert stderr: %s\n"),
+                        strerror (errno));
+               break;
+             }
+           if (dup2 (fd, 1) == -1)
+             {
+               close (fd);
+               fprintf (stderr, GTXT ("er_archive: Can't divert stdout: %s\n"),
+                        strerror (errno));
+               break;
+             }
+           close (fd);
+           struct timeval tp;
+           gettimeofday (&tp, NULL);
+           fprintf (stderr, "### Start %s#", ctime (&tp.tv_sec));
+           for (int i = 0; i < argc; i++)
+             fprintf (stderr, " %s", argv[i]);
+           fprintf (stderr, "\n");
+           break;
+         }
+       case 'V':
+// Ruud
+         Application::print_version_info ();
+/*
+         printf (GTXT ("GNU %s version %s\n"), get_basename (prog_name), VERSION);
+*/
+         exit (0);
+       case 'w':
+         whoami = optarg;
+         break;
+       case 'h':
+         usage ();
+         exit (0);
+       case ':': // -s -m without operand
+         fprintf (stderr, GTXT ("Option -%c requires an operand\n"), optopt);
+         return -1;
+       case '?':
+       default:
+         fprintf (stderr, GTXT ("Unrecognized option: -%c\n"), optopt);
+         return -1;
+       }
+    }
+  return optind;
+}
+
+void
+er_archive::check_env_var ()
+{
+  char *ename = NTXT ("GPROFNG_ARCHIVE");
+  char *var = getenv (ename);
+  if (var == NULL)
+    return;
+  var = dbe_strdup (var);
+  Vector<char*> *opts = new Vector<char*>();
+  opts->append (ename);
+  for (char *s = var;;)
+    {
+      while (*s && isblank (*s))
+       s++;
+      if (*s == 0)
+       break;
+      opts->append (s);
+      while (*s && !isblank (*s))
+       s++;
+      if (*s == 0)
+       break;
+      *s = 0;
+      s++;
+    }
+  if (opts->size () > 0)
+    {
+      char **arr = (char **) malloc (sizeof (char *) *opts->size ());
+      for (long i = 0; i < opts->size (); i++)
+       arr[i] = opts->get (i);
+      if (-1 == check_args (opts->size (), arr))
+       fprintf (stderr, GTXT ("Error: Wrong SP_ER_ARCHIVE: '%s'\n"), var);
+      free (arr);
+    }
+  delete opts;
+  free (var);
+}
+
+static int
+real_main (int argc, char *argv[])
+{
+  er_archive *archive = new er_archive (argc, argv);
+  dbeSession->archive_mode = 1;
+  archive->start (argc, argv);
+  dbeSession->unlink_tmp_files ();
+  return 0;
+}
+
+/**
+ * Call catch_out_of_memory(int (*real_main)(int, char*[]), int argc, char *argv[]) which will call real_main()
+ * @param argc
+ * @param argv
+ * @return
+ */
+int
+main (int argc, char *argv[])
+{
+  return catch_out_of_memory (real_main, argc, argv);
+}
diff --git a/gprofng/src/gp-archive.h b/gprofng/src/gp-archive.h
new file mode 100644 (file)
index 0000000..1d937e0
--- /dev/null
@@ -0,0 +1,64 @@
+/* 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 _GP_ARCHIVE_H_
+#define _GP_ARCHIVE_H_
+
+#include <regex.h>
+#include "DbeApplication.h"
+
+class ArchiveExp;
+class LoadObject;
+template <class ITEM> class Vector;
+
+enum
+{
+  ARCH_NOTHING       = 0,
+  ARCH_EXE_ONLY      = 1,
+  ARCH_USED_EXE_ONLY = 2,
+  ARCH_USED_SRC_ONLY = 4,
+  ARCH_ALL           = 8
+};
+
+class er_archive : public DbeApplication
+{
+public:
+  er_archive (int argc, char *argv[]);
+  ~er_archive ();
+  void start (int argc, char *argv[]);
+
+private:
+  void usage ();
+  int check_args (int argc, char *argv[]);
+  int clean_old_archive (char *expname, ArchiveExp *founder_exp);
+  int mask_is_on (const char *str);
+  void check_env_var ();
+  Vector <LoadObject*> *get_loadObjs ();
+
+  Vector<regex_t *> *mask;  // -m <regexp>
+  int s_option;             // -s NO|ALL|USED
+  char *common_archive_dir; // -d // absolute path to common archive
+  int force;                // -F
+  int quiet;                // -q
+  int descendant;           // -n
+  int use_relative_path;    // -r
+};
+
+#endif
\ No newline at end of file
diff --git a/gprofng/src/gp-collect-app.cc b/gprofng/src/gp-collect-app.cc
new file mode 100644 (file)
index 0000000..afaae70
--- /dev/null
@@ -0,0 +1,1598 @@
+/* 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 <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/ptrace.h>
+
+#include "gp-defs.h"
+#include "cpu_frequency.h"
+#include "util.h"
+#include "collctrl.h"
+#include "hwcdrv.h"
+#include "gp-experiment.h"
+#include "collect.h"
+#include "StringBuilder.h"
+
+#define SP_COLLECTOR_FOUNDER "SP_COLLECTOR_FOUNDER"
+
+extern char **environ;
+
+static volatile int interrupt = 0;
+static int saved_stdout = -1;
+static int  saved_stderr = -1;
+static int no_short_usage = 0;
+static int usage_fd = 2;
+static collect *collect_obj = NULL;
+extern "C" void sigint_handler (int sig, siginfo_t *info, void *context);
+static char *outredirect = NULL;
+static int precheck;
+static int nprocesses;
+static Process **processes;
+
+int
+main (int argc, char *argv[])
+{
+  // disable any alarm that might be pending
+  int r = alarm (0);
+  if (r != 0)
+    dbe_write (2, GTXT ("collect has alarm(%d) pending\n"), r);
+  collect_obj = new collect (argc, argv, environ);
+  collect_obj->start (argc, argv);
+  delete collect_obj;
+  return 0;
+}
+
+extern "C" void
+sigint_handler (int, siginfo_t *, void *)
+{
+  interrupt = 1;
+  if (collect_obj->cc != NULL)
+    collect_obj->cc->interrupt ();
+  return;
+}
+
+extern "C" void
+sigalrm_handler (int, siginfo_t *, void *)
+{
+  dbe_write (2, GTXT ("collect: unexpected alarm clock signal received\n"));
+  return;
+}
+
+extern "C" void
+sigterm_handler (int, siginfo_t *, void *)
+{
+  for (int i = 0; i < nprocesses; i++)
+    {
+      Process *proc = processes[i];
+      if (proc != NULL)
+       kill (proc->pid, SIGTERM);
+    }
+}
+
+collect::collect (int argc, char *argv[], char **envp)
+: Application (argc, argv)
+{
+  verbose = 0;
+  disabled = 0;
+  cc = NULL;
+  collect_warnings = NULL;
+  collect_warnings_idx = 0;
+  int ii;
+  for (ii = 0; ii < MAX_LD_PRELOAD_TYPES; ii++)
+    sp_preload_list[ii] = NULL;
+  for (ii = 0; ii < MAX_LD_PRELOAD_TYPES; ii++)
+    sp_libpath_list[ii] = NULL;
+  java_path = NULL;
+  java_how = NULL;
+  jseen_global = 0;
+  nlabels = 0;
+  origargc = argc;
+  origargv = argv;
+  origenvp = envp;
+  mem_so_me = false;
+}
+
+collect::~collect ()
+{
+  delete cc;
+}
+
+struct sigaction old_sigint_handler;
+struct sigaction old_sigalrm_handler;
+
+void
+collect::start (int argc, char *argv[])
+{
+  char *ccret;
+  char *extype;
+  /* create a collector control structure, disabling aggressive warning */
+  cc = new Coll_Ctrl (0, false, false);
+  if (prog_name)
+    {
+      char *s = strrchr (prog_name, '/');
+      if (s && (s - prog_name) > 5) // Remove /bin/
+       {
+         s = dbe_sprintf (NTXT ("%.*s"), (int) (s - prog_name - 4), prog_name);
+         cc->set_project_home (s);
+         free (s);
+       }
+    }
+  char * errenable = cc->enable_expt ();
+  if (errenable)
+    {
+      writeStr (2, errenable);
+      free (errenable);
+    }
+
+  /* install a handler for SIGALRM */
+  struct sigaction act;
+  memset (&act, 0, sizeof (struct sigaction));
+  sigemptyset (&act.sa_mask);
+  act.sa_handler = (SignalHandler) sigalrm_handler;
+  act.sa_flags = SA_RESTART | SA_SIGINFO;
+  if (sigaction (SIGALRM, &act, &old_sigalrm_handler) == -1)
+    {
+      writeStr (2, GTXT ("Unable to install SIGALRM handler\n"));
+      exit (-1);
+    }
+
+  /* install a handler for SIGINT */
+  sigemptyset (&act.sa_mask);
+  act.sa_handler = (SignalHandler) sigint_handler;
+  act.sa_flags = SA_RESTART | SA_SIGINFO;
+  if (sigaction (SIGINT, &act, &old_sigint_handler) == -1)
+    {
+      writeStr (2, GTXT ("Unable to install SIGINT handler\n"));
+      exit (-1);
+    }
+
+  /* install a handler for SIGTERM */
+  sigemptyset (&act.sa_mask);
+  act.sa_sigaction = sigterm_handler;
+  act.sa_flags = SA_RESTART | SA_SIGINFO;
+  if (sigaction (SIGTERM, &act, NULL) == -1)
+    {
+      writeStr (2, GTXT ("Unable to install SIGTERM handler\n"));
+      exit (-1);
+    }
+  if (argc > 1 && strncmp (argv[1], NTXT ("--whoami="), 9) == 0)
+    {
+      whoami = argv[1] + 9;
+      argc--;
+      argv++;
+    }
+
+  /* check for no arguments -- usage message */
+  if (argc == 1)
+    {
+      verbose = 1;
+      usage_fd = 1;
+      validate_config (0);
+      usage ();
+      exit (0);
+    }
+  else if (argc == 2 && strcmp (argv[1], NTXT ("-h")) == 0)
+    {
+      /* only one argument, -h */
+      verbose = 1;
+      validate_config (0);
+      /* now print the HWC usage message */
+      show_hwc_usage ();
+      exit (0);
+    }
+  else if (argc == 2 && (strcmp (argv[1], NTXT ("-help")) == 0 ||
+                        strcmp (argv[1], NTXT ("--help")) == 0))
+    {
+      /* only one argument, -help or --help */
+      verbose = 1;
+      usage_fd = 1;
+      validate_config (0);
+      usage ();
+      exit (0);
+    }
+// Ruud
+  else if ((argc == 2) &&
+          (strcmp (argv[1], NTXT ("--version")) == 0))
+    {
+      /* only one argument, --version */
+
+      /* print the version info */
+      Application::print_version_info ();
+      exit (0);
+    }
+
+  /* precheck the arguments -- scan for -O, -M flagS */
+  precheck = 1;
+  targ_index = check_args (argc, argv);
+  if (targ_index < 0)
+    {
+      /* message has already been written */
+      usage_fd = 2;
+      short_usage ();
+      exit (1);
+    }
+  /* crack the arguments */
+  precheck = 0;
+  targ_index = check_args (argc, argv);
+  if (targ_index <= 0)
+    {
+      /* message has already been written */
+      usage_fd = 2;
+      short_usage ();
+      exit (1);
+    }
+  if (targ_index != 0)
+    check_target (argc, argv);
+  if (disabled != 0 && cc->get_count () == 0)
+    {
+      // show collection parameters; count data
+      ccret = cc->show (0);
+      writeStr (1, ccret);
+    }
+
+  // see if Java version should be checked
+  if (cc->get_java_default () == 0 && java_path != NULL)
+    validate_java (java_path, java_how, verbose);
+
+  /* if count data is requested, exec bit to do the real work */
+  /* even for a dryrun */
+  if (cc->get_count () != 0)
+    get_count_data ();
+
+  /* if a dry run, just exit */
+  if (disabled != 0)
+    {
+      writeStr (1, cc->show_expt ());
+      StringBuilder sb;
+      sb.append (GTXT ("Exec argv[] = "));
+      for (int i = 0; i < nargs; i++)
+       sb.appendf (NTXT ("%s "), arglist[i]);
+      sb.append (NTXT ("\n"));
+      char *s = sb.toString ();
+      writeStr (1, s);
+      free (s);
+      exit (0);
+    }
+
+  // If the mem_so_me flag is set, preload mem.so
+  //   and launch the process
+  if (mem_so_me)
+    {
+      /* set env vars for mem.so */
+      if (putenv_memso () != 0)
+       exit (1); /* message has already been written */
+      /* ensure original outputs restored for target */
+      reset_output ();
+
+      /* now exec the target ... */
+      if (cc->get_debug_mode () == 1)
+       {
+         traceme (arglist[0], arglist);
+         extype = NTXT ("traceme");
+       }
+      else
+       {
+         execvp (arglist[0], arglist);
+         extype = NTXT ("exevcp");
+       }
+      /* oops, exec of the target failed */
+      char *em = strerror (errno);
+      set_output ();    /* restore output for collector */
+      if (em == NULL)
+       dbe_write (2, GTXT ("memso %s of %s failed: errno = %d\n"), extype, argv[targ_index], errno);
+      else
+       dbe_write (2, GTXT ("memso %s of %s failed: %s\n"), extype, argv[targ_index], em);
+      exit (1);
+    }
+
+  /* normal path, setting up an experiment and launching the target */
+  /* set up the experiment */
+  ccret = cc->setup_experiment ();
+  if (ccret != NULL)
+    {
+      dbe_write (2, NTXT ("%s\n"), ccret);
+      free (ccret);
+      exit (1);
+    }
+  /* Beyond this point, the experiment is created */
+  if (collect_warnings != NULL)
+    {
+      warn_open ();
+      for (int i = 0; i < collect_warnings_idx; i++)
+       warn_comment (SP_JCMD_CWARN, COL_WARN_APP_NOT_READY, collect_warnings[i], (int) strlen (collect_warnings[i]));
+      warn_close ();
+    }
+  /* check cpu frequency variation for intel*/
+  unsigned char mode = COL_CPUFREQ_NONE;
+  int max_freq = get_cpu_frequency (&mode);
+  char freq_scaling[256];
+  char turbo_mode[256];
+  *freq_scaling = 0;
+  *turbo_mode = 0;
+  if (mode & COL_CPUFREQ_SCALING)
+    snprintf (freq_scaling, sizeof (freq_scaling), NTXT (" frequency_scaling=\"enabled\""));
+  if (mode & COL_CPUFREQ_TURBO)
+    snprintf (turbo_mode, sizeof (turbo_mode), NTXT (" turbo_mode=\"enabled\""));
+  if (mode != COL_CPUFREQ_NONE)
+    {
+      warn_open ();
+      if (warn_file != NULL)
+       {
+         warn_write ("<powerm>\n<frequency clk=\"%d\"%s%s/>\n</powerm>\n",
+                     max_freq, freq_scaling, turbo_mode);
+         warn_close ();
+       }
+    }
+
+  /* check for labels to write to notes file */
+  if (nlabels != 0)
+    {
+      char *nbuf;
+      char nbuf2[MAXPATHLEN];
+      // fetch the experiment name and CWD
+      char *exp = cc->get_experiment ();
+      char *ev = getcwd (nbuf2, sizeof (nbuf2));
+
+      // format the environment variable for the experiment directory name
+      if (ev != NULL && exp[0] != '/')
+       // cwd succeeded, and experiment is a relative path
+       nbuf = dbe_sprintf (NTXT ("%s/%s/%s"), nbuf2, exp, SP_NOTES_FILE);
+      else
+       // getcwd failed or experiment is a fullpath
+       nbuf = dbe_sprintf (NTXT ("%s/%s"), exp, SP_NOTES_FILE);
+
+      FILE *f = fopen (nbuf, NTXT ("w"));
+      free (nbuf);
+      if (f != NULL)
+       {
+         for (int i = 0; i < nlabels; i++)
+           fprintf (f, NTXT ("%s\n"), label[i]);
+         fclose (f);
+       }
+    }
+  /* check for user interrupt */
+  if (interrupt == 1)
+    {
+      cc->delete_expt ();
+      writeStr (2, GTXT ("User interrupt\n"));
+      exit (0);
+    }
+
+  /* print data-collection parameters */
+  if (verbose)
+    {
+      ccret = cc->show (0);
+      if (ccret != NULL)
+       writeStr (2, ccret);
+    }
+  ccret = cc->show_expt ();
+  if (ccret != NULL)
+    writeStr (1, ccret);    /* write this to stdout */
+
+  pid_t pid = (pid_t) cc->get_attach_pid ();
+  if (pid == (pid_t) 0)
+    {
+      /* No attach */
+      /* Set the environment for libcollector */
+      if (putenv_libcollector () != 0)
+       {
+         /* message has already been written */
+         cc->delete_expt ();
+         exit (1);
+       }
+      /* ensure original output fds restored for target */
+      reset_output ();
+
+      /* now exec the target ... */
+      if (cc->get_debug_mode () == 1)
+       {
+         traceme (arglist[0], arglist);
+         extype = NTXT ("traceme");
+       }
+      else
+       {
+         execvp (arglist[0], arglist);
+         extype = NTXT ("execvp");
+       }
+
+      /* we reach this point only if the target launch failed */
+      char *em = strerror (errno);
+
+      /* restore output for collector */
+      set_output ();
+
+      /* exec failed; delete experiment */
+      cc->delete_expt ();
+
+      /* print a message and exit */
+      if (em == NULL)
+       dbe_write (2, GTXT ("%s of %s failed: errno = %d\n"), extype, argv[targ_index], errno);
+      else
+       dbe_write (2, GTXT ("%s of %s failed: %s\n"), extype, argv[targ_index], em);
+      exit (1);
+    }
+  else
+    abort ();
+}
+
+/**
+ * Prepare a warning message and pass it to warn_write()
+ * @Parameters:
+ * kind Type of comment
+ * num ID
+ * s Comment sting
+ * len Length of the string
+ * @Return: none.
+ */
+void
+collect::warn_comment (const char *kind, int num, char *s, int len)
+{
+  if (len != 0)
+    warn_write (NTXT ("<event kind=\"%s\" id=\"%d\">%.*s</event>\n"),
+               kind, num, len, s);
+  else if (s == NULL)
+    warn_write (NTXT ("<event kind=\"%s\" id=\"%d\"/>\n"), kind, num);
+  else
+    warn_write (NTXT ("<event kind=\"%s\" id=\"%d\">%s</event>\n"), kind, num, s);
+}
+
+/**
+ * Open the warnings file in Append mode ("aw")
+ */
+void
+collect::warn_open ()
+{
+  // open the warnings file
+  warnfilename = dbe_sprintf (NTXT ("%s/%s"), cc->get_experiment (), SP_WARN_FILE);
+  int fd = open (warnfilename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+  warn_file = fdopen (fd, NTXT ("aw"));
+}
+
+/**
+ * Close the warnings file
+ */
+void
+collect::warn_close ()
+{
+  (void) fclose (warn_file);
+}
+
+/**
+ * Format the warning message and write it to the warnings file
+ */
+void
+collect::warn_write (const char *format, ...)
+{
+  char buf[4096];
+  // format the input arguments into a string
+  va_list va;
+  va_start (va, format);
+  vsnprintf (buf, sizeof (buf), format, va);
+  va_end (va);
+  // write it to the warnings file (warnings.xml)
+  fwrite (buf, 1, strlen (buf), warn_file);
+  fflush (warn_file);
+}
+
+/* process the args, setting expt. params,
+ *     and finding offset for a.out name
+ */
+int
+collect::check_args (int argc, char *argv[])
+{
+  int hseen = 0;
+  int hoffseen = 0;
+  int lseen = 0;
+  int tseen = 0;
+  int pseen = 0;
+  int sseen = 0;
+  int yseen = 0;
+  int Fseen = 0;
+  int Aseen = 0;
+  int Sseen = 0;
+  int Hseen = 0;
+  int iseen = 0;
+  int Jseen = 0;
+  int ofseen = 0;
+  char *expName = NULL;
+  bool overwriteExp = false;
+  char *ccret;
+  char *ccwarn;
+  for (targ_index = 1; targ_index < argc; targ_index++)
+    {
+      if (argv[targ_index] == NULL)
+       break;
+      if (dbe_strcmp (argv[targ_index], "--") == 0)
+       {
+         targ_index++;
+         break;
+       }
+      if (argv[targ_index][0] != '-')
+       break;
+      int param;
+      switch (argv[targ_index][1])
+       {
+       case 'y':
+         {
+           if (precheck == 1)
+             {
+               targ_index++;
+               if (argv[targ_index] == NULL)
+                 return 0;
+               break;
+             }
+           char *ptr;
+           int resume = 1;
+           if (checkflagterm (argv[targ_index]) == -1) return -1;
+           if (yseen != 0)
+             {
+               dupflagseen ('y');
+               return -1;
+             }
+           yseen++;
+           targ_index++;
+           if (argv[targ_index] == NULL)
+             {
+               writeStr (2, GTXT ("-y requires a signal argument\n"));
+               return -1;
+             }
+           if ((ptr = strrchr (argv[targ_index], ',')) != NULL)
+             {
+               if ((*(ptr + 1) != 'r') || (*(ptr + 2) != 0))
+                 {
+                   /* not the right trailer */
+                   dbe_write (2, GTXT ("Invalid delay signal %s\n"), argv[targ_index]);
+                   return -1;
+                 }
+               resume = 0;
+               *ptr = 0;
+             }
+           param = cc->find_sig (argv[targ_index]);
+           if (param < 0)
+             {
+               /* invalid signal */
+               dbe_write (2, GTXT ("Invalid delay signal %s\n"), argv[targ_index]);
+               return -1;
+             }
+           ccret = cc->set_pauseresume_signal (param, resume);
+           if (ccret != NULL)
+             {
+               /* invalid signal; write message */
+               writeStr (2, ccret);
+               return -1;
+             }
+           break;
+         }
+       case 'l':
+         if (precheck == 1)
+           {
+             targ_index++;
+             if (argv[targ_index] == NULL)
+               return 0;
+             break;
+           }
+         if (checkflagterm (argv[targ_index]) == -1) return -1;
+         if (lseen != 0)
+           {
+             dupflagseen ('l');
+             return -1;
+           }
+         lseen++;
+         targ_index++;
+         if (argv[targ_index] == NULL)
+           {
+             writeStr (2, GTXT ("-l requires a signal argument\n"));
+             return -1;
+           }
+         param = cc->find_sig (argv[targ_index]);
+         if (param < 0)
+           {
+             /* invalid signal */
+             dbe_write (2, GTXT ("Invalid sample signal %s\n"), argv[targ_index]);
+             return -1;
+           }
+         ccret = cc->set_sample_signal (param);
+         if (ccret != NULL)
+           {
+             /* invalid signal; write message */
+             writeStr (2, ccret);
+             free (ccret);
+             return -1;
+           }
+         break;
+
+#ifdef GPROFNG_DOES_NOT_SUPPORT
+       case 'P':
+         if (precheck == 1)
+           {
+             targ_index++;
+             if (argv[targ_index] == NULL)
+               return 0;
+             break;
+           }
+         if (checkflagterm (argv[targ_index]) == -1)
+           return -1;
+         if (Pseen != 0)
+           {
+             dupflagseen ('P');
+             return -1;
+           }
+         Pseen++;
+         targ_index++;
+         if (argv[targ_index] == NULL)
+           {
+             writeStr (2, GTXT ("-P requires a process pid argument\n"));
+             return -1;
+           }
+         ccret = cc->set_attach_pid (argv[targ_index]);
+         if (ccret != NULL)
+           {
+             /* error; write message */
+             writeStr (2, ccret);
+             free (ccret);
+             return -1;
+           }
+         break;
+#endif
+       case 't':
+         if (precheck == 1)
+           {
+             targ_index++;
+             if (argv[targ_index] == NULL)
+               return 0;
+             break;
+           }
+
+         if (checkflagterm (argv[targ_index]) == -1) return -1;
+         if (tseen != 0)
+           {
+             dupflagseen ('t');
+             return -1;
+           }
+         tseen++;
+         targ_index++;
+         if (argv[targ_index] == NULL)
+           {
+             writeStr (2, GTXT ("-t requires a run-duration argument\n"));
+             return -1;
+           }
+         ccret = cc->set_time_run (argv[targ_index]);
+         if (ccret != NULL)
+           {
+             /* error; write message */
+             writeStr (2, ccret);
+             free (ccret);
+             return -1;
+           }
+         break;
+       case 'p':
+         {
+           char *warnmsg;
+           if (precheck == 1)
+             {
+               targ_index++;
+               if (argv[targ_index] == NULL)
+                 return 0;
+               break;
+             }
+           if (checkflagterm (argv[targ_index]) == -1) return -1;
+           if (pseen != 0)
+             {
+               dupflagseen ('p');
+               return -1;
+             }
+           pseen++;
+           targ_index++;
+           if (argv[targ_index] == NULL)
+             {
+               writeStr (2, GTXT ("-p requires a clock-profiling argument\n"));
+               return -1;
+             }
+           ccret = cc->set_clkprof (argv[targ_index], &warnmsg);
+           if (ccret != NULL)
+             {
+               writeStr (2, ccret);
+               free (ccret);
+               return -1;
+             }
+           if (warnmsg != NULL)
+             {
+               writeStr (2, warnmsg);
+               free (warnmsg);
+             }
+           break;
+         }
+       case 's':
+         if (precheck == 1)
+           {
+             targ_index++;
+             if (argv[targ_index] == NULL)
+               return 0;
+             break;
+           }
+         if (checkflagterm (argv[targ_index]) == -1) return -1;
+         if (sseen != 0)
+           {
+             dupflagseen ('s');
+             return -1;
+           }
+         sseen++;
+         targ_index++;
+         if (argv[targ_index] == NULL)
+           {
+             writeStr (2, GTXT ("-s requires a synchronization-tracing argument\n"));
+             return -1;
+           }
+         ccret = cc->set_synctrace (argv[targ_index]);
+         if (ccret != NULL)
+           {
+             writeStr (2, ccret);
+             free (ccret);
+             return -1;
+           }
+         break;
+       case 'h':
+         {
+           if (precheck == 1)
+             {
+               targ_index++;
+               if (argv[targ_index] == NULL)
+                 return 0;
+               break;
+             }
+           if (checkflagterm (argv[targ_index]) == -1)
+             return -1;
+           targ_index++;
+           if ((argv[targ_index] == NULL) || (strlen (argv[targ_index]) == 0))
+             {
+               writeStr (2, GTXT ("-h requires a HW-counter-profiling argument\n"));
+               return -1;
+             }
+           // Check for some special cases
+           char * string = argv[targ_index];
+           if (strcmp (argv[targ_index], NTXT ("off")) == 0)
+             {
+               if (hseen != 0)
+                 {
+                   no_short_usage = 1;
+                   writeStr (2, GTXT ("-h off cannot be used with any other -h arguments\n"));
+                   return -1;
+                 }
+               hoffseen = 1;
+               hseen = 1;
+               cc->disable_hwc ();
+               break;
+             }
+           // Check to see if we can use HWC
+           unsigned hwc_maxregs = hwc_get_max_concurrent (false);
+           if (hwc_maxregs == 0)
+             {
+               char buf[1024];
+               char *pch = hwcfuncs_errmsg_get (buf, sizeof (buf), 0);
+               if (*pch)
+                 dbe_write (2, GTXT ("HW counter profiling is not supported on this system: %s%s"),
+                            pch, pch[strlen (pch) - 1] == '\n' ? "" : "\n");
+               else
+                 dbe_write (2, GTXT ("HW counter profiling is not supported on this system\n"));
+               no_short_usage = 1;
+               return -1;
+             }
+           // Make sure there's no other -h after -h off
+           if (hoffseen != 0)
+             {
+               no_short_usage = 1;
+               writeStr (2, GTXT ("No -h arguments can be used after -h off\n"));
+               return -1;
+             }
+           // set up to process HW counters (to know about default counters)
+           cc->setup_hwc ();
+           hseen++;
+           char *warnmsg;
+           if (strcmp (argv[targ_index], NTXT ("on")) == 0)
+             ccret = cc->add_default_hwcstring ("on", &warnmsg, true);
+           else if (strcmp (argv[targ_index], NTXT ("hi")) == 0 ||
+                    strcmp (argv[targ_index], NTXT ("high")) == 0)
+             ccret = cc->add_default_hwcstring ("hi", &warnmsg, true);
+           else if (strcmp (argv[targ_index], NTXT ("lo")) == 0 ||
+                    strcmp (argv[targ_index], NTXT ("low")) == 0)
+             ccret = cc->add_default_hwcstring ("lo", &warnmsg, true);
+           else if (strcmp (argv[targ_index], NTXT ("auto")) == 0)
+             ccret = cc->add_default_hwcstring ("auto", &warnmsg, true);
+           else
+             ccret = cc->add_hwcstring (string, &warnmsg);
+           if (ccret != NULL)
+             {
+               /* set global flag to suppress the short_usage message for any subsequent HWC errors */
+               no_short_usage = 1;
+               writeStr (2, ccret);
+               free (ccret);
+               return -1;
+             }
+           if (warnmsg != NULL)
+             {
+               writeStr (2, warnmsg);
+               free (warnmsg);
+             }
+           break;
+         }
+       case 'O':
+         overwriteExp = true;
+         __attribute__ ((fallthrough));
+       case 'o':
+         if (precheck == 1)
+           {
+             targ_index++;
+             if (argv[targ_index] == NULL)
+               return 0;
+             break;
+           }
+         if (checkflagterm (argv[targ_index]) == -1)
+           return -1;
+         if (argv[targ_index + 1] == NULL)
+           {
+             dbe_write (2, GTXT ("Argument %s must be followed by a file name\n"),
+                        argv[targ_index]);
+             return -1;
+           }
+         if (expName != NULL)
+           {
+             dbe_write (2, GTXT ("Only one -o or -O argument may be used\n"));
+             dupflagseen ('o');
+             return -1;
+           }
+         expName = argv[targ_index + 1];
+         targ_index++;
+         break;
+       case 'S':
+         if (precheck == 1)
+           {
+             targ_index++;
+             if (argv[targ_index] == NULL)
+               return 0;
+             break;
+           }
+         if (checkflagterm (argv[targ_index]) == -1) return -1;
+         if (argv[targ_index + 1] == NULL)
+           {
+             dbe_write (2, GTXT ("Argument %s must be followed by a sample interval name\n"),
+                        argv[targ_index]);
+             return -1;
+           }
+         if (Sseen != 0)
+           {
+             dupflagseen ('S');
+             return -1;
+           }
+         Sseen++;
+         ccret = cc->set_sample_period (argv[targ_index + 1]);
+         if (ccret != NULL)
+           {
+             writeStr (2, ccret);
+             free (ccret);
+             return -1;
+           }
+         targ_index++;
+         break;
+       case 'H':
+         if (precheck == 1)
+           {
+             targ_index++;
+             if (argv[targ_index] == NULL)
+               return 0;
+             break;
+           }
+         if (checkflagterm (argv[targ_index]) == -1)
+           return -1;
+         if (argv[targ_index + 1] == NULL)
+           {
+             dbe_write (2, GTXT ("Argument %s requires a heap-tracing argument\n"),
+                        argv[targ_index]);
+             return -1;
+           }
+         if (Hseen != 0)
+           {
+             dupflagseen ('H');
+             return -1;
+           }
+         Hseen++;
+         ccret = cc->set_heaptrace (argv[targ_index + 1]);
+         if (ccret != NULL)
+           {
+             writeStr (2, ccret);
+             free (ccret);
+             return -1;
+           }
+         if (cc->get_java_default () == 1)
+           cc->set_java_mode (NTXT ("off"));
+         targ_index++;
+         break;
+       case 'i':
+         if (precheck == 1)
+           {
+             targ_index++;
+             if (argv[targ_index] == NULL)
+               return 0;
+             break;
+           }
+         if (checkflagterm (argv[targ_index]) == -1)
+           return -1;
+         if (argv[targ_index + 1] == NULL)
+           {
+             fprintf (stderr, GTXT ("Argument %s requires an I/O-tracing argument\n"),
+                      argv[targ_index]);
+             return -1;
+           }
+         if (iseen != 0)
+           {
+             dupflagseen ('i');
+             return -1;
+           }
+         iseen++;
+         ccret = cc->set_iotrace (argv[targ_index + 1]);
+         if (ccret != NULL)
+           {
+             writeStr (2, ccret);
+             free (ccret);
+             return -1;
+           }
+         targ_index++;
+         break;
+       case 'j':
+         if (precheck == 1)
+           {
+             targ_index++;
+             if (argv[targ_index] == NULL)
+               return 0;
+             break;
+           }
+         if (checkflagterm (argv[targ_index]) == -1) return -1;
+         if (argv[targ_index + 1] == NULL)
+           {
+             dbe_write (2, GTXT ("Argument %s requires a java-profiling argument\n"),
+                        argv[targ_index]);
+             return -1;
+           }
+         if (jseen_global != 0)
+           {
+             dupflagseen ('j');
+             return -1;
+           }
+         jseen_global++;
+         ccret = cc->set_java_mode (argv[targ_index + 1]);
+         if (ccret != NULL)
+           {
+             writeStr (2, ccret);
+             free (ccret);
+             return -1;
+           }
+         targ_index++;
+         break;
+       case 'J':
+         if (precheck == 1)
+           {
+             targ_index++;
+             if (argv[targ_index] == NULL)
+               return 0;
+             break;
+           }
+         if (checkflagterm (argv[targ_index]) == -1) return -1;
+         if (argv[targ_index + 1] == NULL)
+           {
+             dbe_write (2, GTXT ("Argument %s requires a java argument\n"),
+                        argv[targ_index]);
+             return -1;
+           }
+         if (Jseen != 0)
+           {
+             dupflagseen ('J');
+             return -1;
+           }
+         Jseen++;
+         ccret = cc->set_java_args (argv[targ_index + 1]);
+         if (ccret != NULL)
+           {
+             writeStr (2, ccret);
+             free (ccret);
+             return -1;
+           }
+         targ_index++;
+         break;
+       case 'F':
+         if (precheck == 1)
+           {
+             targ_index++;
+             if (argv[targ_index] == NULL)
+               return 0;
+             break;
+           }
+         if (checkflagterm (argv[targ_index]) == -1)
+           return -1;
+         if (argv[targ_index + 1] == NULL)
+           {
+             dbe_write (2, GTXT ("Argument %s requires a descendant-following argument\n"),
+                        argv[targ_index]);
+             return -1;
+           }
+         if (Fseen != 0)
+           {
+             dupflagseen ('F');
+             return -1;
+           }
+         Fseen++;
+         ccret = cc->set_follow_mode (argv[targ_index + 1]);
+         if (ccret != NULL)
+           {
+             writeStr (2, ccret);
+             free (ccret);
+             return -1;
+           }
+         targ_index++;
+         break;
+       case 'a':
+         if (precheck == 1)
+           {
+             targ_index++;
+             if (argv[targ_index] == NULL)
+               return 0;
+             break;
+           }
+         if (checkflagterm (argv[targ_index]) == -1)
+           return -1;
+         if (argv[targ_index + 1] == NULL)
+           {
+             dbe_write (2, GTXT ("Argument %s requires a load-object archiving argument\n"),
+                        argv[targ_index]);
+             return -1;
+           }
+         if (Aseen != 0)
+           {
+             dupflagseen ('a');
+             return -1;
+           }
+         Aseen++;
+         ccret = cc->set_archive_mode (argv[targ_index + 1]);
+         if (ccret != NULL)
+           {
+             writeStr (2, ccret);
+             free (ccret);
+             return -1;
+           }
+         targ_index++;
+         break;
+       case 'C':
+         if (precheck == 1)
+           {
+             targ_index++;
+             if (argv[targ_index] == NULL)
+               return 0;
+             break;
+           }
+         if (checkflagterm (argv[targ_index]) == -1)
+           return -1;
+         if (argv[targ_index + 1] == NULL)
+           {
+             dbe_write (2, GTXT ("Argument %s must be followed by a comment\n"),
+                        argv[targ_index]);
+             return -1;
+           }
+         if (nlabels == MAXLABELS)
+           {
+             dbe_write (2, GTXT ("No more than %d comments may be specified\n"),
+                        MAXLABELS);
+             return -1;
+           }
+         label[nlabels] = argv[targ_index + 1];
+         nlabels++;
+         targ_index++;
+         break;
+       case 'n':
+       case 'v':
+       case 'V':
+         if (precheck == 1)
+           break;
+         do_flag (&argv[targ_index][1]);
+         break;
+       case 'Z':
+         // special undocumented argument for debug builds only to allow analyzer to
+         // LD_PRELOAD mem.so for the target it spawns
+         mem_so_me = true;
+         break;
+       case '-':
+         if (strcmp (argv[targ_index], NTXT ("--verbose")) == 0)
+           do_flag ("v");
+         else if (strcmp (argv[targ_index], "--outfile") == 0)
+           {
+             if (precheck == 0)
+               {
+                 targ_index++;
+                 if (argv[targ_index] == NULL)
+                   return 0;
+                 break;
+               }
+             // process this argument now
+             if (argv[targ_index + 1] == NULL)
+               {
+                 dbe_write (2, GTXT ("Argument %s requires a file argument\n"),
+                            argv[targ_index]);
+                 return -1;
+               }
+             if (ofseen != 0)
+               {
+                 dupflagseen (argv[targ_index]);
+                 return -1;
+               }
+             ofseen++;
+             if (outredirect == NULL)
+               {
+                 outredirect = argv[targ_index + 1];
+                 set_output ();
+               } // else already redirected; ignore with no message
+             targ_index++;
+           }
+         else
+           {
+             dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), argv[targ_index]);
+             return -1;
+           }
+         break;
+       default:
+         dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), argv[targ_index]);
+         return -1;
+       }
+    }
+  if (targ_index >= argc)
+    return -1;
+  if (argv[targ_index] == NULL)
+    {
+      if (precheck == 1)
+       return 0;
+      if (cc->get_attach_pid () != 0)  /* no target is OK, if we're attaching */
+       return 0;
+      writeStr (2, GTXT ("Name of target must be specified\n"));
+      return -1;
+    }
+  if (expName)
+    {
+      ccwarn = NULL;
+      ccret = cc->set_expt (expName, &ccwarn, overwriteExp);
+      if (ccwarn)
+       {
+         writeStr (2, ccwarn);
+         free (ccwarn);
+       }
+      if (ccret)
+       {
+         writeStr (2, ccret);
+         return -1;
+       }
+    }
+  if (cc->get_attach_pid () != 0)
+    {
+      writeStr (2, GTXT ("Name of target must not be specified when -P is used\n"));
+      return -1;
+    }
+  return targ_index;
+}
+
+int
+collect::checkflagterm (const char *c)
+{
+  if (c[2] != 0)
+    {
+      dbe_write (2, GTXT ("collect: unrecognized argument `%s'\n"), c);
+      return -1;
+    }
+  return 0;
+}
+
+int
+collect::do_flag (const char *flags)
+{
+  char *s;
+  for (int i = 0;; i++)
+    {
+      switch (flags[i])
+       {
+       case 0: // end of string
+         return 0;
+       case 'n':
+         disabled = 1;
+         if (verbose != 1)
+           {
+// Ruud
+             Application::print_version_info ();
+/*
+             dbe_write (2, NTXT ("GNU %s version %s\n"),
+                        get_basename (prog_name), VERSION);
+*/
+             verbose = 1;
+           }
+         break;
+       case 'x':
+         s = cc->set_debug_mode (1);
+         if (s)
+           {
+             writeStr (2, s);
+             free (s);
+           }
+         break;
+       case 'v':
+         if (verbose != 1)
+           {
+// Ruud
+             Application::print_version_info ();
+/*
+             dbe_write (2, NTXT ("GNU %s version %s\n"),
+                        get_basename (prog_name), VERSION);
+*/
+             verbose = 1;
+           }
+         break;
+       case 'V':
+// Ruud
+         Application::print_version_info ();
+/*
+         dbe_write (2, NTXT ("GNU %s version %s\n"),
+                    get_basename (prog_name), VERSION);
+*/
+         /* no further processing.... */
+         exit (0);
+       }
+    }
+}
+
+/*
+ * traceme - cause the caller to stop at the end of the next exec()
+ *      so that a debugger can attach to the new program
+ *
+ * Takes same arguments as execvp()
+ */
+int
+collect::traceme (const char *execvp_file, char *const execvp_argv[])
+{
+  int ret = -1;
+  pid_t pid = fork ();
+  if (pid == 0)
+    { // child
+      // child will set up itself to be PTRACE'd, and then exec the target executable
+      /* reset the SP_COLLECTOR_FOUNDER value to the new pid */
+      pid_t mypid = getpid ();
+      char *ev = dbe_sprintf (NTXT ("%s=%d"), SP_COLLECTOR_FOUNDER, mypid);
+      if (putenv (ev) != 0)
+       {
+         dbe_write (2, GTXT ("fork-child: Can't putenv of \"%s\": run aborted\n"), ev);
+         return 1;
+       }
+      ptrace (PTRACE_TRACEME, 0, NULL, NULL); // initiate trace
+      ret = execvp (execvp_file, execvp_argv); // execvp user command
+      return ret; // execvp failed
+    }
+  else if (pid > 0)
+    { // parent
+      int status;
+      if (waitpid (pid, &status, 0) != pid)
+       { // wait for execvp to cause signal
+         writeStr (2, GTXT ("parent waitpid() failed\n"));
+         return -2;
+       }
+      if (!WIFSTOPPED (status))
+       writeStr (2, GTXT ("WIFSTOPPED(status) failed\n"));
+
+      // originally, PTRACE_DETACH would send SIGTSTP, but now we do it here:
+      if (kill (pid, SIGTSTP) != 0)
+       writeStr (2, GTXT ("kill(pid, SIGTSTP) failed\n"));
+      if (ptrace (PTRACE_DETACH, pid, NULL, 0) != 0)
+       { // detach trace
+         writeStr (2, GTXT ("ptrace(PTRACE_DETACH) failed\n"));
+         return -4;
+       }
+      dbe_write (2, GTXT ("Waiting for attach from debugger: pid=%d\n"), (int) pid);
+
+      // wait for an external debugger to attach
+      if (waitpid (pid, &status, 0) != pid)
+       { // keep parent alive until child quits
+         writeStr (2, GTXT ("parent final waitpid() failed\n"));
+         return -5;
+       }
+    }
+  else
+    return -1; // fork failed
+  exit (0);
+}
+
+void
+collect::dupflagseen (char c)
+{
+  dbe_write (2, GTXT ("Only one -%c argument may be used\n"), c);
+}
+
+void
+collect::dupflagseen (const char *s)
+{
+  dbe_write (2, GTXT ("Only one %s argument may be used\n"), s);
+}
+
+int
+collect::set_output ()
+{
+  static int initial = 1;
+  if (outredirect)
+    {
+      int fd = open (outredirect, O_WRONLY | O_CREAT | O_APPEND,
+                    S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+      if (fd == -1)
+       {
+         dbe_write (2, GTXT ("Warning: Can't open collector output `%s': %s\n"),
+                    outredirect, strerror (errno));
+       }
+      else
+       {
+         if ((saved_stdout = dup (1)) == -1 || dup2 (fd, 1) == -1)
+           dbe_write (2, GTXT ("Warning: Can't divert collector %s: %s\n"),
+                      NTXT ("stdout"), strerror (errno));
+         if ((saved_stderr = dup (2)) == -1 || dup2 (fd, 2) == -1)
+           dbe_write (2, GTXT ("Warning: Can't divert collector %s: %s\n"),
+                      NTXT ("stderr"), strerror (errno));
+         close (fd);
+         if ((saved_stdout != -1) && (saved_stderr != -1))
+           {
+             if (initial)
+               {
+                 struct timeval tp;
+                 gettimeofday (&tp, NULL);
+                 writeStr (2, ctime (&tp.tv_sec));
+                 initial = 0;
+               }
+             return 1; // diversion in place
+           }
+       }
+    }
+  return 0; // no diversion
+}
+
+void
+collect::reset_output ()
+{
+  if (saved_stdout != -1 &&
+      (dup2 (saved_stdout, 1) == -1 || close (saved_stdout)))
+    dbe_write (2, GTXT ("Warning: Can't restore collector stdout: %s\n"),
+              strerror (errno));
+  if (saved_stderr != -1 &&
+      (dup2 (saved_stderr, 2) == -1 || close (saved_stderr)))
+    dbe_write (2, GTXT ("Warning: Can't restore collector stderr: %s\n"),
+              strerror (errno));
+}
+
+void
+collect::usage ()
+{
+
+/*
+  Ruud - Isolate this line because it has an argument.  Otherwise it would be at the
+  end of this long list.
+*/
+  printf ( GTXT (
+    "Usage: gprofng collect app [OPTION(S)] TARGET [TARGET_ARGUMENTS]\n")),
+
+/*
+-------------------------------------------------------------------------------
+  For a reason I don't understand, the continuation line(s) need to start at
+  column 26 in order for help2man to do the righ thing. Ruud
+-------------------------------------------------------------------------------
+*/
+  printf ( GTXT (
+    "\n"
+    "Collect performance data on the target program. In addition to Program\n"
+    "Counter PC) sampling, hardware event counters and various tracing options\n"
+    "are supported.\n"
+    "\n"
+    "Options:\n"
+    "\n"
+    " --version           print the version number and exit.\n"
+    " --help              print usage information and exit.\n"
+    " --verbose {on|off}  enable (on) or disable (off) verbose mode; the default is \"off\".\n"
+    "\n"
+    " -p {off|on|lo|hi|<value>}  disable (off) or enable (on) clock-profiling using a default\n"
+    "                    sampling granularity, or enable clock-profiling implicitly by\n"
+    "                    setting the sampling granularity (lo, hi, or a specific value\n"
+    "                    in ms); by default clock profiling is enabled.\n"
+    "\n"
+    " -h {<ctr_def>...,<ctr_n_def>}  enable hardware event counter profiling and select\n"
+    "                    the counter(s); to see the supported counters on this system use\n"
+    "                    the -h option without other arguments.\n"
+    "\n"
+    " -o <exp_name>     specify the name for (and path to) the experiment directory; the\n"
+    "                    the default path is the current directory.\n"
+    "\n"
+    " -O <exp_name>     the same as -o, but unlike the -o option, silently overwrite an\n"
+    "                    existing experiment directory with the same name.\n"
+    "\n"
+    " -C <label>        add up to 10 comment labels to the experiment; comments appear in\n"
+    "                    the notes section of the header.\n"
+    "\n"
+    " -j {on|off|<path>} enable (on), or disable (off) Java profiling when the target\n"
+    "                     program is a JVM; optionally set the <path> to a non-default JVM;\n"
+    "                     the default is \"-j on\".\n"
+    "\n"
+    " -J <java-args>    specify arguments to the JVM.\n"
+    "\n"
+    " -t <duration>[m|s]  specify the duration over which to record data; the default unit\n"
+    "                      is seconds (s), but can be set to minutes (m).\n"
+    "\n"
+    " -n                  dry run; display several run-time settings, but do not run the\n"
+    "                      target, or collect performance data.\n"
+    "\n"
+    " -y <signal>[,r]     specify delayed initialization and a pause/resume signal; by default\n"
+    "                      the target starts in paused mode; if the optional r keyword is\n"
+    "                      provided, start in resumed mode.\n"
+    "\n"
+    " -F {off|on|=<regex>}  control to follow descendant processes; disable (off), enable (on),\n"
+    "                        or collect data on all descendant processes whose name matches the\n"
+    "                        specified regular expression; the default is \"-F on\".\n"
+    "\n"
+    " -a {off|on|ldobjects|src|usedldobjects|usedsrc}  specify archiving of binaries and other files;\n"
+    "                    in addition to disable this feature (off), or enable archiving off all\n"
+    "                    loadobjects and sources (on), the other options support a more\n"
+    "                    refined selection. All of these options enable archiving, but the\n"
+    "                    keyword controls what exactly is selected: all load objects (ldobjects),\n"
+    "                    all source files (src), the loadobjects asscoiated with a program counter\n"
+    "                    (usedldobjects), or the source files associated with a program counter\n"
+    "                    (usedsrc); the default is \"-a ldobjects\".\n"
+    "\n"
+    " -S {off|on|<seconds>}  disable (off) or enable (on) periodic sampling of process-wide resource\n"
+    "                         utilization; by default sampling occurs every second; use the <seconds>\n"
+    "                         option to change this; the default is \"-S on\".\n"
+    "\n"
+    " -l <signal>       specify a signal that will trigger a sample of process-wide resource utilization.\n"
+    "\n"
+    " -s <option>[,<API>]  enable synchronization wait tracing; <option> is used to define the specifics\n"
+    "                       of the tracing (on, off, <threshold>, or all); <API> is used to select the API:\n"
+    "                       \"n\" selects native/Pthreads, \"j\" selects Java, and \"nj\" selects both;\n"
+    "                       the default is \"-s off\".\n"
+    "\n"
+    " -H {off|on}        disable (off), or enable (on) heap tracing; the default is \"-H off\".\n"
+    "\n"
+    " -i {off|on}        disable (off), or enable (on) I/O tracing; the default is \"-i off\".\n"
+    "\n"
+    "Documentation:\n"
+    "\n"
+    "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
+    "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
+    "should give you access to this document.\n"
+    "\n"
+    "See also:\n"
+    "\n"
+    "gprofng(1), gp-archive(1), gp-display-html(1), gp-display-src(1), gp-display-text(1)\n"));
+/*
+  char *s = dbe_sprintf (GTXT ("Usage:  %s <args> target <target-args>\n"),
+                        whoami);
+  writeStr (usage_fd, s);
+  free (s);
+  writeStr (usage_fd, GTXT ("  -p {lo|on|hi|off|<value>}\tspecify clock-profiling\n"));
+  writeStr (usage_fd, GTXT ("\t`lo'    per-thread rate of ~10 samples/second\n"));
+  writeStr (usage_fd, GTXT ("\t`on'    per-thread rate of ~100 samples/second (default)\n"));
+  writeStr (usage_fd, GTXT ("\t`hi'    per-thread rate of ~1000 samples/second\n"));
+  writeStr (usage_fd, GTXT ("\t`off'   disable clock profiling\n"));
+  writeStr (usage_fd, GTXT ("\t<value> specify profile timer period in millisec.\n"));
+  s = dbe_sprintf (GTXT ("\t\t\tRange on this system is from %.3f to %.3f millisec.\n\t\t\tResolution is %.3f millisec.\n"),
+                  (double) cc->get_clk_min () / 1000.,
+                  (double) cc->get_clk_max () / 1000.,
+                  (double) cc->get_clk_res () / 1000.);
+  writeStr (usage_fd, s);
+  free (s);
+  writeStr (usage_fd, GTXT ("  -h <ctr_def>...[,<ctr_n_def>]\tspecify HW counter profiling\n"));
+  s = dbe_sprintf (GTXT ("\tto see the supported HW counters on this machine, run \"%s -h\" with no other arguments\n"),
+                  whoami);
+  writeStr (usage_fd, s);
+  free (s);
+  writeStr (usage_fd, GTXT ("  -s <threshold>[,<scope>]\tspecify synchronization wait tracing\n"));
+  writeStr (usage_fd, GTXT ("\t<scope> is \"j\" for tracing Java-APIs, \"n\" for tracing native-APIs, or \"nj\" for tracing both\n"));
+  writeStr (usage_fd, GTXT ("  -H {on|off}\tspecify heap tracing\n"));
+  writeStr (usage_fd, GTXT ("  -i {on|off}\tspecify I/O tracing\n"));
+  writeStr (usage_fd, GTXT ("  -N <lib>\tspecify library to exclude count from instrumentation (requires -c also)\n"));
+  writeStr (usage_fd, GTXT ("          \tmultiple -N arguments can be provided\n"));
+  writeStr (usage_fd, GTXT ("  -j {on|off|path}\tspecify Java profiling\n"));
+  writeStr (usage_fd, GTXT ("  -J <java-args>\tspecify arguments to Java for Java profiling\n"));
+  writeStr (usage_fd, GTXT ("  -t <duration>\tspecify time over which to record data\n"));
+  writeStr (usage_fd, GTXT ("  -n\tdry run -- don't run target or collect performance data\n"));
+  writeStr (usage_fd, GTXT ("  -y <signal>[,r]\tspecify delayed initialization and pause/resume signal\n"));
+  writeStr (usage_fd, GTXT ("\tWhen set, the target starts in paused mode;\n\t  if the optional r is provided, it starts in resumed mode\n"));
+  writeStr (usage_fd, GTXT ("  -F {on|off|=<regex>}\tspecify following descendant processes\n"));
+  writeStr (usage_fd, GTXT ("  -a {on|ldobjects|src|usedldobjects|usedsrc|off}\tspecify archiving of binaries and other files;\n"));
+  writeStr (usage_fd, GTXT ("  -S {on|off|<seconds>}\t Set the interval for periodic sampling of process-wide resource utilization\n"));
+  writeStr (usage_fd, GTXT ("  -l <signal>\tspecify signal that will trigger a sample of process-wide resource utilization\n"));
+  writeStr (usage_fd, GTXT ("  -o <expt>\tspecify experiment name\n"));
+  writeStr (usage_fd, GTXT ("  --verbose\tprint expanded log of processing\n"));
+  writeStr (usage_fd, GTXT ("  -C <label>\tspecify comment label (up to 10 may appear)\n"));
+  writeStr (usage_fd, GTXT ("  -V|--version\tprint version number and exit\n"));
+*/
+  /* don't document this feature */
+  //   writeStr (usage_fd, GTXT("  -Z\tPreload mem.so, and launch target [no experiment]\n") );
+/*
+  writeStr (usage_fd, GTXT ("\n See the gp-collect(1) man page for more information\n"));
+*/
+
+#if 0
+  /* print an extended usage message */
+  /* find a Java for Java profiling, set Java on to check Java */
+  find_java ();
+  cc->set_java_mode (NTXT ("on"));
+
+  /* check for variable-clock rate */
+  unsigned char mode = COL_CPUFREQ_NONE;
+  get_cpu_frequency (&mode);
+  if (mode != COL_CPUFREQ_NONE)
+    writeStr (usage_fd, GTXT ("NOTE: system has variable clock frequency, which may cause variable program run times.\n"));
+
+  /* show the experiment that would be run */
+  writeStr (usage_fd, GTXT ("\n Default experiment:\n"));
+  char *ccret = cc->setup_experiment ();
+  if (ccret != NULL)
+    {
+      writeStr (usage_fd, ccret);
+      free (ccret);
+      exit (1);
+    }
+  cc->delete_expt ();
+  ccret = cc->show (1);
+  if (ccret != NULL)
+    {
+      writeStr (usage_fd, ccret);
+      free (ccret);
+    }
+#endif
+}
+
+void
+collect::short_usage ()
+{
+  if (no_short_usage == 0)
+    dbe_write (usage_fd, GTXT ("Run \"%s --help\" for a usage message.\n"), whoami);
+}
+
+void
+collect::show_hwc_usage ()
+{
+  usage_fd = 1;
+  short_usage ();
+  cc->setup_hwc ();
+  hwc_usage (false, whoami, NULL);
+}
+
+void
+collect::writeStr (int f, const char *buf)
+{
+  if (buf != NULL)
+    write (f, buf, strlen (buf));
+}
diff --git a/gprofng/src/gp-display-src.cc b/gprofng/src/gp-display-src.cc
new file mode 100644 (file)
index 0000000..ca7853d
--- /dev/null
@@ -0,0 +1,752 @@
+/* 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 <unistd.h>
+#include <fcntl.h>
+
+#include "util.h"
+#include "DbeApplication.h"
+#include "DbeSession.h"
+#include "Function.h"
+#include "LoadObject.h"
+#include "Module.h"
+#include "DbeView.h"
+#include "Print.h"
+#include "DbeFile.h"
+#include "Command.h"
+
+class er_src : public DbeApplication
+{
+public:
+  er_src (int argc, char *argv[]);
+  void start (int argc, char *argv[]);
+
+private:
+
+  // override methods in base class
+  void usage ();
+  int check_args (int argc, char *argv[]);
+  void run_args (int argc, char *argv[]);
+
+  enum Obj_Types
+  {
+    OT_EXE_ELF = 0, OT_JAVA_CLASS, OT_JAR_FILE, OT_UNKNOWN
+  };
+
+  void open (char *exe);
+  void dump_annotated (char *name, char* sel, char *src, DbeView *dbev,
+                      bool is_dis, bool first);
+  void checkJavaClass (char *exe);
+  void print_header (bool first, const char* text);
+  void proc_cmd (CmdType cmd_type, bool first, char *arg1,
+                const char *arg2, const char *arg3 = NULL);
+  FILE *set_outfile (char *cmd, FILE *&set_file);
+
+  bool is_java_class ()     { return obj_type == OT_JAVA_CLASS; }
+
+  int dbevindex;
+  DbeView *dbev;
+  LoadObject *lo;
+  Obj_Types obj_type;
+  const char *out_fname;
+  FILE *out_file;
+  bool isDisasm;
+  bool isFuncs;
+  bool isDFuncs;
+  bool isSrc;
+  bool v_opt;
+  int multiple;
+  char *str_compcom;
+  bool hex_visible;
+  int src_visible;
+  int vis_src;
+  int vis_dis;
+  int threshold_src;
+  int threshold_dis;
+  int threshold;
+  int vis_bits;
+};
+
+static int
+real_main (int argc, char *argv[])
+{
+  er_src *src = new er_src (argc, argv);
+  src->start (argc, argv);
+  delete src;
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  return catch_out_of_memory (real_main, argc, argv);
+}
+
+er_src::er_src (int argc, char *argv[])
+: DbeApplication (argc, argv)
+{
+  obj_type = OT_UNKNOWN;
+  out_fname = "<stdout>";
+  out_file = stdout;
+  isDisasm = false;
+  isFuncs = false;
+  isDFuncs = false;
+  isSrc = false;
+  v_opt = false;
+  multiple = 0;
+  lo = NULL;
+}
+
+static int
+FuncNameCmp (const void *a, const void *b)
+{
+  Function *item1 = *((Function **) a);
+  Function *item2 = *((Function **) b);
+  return strcmp (item1->get_mangled_name (), item2->get_mangled_name ());
+}
+
+static int
+FuncAddrCmp (const void *a, const void *b)
+{
+  Function *item1 = *((Function **) a);
+  Function *item2 = *((Function **) b);
+  return (item1->img_offset == item2->img_offset) ?
+         FuncNameCmp (a, b) : item1->img_offset > item2->img_offset ? 1 : -1;
+}
+
+void
+er_src::usage ()
+{
+
+/*
+  Ruud - Isolate this line because it has an argument.  Otherwise it would be at the
+  end of a long usage list.
+*/
+  printf ( GTXT (
+    "Usage: gprofng display src [OPTION(S)] TARGET-OBJECT\n"));
+
+  printf ( GTXT (
+    "\n"
+    "Display the source code listing, or source code interleaved with disassembly code,\n"
+    "as extracted from the target object (an executable, shared object, object file, or\n"
+    "a Java .class file).\n"
+    "\n"
+    "Options:\n"
+    "\n"
+    " --version           print the version number and exit.\n"
+    " --help              print usage information and exit.\n"
+    " --verbose {on|off}  enable (on) or disable (off) verbose mode; the default is \"off\".\n"
+    "\n"
+    " -func                   list all the functions from the given object.\n"
+    "\n"
+    " -source item tag    show the source code for item; the tag is used to\n"
+    "                     differentiate in case of multiple occurences with\n"
+    "                     the same name; the combination of \"all -1\" selects\n"
+    "                     all the functions in the object; the default is\n"
+    "                     \"-source all -1\".\n"
+    "\n"
+    " -disasm item tag        show the source code, interleaved with the disassembled\n"
+    "                         instructions; the same definitions for item and tag apply.\n"
+    "\n"
+    " -outfile <filename>     write results to file <filename>; a dash (-) writes to\n"
+    "                         stdout; this is also the default; note that this only\n"
+    "                         affects options included to the right of this option.\n"
+    "\n"
+   "Documentation:\n"
+    "\n"
+    "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
+    "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
+    "should give you access to this document.\n"
+    "\n"
+    "See also:\n"
+    "\n"
+    "gprofng(1), gp-archive(1), gp-collect-app(1), gp-display-html(1), gp-display-text(1)\n"));
+/*
+  printf (GTXT ("Usage: %s [OPTION] a.out/.so/.o/.class\n\n"), whoami);
+  printf (GTXT ("    -func                     List all the functions from the given object\n"
+               "    -source, -src item tag    Show the annotated source for the listed item\n"
+               "    -disasm item tag          Include the disassembly in the listing\n"
+               "    -V                        Print the current release version of er_src\n"
+               "    -cc, -scc, -dcc com_spec  Define the compiler commentary classes to show\n"
+               "    -outfile filename         Open filename for output\n"));
+*/
+  exit (0);
+}
+
+void
+er_src::start (int argc, char *argv[])
+{
+  dbevindex = dbeSession->createView (0, -1);
+  dbev = dbeSession->getView (dbevindex);
+
+  // get options
+  check_args (argc, argv);
+  run_args (argc, argv);
+  if (out_file != stdout)
+    fclose (out_file);
+}
+
+FILE *
+er_src::set_outfile (char *cmd, FILE *&set_file)
+{
+  FILE *new_file;
+  if (!strcasecmp (cmd, "-"))
+    {
+      new_file = stdout;
+      out_fname = "<stdout>";
+    }
+  else
+    {
+      char *cmdpath;
+      char *fname = strstr (cmd, "~/");
+      // Handle ~ in file names
+      char *home = getenv ("HOME");
+      if (fname != NULL && home != NULL)
+       cmdpath = dbe_sprintf ("%s/%s", home, fname + 2);
+      else if ((fname = strstr (cmd, "~")) != NULL && home != NULL)
+       cmdpath = dbe_sprintf ("/home/%s", fname + 1);
+      else
+       cmdpath = strdup (cmd);
+      new_file = fopen (cmdpath, "w");
+      if (new_file == NULL)
+       {
+         fprintf (stderr, GTXT ("Unable to open file: %s"), cmdpath);
+         free (cmdpath);
+         return NULL;
+       }
+      out_fname = cmdpath;
+    }
+  if (set_file && (set_file != stdout))
+    fclose (set_file);
+
+  set_file = new_file;
+  return set_file;
+}
+
+void
+er_src::proc_cmd (CmdType cmd_type, bool first, char *arg1,
+                 const char *arg2, const char *arg3)
+{
+  Cmd_status status;
+  Module *module;
+  Function *fitem;
+  int mindex, findex;
+  switch (cmd_type)
+    {
+    case SOURCE:
+      dbev->set_view_mode (VMODE_USER);
+      print_anno_file (arg1, arg2, arg3, false,
+                      stdout, stdin, out_file, dbev, false);
+      break;
+    case DISASM:
+      dbev->set_view_mode (VMODE_MACHINE);
+      print_header (first, GTXT ("Annotated disassembly\n"));
+      print_anno_file (arg1, arg2, arg3, true,
+                      stdout, stdin, out_file, dbev, false);
+      break;
+    case OUTFILE:
+      if (arg1)
+       set_outfile (arg1, out_file);
+      break;
+    case FUNCS:
+      print_header (false, GTXT ("Function list\n"));
+      fprintf (out_file, GTXT ("Functions sorted in lexicographic order\n"));
+      fprintf (out_file, GTXT ("\nLoad Object: %s\n\n"), lo->get_name ());
+      if (lo->wsize == W32)
+       fprintf (out_file, GTXT ("    Address     Size        Name\n\n"));
+      else
+       fprintf (out_file, GTXT ("    Address                     Size        Name\n\n"));
+
+      Vec_loop (Module*, lo->seg_modules, mindex, module)
+      {
+       module->functions->sort (FuncNameCmp);
+       const char *fmt = (lo->wsize == W32) ?
+               GTXT ("  0x%08llx  %8lld      %s\n") :
+               GTXT ("  0x%016llx  %16lld      %s\n");
+       Vec_loop (Function*, module->functions, findex, fitem)
+       {
+         fprintf (out_file, fmt,
+                  (ull_t) fitem->img_offset,
+                  (ull_t) fitem->size,
+                  fitem->get_name ());
+       }
+      }
+      break;
+    case DUMPFUNC:
+      lo->functions->sort (FuncAddrCmp);
+      print_header (first, GTXT ("Dump functions\n"));
+      lo->dump_functions (out_file);
+      first = false;
+      break;
+    case SCOMPCOM:
+      status = dbev->proc_compcom (arg1, true, false);
+      if (status != CMD_OK)
+       fprintf (stderr, GTXT ("Error: %s"), Command::get_err_string (status));
+      break;
+    case DCOMPCOM:
+      status = dbev->proc_compcom (arg1, false, false);
+      if (status != CMD_OK)
+       fprintf (stderr, GTXT ("Error: %s"), Command::get_err_string (status));
+      break;
+    case COMPCOM:
+      status = dbev->proc_compcom (arg1, true, false);
+      if (status != CMD_OK)
+       fprintf (stderr, GTXT ("Error: %s: %s"), Command::get_err_string (status), arg1);
+      status = dbev->proc_compcom (arg1, false, false);
+      if (status != CMD_OK)
+       fprintf (stderr, GTXT ("Error: %s: %s"), Command::get_err_string (status), arg1);
+      break;
+    case HELP:
+      usage ();
+      break;
+    case VERSION_cmd:
+      if (out_file != stdout)
+// Ruud
+       Application::print_version_info ();
+/*
+       fprintf (out_file, "GNU %s version %s\n", get_basename (prog_name), VERSION);
+*/
+      break;
+    default:
+      fprintf (stderr, GTXT ("Invalid option"));
+      break;
+    }
+}
+
+void
+er_src::run_args (int argc, char *argv[])
+{
+  CmdType cmd_type;
+  int arg_count, cparam;
+  char *arg;
+  char *arg1;
+  const char *arg2;
+  bool first = true;
+  bool space;
+  Module *module;
+  int mindex;
+
+  for (int i = 1; i < argc; i++)
+    {
+      if (*argv[i] != '-')
+       {
+         if (!multiple)
+           { // er_src -V exe
+             space = false;
+             dbev->set_view_mode (VMODE_USER);
+             print_header (first, GTXT ("Annotated source\n"));
+             Vec_loop (Module*, lo->seg_modules, mindex, module)
+             {
+               if ((module->flags & MOD_FLAG_UNKNOWN) != 0 ||
+                   module->lang_code == Sp_lang_unknown)
+                 continue;
+               if (space)
+                 fprintf (out_file, "\n");
+               print_anno_file (module->file_name, "1", NULL, false,
+                                stdout, stdin, out_file, dbev, false);
+               space = true;
+             }
+           }
+         break;
+       }
+      if (strncmp (argv[i], NTXT ("--whoami="), 9) == 0)
+       {
+         whoami = argv[i] + 9;
+         continue;
+       }
+      switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam))
+       {
+       case SOURCE:
+       case DISASM:
+         {
+           i += arg_count;
+           multiple++;
+           if (i >= argc || argv[i] == NULL ||
+               (*(argv[i]) == '-' && atoi (argv[i]) != -1) || i + 1 == argc)
+             {
+               i--;
+               arg = argv[i];
+               arg2 = "1";
+             }
+           else
+             {
+               arg = argv[i - 1];
+               if (*(argv[i]) == '-' && atoi (argv[i]) == -1 &&
+                   streq (arg, NTXT ("all")))
+                 {
+                   space = false;
+                   if (cmd_type == SOURCE)
+                     print_header (first, GTXT ("Annotated source\n"));
+                   else
+                     print_header (first, GTXT ("Annotated disassembly\n"));
+                   Vec_loop (Module*, lo->seg_modules, mindex, module)
+                   {
+                     if ((module->flags & MOD_FLAG_UNKNOWN) != 0 ||
+                         module->lang_code == Sp_lang_unknown)
+                       continue;
+                     if (space)
+                       fprintf (out_file, "\n");
+                     proc_cmd (cmd_type, first, module->file_name, "1");
+                     space = true;
+                   }
+                   first = false;
+                   break;
+                 }
+               arg2 = argv[i];
+             }
+           char *fcontext = NULL;
+           arg1 = parse_fname (arg, &fcontext);
+           if (arg1 == NULL)
+             {
+               fprintf (stderr, GTXT ("Error: Invalid function/file setting: %s\n"), arg1);
+               free (fcontext);
+               break;
+             }
+           proc_cmd (cmd_type, first, arg1, arg2, fcontext);
+           free (arg1);
+           free (fcontext);
+           first = false;
+           break;
+         }
+       case OUTFILE:
+       case FUNCS:
+       case DUMPFUNC:
+       case COMPCOM:
+       case SCOMPCOM:
+       case DCOMPCOM:
+       case VERSION_cmd:
+       case HELP:
+         proc_cmd (cmd_type, first, (arg_count > 0) ? argv[i + 1] : NULL,
+                   (arg_count > 1) ? argv[i + 2] : NULL);
+         i += arg_count;
+         break;
+       default:
+         if (streq (argv[i] + 1, NTXT ("all")) || streq (argv[i] + 1, NTXT ("dall")))
+           {
+             first = false;
+             multiple++;
+             if (streq (argv[i] + 1, NTXT ("all")))
+               proc_cmd (FUNCS, first, NULL, NULL);
+             else
+               proc_cmd (DUMPFUNC, first, NULL, NULL);
+             space = false;
+             print_header (first, GTXT ("Annotated source\n"));
+             Vec_loop (Module*, lo->seg_modules, mindex, module)
+             {
+               if ((module->flags & MOD_FLAG_UNKNOWN) != 0 ||
+                   module->lang_code == Sp_lang_unknown)
+                 continue;
+               if (space)
+                 fprintf (out_file, "\n");
+               proc_cmd (SOURCE, first, module->file_name, "1");
+               space = true;
+             }
+             print_header (first, GTXT ("Annotated disassembly\n"));
+             Vec_loop (Module*, lo->seg_modules, mindex, module)
+             {
+               if ((module->flags & MOD_FLAG_UNKNOWN) != 0 ||
+                   module->lang_code == Sp_lang_unknown)
+                 continue;
+               if (space)
+                 fprintf (out_file, "\n");
+               proc_cmd (DISASM, first, module->file_name, "1");
+               space = true;
+             }
+           }
+         else
+           {
+             proc_cmd (cmd_type, first, (arg_count > 0) ? argv[i + 1] : NULL,
+                       (arg_count > 1) ? argv[i + 2] : NULL);
+             i += arg_count;
+             break;
+           }
+       }
+    }
+}
+
+int
+er_src::check_args (int argc, char *argv[])
+{
+  CmdType cmd_type = UNKNOWN_CMD;
+  int arg_count, cparam;
+  int i;
+  char *exe;
+  bool first = true;
+  if (argc == 1)
+    usage ();
+
+  // If any comments from the .rc files, log them to stderr
+  Emsg * rcmsg = fetch_comments ();
+  while (rcmsg != NULL)
+    {
+      fprintf (stderr, "%s: %s\n", prog_name, rcmsg->get_msg ());
+      rcmsg = rcmsg->next;
+    }
+
+  // Parsing the command line
+  opterr = 0;
+  exe = NULL;
+  for (i = 1; i < argc; i++)
+    {
+      if (*argv[i] != '-')
+       {
+         exe = argv[i];
+         if (i == 1)
+           { // er_src exe ?
+             if (!exe)
+               usage ();
+             if (argc == 3) // er_src exe file
+               usage ();
+           }
+         else if (v_opt && !multiple && !exe && !str_compcom) // just er_src -V
+             exit (0);
+         if (argc < i + 1 || argc > i + 3)
+           usage ();
+         i++;
+         if (argc > i)
+           usage ();
+         open (exe);
+         return i;
+       }
+      switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam))
+       {
+       case WHOAMI:
+         whoami = argv[i] + 1 + cparam;
+         break;
+       case HELP:
+         i += arg_count;
+         multiple++;
+         usage ();
+         break;
+       case VERSION_cmd:
+         if (first)
+           {
+// Ruud
+             Application::print_version_info ();
+/*
+             printf ("GNU %s version %s\n", get_basename (prog_name), VERSION);
+*/
+             v_opt = true;
+             first = false;
+           }
+         break;
+       case SOURCE:
+       case DISASM:
+         i += arg_count;
+         multiple++;
+         isDisasm = true;
+         if (i >= argc || argv[i] == NULL ||
+             (*(argv[i]) == '-' && atoi (argv[i]) != -1) || (i + 1 == argc))
+           i--;
+         break;
+       case DUMPFUNC:
+         i += arg_count;
+         multiple++;
+         break;
+       case FUNCS:
+         i += arg_count;
+         multiple++;
+         break;
+       case OUTFILE:
+       case COMPCOM:
+       case SCOMPCOM:
+       case DCOMPCOM:
+         i += arg_count;
+         break;
+       default:
+         if (!(streq (argv[i] + 1, NTXT ("all")) ||
+               streq (argv[i] + 1, NTXT ("dall"))))
+           {
+             fprintf (stderr, "Error: invalid option: `%s'\n", argv[i]);
+             exit (1);
+           }
+       }
+    }
+  if (!exe && !(argc == 2 && cmd_type == VERSION_cmd))
+    usage ();
+  return i;
+}
+
+void
+er_src::checkJavaClass (char* exe)
+{
+  unsigned char cf_buf[4];
+  unsigned int magic_number;
+  int fd = ::open (exe, O_RDONLY | O_LARGEFILE);
+  if (fd == -1)
+    return;
+  if (sizeof (cf_buf) == read_from_file (fd, cf_buf, sizeof (cf_buf)))
+    {
+      magic_number = cf_buf[0] << 24;
+      magic_number |= cf_buf[1] << 16;
+      magic_number |= cf_buf[2] << 8;
+      magic_number |= cf_buf[3];
+      if (magic_number == 0xcafebabe)
+       obj_type = OT_JAVA_CLASS;
+    }
+  close (fd);
+}
+
+void
+er_src::print_header (bool first, const char* text)
+{
+  if (!first)
+    fprintf (out_file, "\n");
+  if (multiple > 1)
+    {
+      fprintf (out_file, NTXT ("%s"), text);
+      fprintf (out_file, "---------------------------------------\n");
+    }
+}
+
+void
+er_src::dump_annotated (char *name, char *sel, char *src, DbeView *dbevr,
+                       bool is_dis, bool first)
+{
+  Module *module;
+  bool space;
+  int mindex;
+  print_header (first, (is_dis) ? ((is_java_class ()) ?
+                                  GTXT ("Annotated bytecode\n") :
+                                  GTXT ("Annotated disassembly\n")) :
+               GTXT ("Annotated source\n"));
+  if (!name)
+    {
+      space = false;
+      Vec_loop (Module*, lo->seg_modules, mindex, module)
+      {
+       if ((module->flags & MOD_FLAG_UNKNOWN) != 0 ||
+           (!is_dis && module->lang_code == Sp_lang_unknown))
+         continue;
+       if (space)
+         fprintf (out_file, "\n");
+       print_anno_file (module->file_name, sel, src, is_dis,
+                        stdout, stdin, out_file, dbevr, false);
+       space = true;
+      }
+    }
+  else
+    print_anno_file (name, sel, src, is_dis, stdout, stdin, out_file, dbevr, false);
+}
+
+static bool
+isFatal (bool isDisasm, LoadObject::Arch_status status)
+{
+  if (isDisasm)
+    {
+      switch (status)
+       {
+         // non-fatal errors for disassembly
+       case LoadObject::ARCHIVE_BAD_STABS:
+       case LoadObject::ARCHIVE_NO_STABS:
+         return false;
+       default:
+         return true;
+       }
+    }
+  return true;
+}
+
+void
+er_src::open (char *exe)
+{
+  LoadObject::Arch_status status;
+  char *errstr;
+  Module *module;
+  Vector<Histable*> *module_lst;
+
+  // Construct the Segment structure
+  char *path = strdup (exe);
+  lo = dbeSession->createLoadObject (path);
+  if (NULL == lo->dbeFile->find_file (lo->dbeFile->get_name ()))
+    {
+      fprintf (stderr, GTXT ("%s: Error: unable to open file %s\n"), prog_name, lo->dbeFile->get_name ());
+      exit (1);
+    }
+  checkJavaClass (exe);
+
+  if (is_java_class ())
+    {
+      lo->type = LoadObject::SEG_TEXT;
+      lo->set_platform (Java, Wnone);
+      lo->id = (uint64_t) - 1; // see AnalyzerSession::ask_which for details
+      module = dbeSession->createClassFile (dbe_strdup (exe));
+      module->loadobject = lo;
+      lo->seg_modules->append (module);
+      module->dbeFile->set_location (exe);
+      if (module->readFile () != module->AE_OK)
+       {
+         Emsg *emsg = module->get_error ();
+         if (emsg)
+           {
+             fprintf (stderr, GTXT ("%s: Error: %s\n"), prog_name, emsg->get_msg ());
+             return;
+           }
+         fprintf (stderr, GTXT ("%s: Error: Could not read class file `%s'\n"), prog_name, exe);
+         return;
+       }
+      status = lo->sync_read_stabs ();
+      if (status != LoadObject::ARCHIVE_SUCCESS)
+       {
+         if (status == LoadObject::ARCHIVE_ERR_OPEN)
+           {
+             fprintf (stderr, GTXT ("%s: Error: Could not read class file `%s'\n"), prog_name, exe);
+             return;
+           }
+         else
+           {
+             if (isDisasm)
+               if (status == LoadObject::ARCHIVE_NO_STABS)
+                 {
+                   fprintf (stderr, GTXT ("%s: Error: `%s' is interface; disassembly annotation not available\n"), prog_name, exe);
+                   return;
+                 }
+           }
+       }
+    }
+  else
+    {
+      status = lo->sync_read_stabs ();
+      if (status != LoadObject::ARCHIVE_SUCCESS)
+       {
+         errstr = lo->status_str (status);
+         if (errstr)
+           {
+             fprintf (stderr, "%s: %s\n", prog_name, errstr);
+             free (errstr);
+           }
+         if (isFatal (isDisasm, status))
+           return;
+       }
+      obj_type = OT_EXE_ELF;
+
+      // if .o file, then set file as the exe name
+      if (lo->is_relocatable ())
+       {
+         // find the module, if we can
+         module_lst = new Vector<Histable*>;
+         module = dbeSession->map_NametoModule (path, module_lst, 0);
+         if (module == NULL)
+           // Create a module with the right name
+           module = dbeSession->createModule (lo, path);
+       }
+    }
+}
diff --git a/gprofng/src/gp-display-text.cc b/gprofng/src/gp-display-text.cc
new file mode 100644 (file)
index 0000000..7183553
--- /dev/null
@@ -0,0 +1,2834 @@
+/* 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 <unistd.h>     // isatty
+
+#include "gp-print.h"
+#include "ipcio.h"
+#include "Command.h"
+#include "Dbe.h"
+#include "DbeApplication.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "Emsg.h"
+#include "DbeView.h"
+#include "DataObject.h"
+#include "Function.h"
+#include "Hist_data.h"
+#include "PathTree.h"
+#include "LoadObject.h"
+#include "Function.h"
+#include "FilterSet.h"
+#include "Filter.h"
+#include "MetricList.h"
+#include "MemorySpace.h"
+#include "Module.h"
+#include "util.h"
+#include "i18n.h"
+#include "StringBuilder.h"
+#include "debug.h"
+#include "UserLabel.h"
+
+static char *exe_name;
+static char **new_argv;
+
+void
+reexec ()
+{
+  if (dbeSession != NULL)
+    dbeSession->unlink_tmp_files ();
+  execv (exe_name, new_argv);
+}
+
+/**
+ * Run application under enhance if the following requirements are satisfied:
+ * 1. Environment variable GPROFNG_ENHANCE is not set to "no"
+ * 2. Standard input is terminal
+ * 3. Standard output is terminal
+ * 4. /bin/enhance exists and can work on this system
+ */
+static void
+reexec_enhance (int argc, char *argv[])
+{
+  char *gp_enhance = getenv ("GPROFNG_ENHANCE");
+  if (NULL != gp_enhance && 0 == strcasecmp (gp_enhance, "no"))
+    return; // Do not enhance
+  // Verify that input and output are tty
+  if (!isatty (fileno (stdin)))     // stdin is not a terminal
+    return; // Do not enhance
+  if (!isatty (fileno (stdout)))    // stdout is not a terminal
+    return; // Do not enhance
+  char *enhance_name = NTXT ("/bin/enhance");
+  struct stat sbuf;
+  int res = stat (enhance_name, &sbuf); // Check if enhance exists
+  if (res == 0)
+    res = system (NTXT ("/bin/enhance /bin/true")); // Check if enhance can work
+  if (res != 0)
+    {
+      fflush (stdout);
+      printf (GTXT ("Warning: History and command editing is not supported on this system.\n"));
+      fflush (stdout);
+      return;
+    }
+  else
+    {
+      printf (GTXT ("Note: History and command editing is supported on this system.\n"));
+      fflush (stdout);
+    }
+  char **nargv = new char*[argc + 2];
+  for (int i = 0; i < argc; i++)
+    nargv[i + 1] = argv[i];
+  nargv[0] = enhance_name;
+  nargv[argc + 1] = NULL;
+  putenv (NTXT ("GPROFNG_ENHANCE=no")); // prevent recursion
+  execv (enhance_name, nargv);
+  // execv failed. Continue to run the program
+  delete[] nargv;
+}
+
+int
+main (int argc, char *argv[])
+{
+  er_print *erprint;
+  int ind = 1;
+  if (argc > ind && *argv[ind] == '-')
+    {
+      int arg_count, cparam;
+      if (Command::get_command (argv[ind] + 1, arg_count, cparam) == WHOAMI)
+       ind = ind + 1 + arg_count;
+    }
+  if (argc > ind && argv[ind] != NULL && *argv[ind] != '-')
+    reexec_enhance (argc, argv);
+
+  // Save argv for reexec())
+  exe_name = argv[0];
+  new_argv = argv;
+
+  if (argc > ind && argv[ind] != NULL && strcmp (argv[ind], "-IPC") == 0)
+    {
+      putenv (NTXT ("LC_NUMERIC=C")); // Use non-localized numeric data in IPC packets
+      erprint = new er_print (argc, argv);
+      theDbeApplication->rdtMode = false;
+      ipc_mainLoop (argc, argv);
+    }
+  else
+    {
+      erprint = new er_print (argc, argv);
+      erprint->start (argc, argv);
+    }
+
+  dbeSession->unlink_tmp_files ();
+  if (DUMP_CALL_STACK)
+    {
+      extern long total_calls_add_stack, total_stacks, total_nodes, call_stack_size[201];
+      fprintf (stderr, NTXT ("total_calls_add_stack=%lld\ntotal_stacks=%lld\ntotal_nodes=%lld\n"),
+              (long long) total_calls_add_stack, (long long) total_stacks, (long long) total_nodes);
+      for (int i = 0; i < 201; i++)
+       if (call_stack_size[i] != 0)
+           fprintf (stderr, NTXT ("   call_stack_size[%d] = %6lld\n"), i,
+                    (long long) call_stack_size[i]);
+    }
+#if defined(DEBUG)
+  delete erprint;
+#endif
+  return 0;
+}
+
+er_print::er_print (int argc, char *argv[])
+: DbeApplication (argc, argv)
+{
+  out_fname = GTXT ("<stdout>");
+  inp_file = stdin;
+  out_file = stdout;
+  dis_file = stdout;
+  cov_string = NULL;
+  limit = 0;
+  cstack = new Vector<Histable*>();
+  was_QQUIT = false;
+}
+
+er_print::~er_print ()
+{
+  free (cov_string);
+  delete cstack;
+  if (inp_file != stdin)
+    fclose (inp_file);
+}
+
+void
+er_print::start (int argc, char *argv[])
+{
+  Vector<String> *res = theDbeApplication->initApplication (NULL, NULL, NULL);
+  res->destroy ();
+  delete res;
+
+  // Create a view on the session
+  dbevindex = dbeSession->createView (0, -1);
+  dbev = dbeSession->getView (dbevindex);
+  limit = dbev->get_limit ();
+  (void) check_args (argc, argv);
+  int ngood = dbeSession->ngoodexps ();
+  if (ngood == 0)
+    {
+      fprintf (stderr, GTXT ("No valid experiments loaded; exiting\n"));
+      return;
+    }
+  dbeDetectLoadMachineModel (dbevindex);
+  run (argc, argv);
+}
+
+bool
+er_print::free_memory_before_exit ()
+{
+  return was_QQUIT;
+}
+
+void
+er_print::usage ()
+{
+
+/*
+  Ruud - Isolate this line because it has an argument.  Otherwise it would be at the
+  end of the long option list.
+*/
+  printf ( GTXT (
+    "Usage: gprofng display text [OPTION(S)] [COMMAND(S)] [-script <script_file>] EXPERIMENT(S)\n"));
+
+  printf ( GTXT (
+    "\n"
+    "Print a plain text version of the various displays supported by gprofng.\n"
+    "\n"
+    "Options:\n"
+    "\n"
+    " --version           print the version number and exit.\n"
+    " --help              print usage information and exit.\n"
+    " --verbose {on|off}  enable (on) or disable (off) verbose mode; the default is \"off\".\n"
+    "\n"
+    " -script <script-file>  execute the commands stored in the script file;\n"
+    "                        this feature may be combined with commands specified\n"
+    "                        at the command line.\n"
+    "\n"
+    "Commands:\n"
+    "\n"
+    "This tool supports a rich set of commands to control the display of the\n"
+    "data; instead of, or in addition to, including these commands in a script\n"
+    "file, it is also allowed to include such commands at the command line;\n"
+    "in this case, the commands need to be prepended with the \"-\" symbol; the\n"
+    "commands are processed and interpreted left from right, so the order matters;\n"
+    "The gprofng manual documents the commands that are supported.\n"
+    "\n"
+    "If this tool is invoked without options, commands, or a script file, it starts\n"
+    "in interpreter mode. The user can then issue the commands interactively; the\n"
+    "session is terminated with the \"exit\" command in the interpreter.\n"
+    "\n"
+    "Documentation:\n"
+    "\n"
+    "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
+    "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
+    "should give you access to this document.\n"
+    "\n"
+    "See also:\n"
+    "\n"
+    "gprofng(1), gp-archive(1), gp-collect-app(1), gp-display-html(1), gp-display-src(1)\n"));
+}
+
+int // returns count of experiments read
+er_print::check_args (int argc, char *argv[])
+{
+  CmdType cmd_type;
+  int arg_count;
+  int cparam;
+  int exp_no;
+  error_msg = NULL;
+
+  Emsg *rcmsg = fetch_comments ();
+  while (rcmsg != NULL)
+    {
+      fprintf (stderr, NTXT ("%s: %s\n"), prog_name, rcmsg->get_msg ());
+      rcmsg = rcmsg->next;
+    }
+  delete_comments ();
+
+  // Set up the list of experiments to add after checking the args
+  Vector<Vector<char*>*> *exp_list = new Vector<Vector<char*>*>();
+
+  // Prescan the command line arguments, processing only a few
+  for (int i = 1; i < argc; i++)
+    {
+      if (*argv[i] != '-')
+       {
+         // we're at the end -- get the list of experiments
+         //  Build the list of experiments, and set the searchpath
+         Vector<char*> *list = dbeSession->get_group_or_expt (argv[i]);
+         if (list->size () > 0)
+           {
+             for (int j = 0, list_sz = list->size (); j < list_sz; j++)
+               {
+                 char *path = list->fetch (j);
+                 if (strlen (path) == 0 || strcmp (path, NTXT ("\\")) == 0)
+                   continue;
+                 char *p = strrchr (path, '/');
+                 if (p)
+                   {
+                     // there's a directory in front of the name; add it to search path
+                     *p = '\0';
+                     dbeSession->set_search_path (path, false);
+                   }
+               }
+             list->destroy ();
+             list->append (dbe_strdup (argv[i]));
+             exp_list->append (list);
+           }
+         else
+           delete list;
+         continue;
+       }
+
+      // Not at the end yet, treat the next argument as a command
+      switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam))
+       {
+       case WHOAMI:
+         whoami = argv[i] + 1 + cparam;
+         break;
+       case HELP:
+         if (i + 1 + arg_count == argc)
+           {
+             usage();
+             exit (0);
+           }
+         break;
+       case HHELP:
+         Command::print_help (whoami, true, false, stdout);
+         fprintf (stdout, "\n");
+         indxo_list (false, stdout);
+         fprintf (stdout, "\n");
+         mo_list (false, stdout);
+         if (!getenv ("_BUILDING_MANPAGE"))
+           fprintf (stdout, GTXT ("\nSee gprofng(1) for more details\n"));
+         exit (0);
+       case ADD_EXP:
+       case DROP_EXP:
+       case OPEN_EXP:
+         printf (GTXT ("Error: command %s can not appear on the command line\n"), argv[i]);
+         exit (2);
+       case VERSION_cmd:
+         Application::print_version_info ();
+         exit (0);
+       case AMBIGUOUS_CMD:
+         fprintf (stderr, GTXT ("Error: Ambiguous command: %s\n"), argv[i]);
+         exit (2);
+       case UNKNOWN_CMD:
+         fprintf (stderr, GTXT ("Error: Invalid command: %s\n"), argv[i]);
+         exit (2);
+         // it's a plausible argument; see if we process now or later
+       case SOURCE:
+       case DISASM:
+       case CSINGLE:
+       case CPREPEND:
+       case CAPPEND:
+       case FSINGLE:
+       case SAMPLE_DETAIL:
+       case STATISTICS:
+       case HEADER:
+         //skip the arguments to that command
+         i += arg_count;
+         if (i >= argc || end_command (argv[i]))
+           i--;
+         break;
+       case PRINTMODE:
+       case INDXOBJDEF:
+       case ADDPATH:
+       case SETPATH:
+       case PATHMAP:
+       case OBJECT_SHOW:
+       case OBJECT_HIDE:
+       case OBJECT_API:
+       case OBJECTS_DEFAULT:
+       case EN_DESC:
+         // these are processed in the initial pass over the arguments
+         proc_cmd (cmd_type, cparam, (arg_count > 0) ? argv[i + 1] : NULL,
+                   (arg_count > 1) ? argv[i + 2] : NULL,
+                   (arg_count > 2) ? argv[i + 3] : NULL,
+                   (arg_count > 3) ? argv[i + 4] : NULL);
+         i += arg_count;
+         break;
+       default:
+         // any others, we skip for now
+         i += arg_count;
+         break;
+       }
+    }
+
+  // Make sure some experiments were specified
+  exp_no = exp_list->size ();
+  if (exp_no == 0)
+    { // no experiment name
+      fprintf (stderr, GTXT ("%s: Missing experiment directory (use the --help option to get a usage overview)\n"), whoami);
+      exit (1);
+    }
+
+  // add the experiments to the session
+  char *errstr = dbeOpenExperimentList (0, exp_list, false);
+  for (long i = 0; i < exp_list->size (); i++)
+    {
+      Vector<char*>* p = exp_list->get (i);
+      Destroy (p);
+    }
+  delete exp_list;
+  if (errstr != NULL)
+    {
+      fprintf (stderr, NTXT ("%s"), errstr);
+      free (errstr);
+    }
+
+  return exp_no;
+}
+
+int
+er_print::is_valid_seg_name (char *lo_name, int prev)
+{
+  // prev is the loadobject segment index that was last returned
+  // search starts following that loadobject
+  int index;
+  LoadObject *lo;
+  char *p_lo_name = lo_name;
+  char *name = NULL;
+
+  // strip angle brackets from all but <Unknown> and <Total>
+  if (strcmp (lo_name, "<Unknown>") && strcmp (lo_name, "<Total>"))
+    {
+      if (*lo_name == '<')
+       {
+         name = dbe_strdup (lo_name + 1);
+         p_lo_name = name;
+         char *p = strchr (name, '>');
+         if (p)
+           *p = '\0';
+       }
+    }
+
+  // get the load object list from the session
+  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+  Vec_loop (LoadObject*, lobjs, index, lo)
+  {
+    if (prev > 0)
+      {
+       if (lo->seg_idx == prev)    // this is where we left off
+         prev = -1;
+       continue;
+      }
+
+    // does this one match?
+    if (cmp_seg_name (lo->get_pathname (), p_lo_name))
+      {
+       delete lobjs;
+       free (name);
+       size_t len = strlen (lo_name);
+       if ((len > 7 && streq (lo_name + len - 7, NTXT (".class>"))) ||
+           (len > 6 && streq (lo_name + len - 6, NTXT (".class"))))
+         {
+           fprintf (stderr, GTXT ("Error: Java class `%s' is not selectable\n"), lo_name);
+           return -1;
+         }
+       return lo->seg_idx;
+      }
+  }
+  delete lobjs;
+  free (name);
+  return -1;
+}
+
+int
+er_print::cmp_seg_name (char *full_name, char *lo_name)
+{
+  char *cmp_name;
+  if (!strchr (lo_name, '/') && (cmp_name = strrchr (full_name, '/')))
+    cmp_name++; // basename
+  else
+    cmp_name = full_name; // full path name
+  return !strcmp (lo_name, cmp_name);
+}
+
+// processing object_select
+//     Note that this does not affect the strings in Settings,
+//     unlike object_show, object_hide, and object_api
+int
+er_print::process_object_select (char *names)
+{
+  int index;
+  LoadObject *lo;
+  int no_lobj = 0;
+  bool got_err = false;
+  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+  if ((names == NULL) || !strcasecmp (names, Command::ALL_CMD))
+    { // full coverage
+      Vec_loop (LoadObject*, lobjs, index, lo)
+      {
+       dbev->set_lo_expand (lo->seg_idx, LIBEX_SHOW);
+      }
+    }
+  else
+    { // parsing coverage
+      // first, hide functions from all loadobjects
+      // except the java ones
+      Vec_loop (LoadObject*, lobjs, index, lo)
+      {
+       char *lo_name = lo->get_name ();
+       if (lo_name != NULL)
+         {
+           size_t len = strlen (lo_name);
+           if ((len > 7 && streq (lo_name + len - 7, NTXT (".class>"))) ||
+               (len > 6 && streq (lo_name + len - 6, NTXT (".class"))))
+             continue;
+         }
+       dbev->set_lo_expand (lo->seg_idx, LIBEX_HIDE);
+      }
+
+      Vector <char *> *tokens = split_str (names, ',');
+      for (long j = 0, sz = VecSize (tokens); j < sz; j++)
+       {
+         // loop over the provided names
+         char *lo_name = tokens->get (j);
+         int seg_idx = -1;
+         seg_idx = is_valid_seg_name (lo_name, seg_idx);
+         while (seg_idx != -1)
+           {
+             dbev->set_lo_expand (seg_idx, LIBEX_SHOW);
+             no_lobj++;
+             seg_idx = is_valid_seg_name (lo_name, seg_idx);
+           }
+         if (no_lobj == 0)
+           {
+             got_err = true;
+             fprintf (stderr, GTXT ("Error: Unknown load object: `%s'\n"), lo_name);
+           }
+         free (lo_name);
+       }
+      delete tokens;
+    }
+
+  if (!got_err)
+    { // good coverage string
+      free (cov_string);
+      cov_string = strdup (names);
+    }
+  else
+    { // bad, restore original coverage
+      no_lobj = -1;
+      process_object_select (cov_string);
+    }
+  delete lobjs;
+  return no_lobj;
+}
+
+int
+er_print::set_libexpand (char *cov, enum LibExpand expand)
+{
+  bool changed = dbev->set_libexpand (cov, expand);
+  if (changed == true)
+    dbev->update_lo_expands ();
+  return 0;
+}
+
+int
+er_print::set_libdefaults ()
+{
+  dbev->set_libdefaults ();
+  return 0;
+}
+
+bool
+er_print::end_command (char *cmd)
+{
+  if (cmd == NULL || *cmd == '-')
+    return true;
+  size_t len = strlen (cmd);
+  if (cmd[len - 1] == '/')
+    len--;
+  if ((len > 3 && !strncmp (&cmd[len - 3], NTXT (".er"), 3)) ||
+      (len > 4 && !strncmp (&cmd[len - 4], NTXT (".erg"), 4)))
+    return true;
+  return false;
+}
+
+// Now actually start processing the arguments
+void
+er_print::run (int argc, char *argv[])
+{
+  CmdType cmd_type;
+  int arg_count, cparam, i;
+  bool got = false;
+  char *arg1, *arg2;
+  for (i = 1; i < argc; i++)
+    {
+      if (*argv[i] != '-') // open experiment pointer files
+       continue;
+      switch (cmd_type = Command::get_command (argv[i] + 1, arg_count, cparam))
+       {
+       case WHOAMI:
+         whoami = argv[i] + 1 + cparam;
+         break;
+       case SCRIPT:
+         got = true;
+         inp_file = fopen (argv[++i], "r");
+         if (inp_file == NULL)
+           {
+             fprintf (stderr, GTXT ("Error: Script file cannot be opened: %s\n"), argv[i]);
+             exit (3);
+           }
+         proc_script ();
+         break;
+       case STDIN:
+         got = true;
+         inp_file = stdin;
+         proc_script ();
+         break;
+       case SOURCE: // with option arg_count == 2
+       case DISASM:
+         got = true;
+         i += arg_count;
+         if ((i >= argc) || end_command (argv[i]))
+           {
+             i--;
+             arg1 = argv[i];
+             arg2 = NTXT ("");
+           }
+         else
+           {
+             arg1 = argv[i - 1];
+             arg2 = argv[i];
+           }
+         proc_cmd (cmd_type, cparam, arg1, arg2, NULL, NULL, true);
+         break;
+       case CSINGLE:
+       case CPREPEND:
+       case CAPPEND:
+       case FSINGLE:
+         got = true;
+         i += arg_count;
+         if ((i >= argc) || end_command (argv[i]))
+           {
+             i--;
+             proc_cmd (cmd_type, cparam, argv[i], NTXT ("1"));
+           }
+         else
+           proc_cmd (cmd_type, cparam, argv[i - 1], argv[i]);
+         break;
+       case SAMPLE_DETAIL: // with option arg_count == 1
+       case STATISTICS:
+       case HEADER:
+         got = true;
+         // now fall through to process the command
+       case COMPARE:
+         got = true;
+         i += arg_count;
+         if ((i >= argc) || end_command (argv[i]))
+           {
+             i--;
+             proc_cmd (cmd_type, cparam, NULL, NULL);
+           }
+         else
+           proc_cmd (cmd_type, cparam, argv[i], NULL);
+         break;
+       case PRINTMODE:
+       case INDXOBJDEF:
+       case ADDPATH:
+       case SETPATH:
+       case PATHMAP:
+       case OBJECT_SHOW:
+       case OBJECT_HIDE:
+       case OBJECT_API:
+       case OBJECTS_DEFAULT:
+       case EN_DESC:
+         got = true;
+         // these have been processed already
+         i += arg_count;
+         break;
+       case LIMIT:
+         got = true;
+         proc_cmd (cmd_type, cparam, (arg_count > 0) ? argv[i + 1] : NULL,
+                   (arg_count > 1) ? argv[i + 2] : NULL);
+         i += arg_count;
+         break;
+       default:
+         got = true;
+         proc_cmd (cmd_type, cparam, (arg_count > 0) ? argv[i + 1] : NULL,
+                   (arg_count > 1) ? argv[i + 2] : NULL);
+         i += arg_count;
+         break;
+       }
+    }
+  if (!got) // no command has been specified
+    proc_script ();
+}
+
+#define MAXARGS 20
+
+void
+er_print::proc_script ()
+{
+  CmdType cmd_type;
+  int arg_count, cparam;
+  char *cmd, *end_cmd;
+  char *script = NULL;
+  char *arglist[MAXARGS];
+  char *line = NULL;
+  int lineno = 0;
+  while (!feof (inp_file))
+    {
+      if (inp_file == stdin)
+       printf (NTXT ("(%s) "), get_basename (prog_name));
+      free (script);
+      script = read_line (inp_file);
+      if (script == NULL)
+       continue;
+      free (line);
+      line = dbe_strdup (script);
+      lineno++;
+      for (int i = 0; i < MAXARGS; i++)
+       arglist[i] = NULL;
+
+      // ensure it's terminated by a \n, and remove that character
+      strtok (script, NTXT ("\n"));
+
+      // extract the command
+      cmd = strtok (script, NTXT (" \t"));
+      if (cmd == NULL)
+       continue;
+      if (*cmd == '#')
+       {
+         fprintf (stderr, NTXT ("%s"), line);
+         continue;
+       }
+      if (*cmd == '\n')
+       continue;
+
+      char *remainder = strtok (NULL, NTXT ("\n"));
+      // now extract the arguments
+      int nargs = 0;
+      for (;;)
+       {
+         end_cmd = NULL;
+         if (nargs >= MAXARGS)
+           fprintf (stderr, GTXT ("Warning: more than %d arguments to %s command, line %d\n"),
+                    MAXARGS, cmd, lineno);
+         char *nextarg = strtok (remainder, NTXT ("\n"));
+         if ((nextarg == NULL) || (*nextarg == '#'))
+           // either the end of the line, or a comment indicator
+           break;
+         if (nargs >= MAXARGS)
+           {
+             parse_qstring (nextarg, &end_cmd);
+             nargs++;
+           }
+         else
+           arglist[nargs++] = parse_qstring (nextarg, &end_cmd);
+         remainder = end_cmd;
+         if (remainder == NULL)
+           break;
+         // skip any blanks or tabs to get to next argument
+         while (*remainder == ' ' || *remainder == '\t')
+           remainder++;
+       }
+
+      cmd_type = Command::get_command (cmd, arg_count, cparam);
+
+      // check for extra arguments
+      if (cmd_type != UNKNOWN_CMD && cmd_type != INDXOBJDEF && nargs > arg_count)
+       fprintf (stderr, GTXT ("Warning: extra arguments to %s command, line %d\n"),
+                cmd, lineno);
+      switch (cmd_type)
+       {
+       case SOURCE:
+       case DISASM:
+         // ignore any third parameter
+         // if there was, we have written a warning
+         proc_cmd (cmd_type, cparam, arglist[0], arglist[1], NULL, NULL,
+                   (inp_file != stdin));
+         break;
+       case QUIT:
+         free (script);
+         free (line);
+         exit (0);
+       case QQUIT:
+         was_QQUIT = true;
+         free (script);
+         free (line);
+         return;
+       case STDIN:
+         break;
+       case COMMENT:
+         fprintf (dis_file, NTXT ("%s"), line);
+         break;
+       case AMBIGUOUS_CMD:
+         fprintf (stderr, GTXT ("Error: Ambiguous command: %s\n"), cmd);
+         break;
+       case UNKNOWN_CMD:
+         if (*cmd != '\n')
+           fprintf (stderr, GTXT ("Error: Invalid command: %s\n"), cmd);
+         break;
+       default:
+         proc_cmd (cmd_type, cparam, arglist[0], arglist[1]);
+         break;
+       }
+    }
+  // free up the input line
+  free (script);
+  free (line);
+}
+
+void
+er_print::proc_cmd (CmdType cmd_type, int cparam,
+                   char *arg1, char *arg2, char *arg3, char *arg4, bool xdefault)
+{
+  er_print_common_display *cd;
+  FILE *ck_file, *save_file;
+  char *name;
+  int bgn_index, end_index, index;
+  Cmd_status status;
+  char *scratch, *scratch1;
+  switch (cmd_type)
+    {
+    case FUNCS:
+      print_func (Histable::FUNCTION, MODE_LIST,
+                 dbev->get_metric_list (MET_NORMAL), dbev->get_metric_list (MET_NORMAL));
+      break;
+    case FDETAIL:
+      print_func (Histable::FUNCTION, MODE_DETAIL,
+                 dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL));
+      break;
+    case FSINGLE:
+      print_func (Histable::FUNCTION, MODE_DETAIL,
+                 dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL),
+                 arg1, arg2);
+      break;
+    case HOTPCS:
+      print_func (Histable::INSTR, MODE_LIST,
+                 dbev->get_metric_list (MET_NORMAL), dbev->get_metric_list (MET_NORMAL));
+      break;
+    case PDETAIL:
+      print_func (Histable::INSTR, MODE_DETAIL,
+                 dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL));
+      break;
+    case HOTLINES:
+      print_func (Histable::LINE, MODE_LIST,
+                 dbev->get_metric_list (MET_NORMAL), dbev->get_metric_list (MET_NORMAL));
+      break;
+    case LDETAIL:
+      print_func (Histable::LINE, MODE_DETAIL,
+                 dbev->get_metric_list (MET_NORMAL), dbev->get_metric_ref (MET_NORMAL));
+      break;
+    case OBJECTS:
+      print_objects ();
+      break;
+    case OVERVIEW_NEW:
+      print_overview ();
+      break;
+    case LOADOBJECT:
+      print_segments ();
+      break;
+    case GPROF:
+      print_func (Histable::FUNCTION, MODE_GPROF,
+                 dbev->get_metric_list (MET_CALL), dbev->get_metric_list (MET_NORMAL));
+      break;
+    case CALLTREE:
+      if (dbev->comparingExperiments ())
+       {
+         fprintf (out_file, GTXT ("\nNot available when comparing experiments\n\n"));
+         break;
+       }
+      print_ctree (cmd_type);
+      break;
+    case CSINGLE:
+    case CPREPEND:
+    case CAPPEND:
+    case CRMFIRST:
+    case CRMLAST:
+      print_gprof (cmd_type, arg1, arg2);
+      break;
+    case EXP_LIST:
+      exp_list ();
+      break;
+    case DESCRIBE:
+      describe ();
+      break;
+    case SCOMPCOM:
+      status = dbev->proc_compcom (arg1, true, false);
+      if (status != CMD_OK)
+       fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+      break;
+    case STHRESH:
+      status = dbev->proc_thresh (arg1, true, false);
+      if (status != CMD_OK)
+       fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+      break;
+    case DCOMPCOM:
+      status = dbev->proc_compcom (arg1, false, false);
+      if (status != CMD_OK)
+       fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+      break;
+    case COMPCOM:
+      status = dbev->proc_compcom (arg1, true, false);
+      if (status != CMD_OK)
+       fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+      status = dbev->proc_compcom (arg1, false, false);
+      if (status != CMD_OK)
+       fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+      break;
+    case DTHRESH:
+      status = dbev->proc_thresh (arg1, false, false);
+      if (status != CMD_OK)
+       fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+      break;
+    case SOURCE:
+    case DISASM:
+      {
+       if (arg3 != NULL)
+         abort ();
+       if (arg1 == NULL)
+         {
+           fprintf (stderr, GTXT ("Error: Invalid function/file setting: \n"));
+           break;
+         }
+       char *fcontext = NULL;
+       char *arg = parse_fname (arg1, &fcontext);
+       if (arg == NULL)
+         {
+           fprintf (stderr, GTXT ("Error: Invalid function/file setting: %s\n"), arg1);
+           free (fcontext);
+           break;
+         }
+       if (arg2 && (strlen (arg2) == 0))
+         arg2 = NULL;
+       print_anno_file (arg, arg2, fcontext, cmd_type == DISASM,
+                        dis_file, inp_file, out_file, dbev, xdefault);
+       free (arg);
+       free (fcontext);
+       break;
+      }
+    case METRIC_LIST:
+      proc_cmd (METRICS, cparam, NULL, NULL);
+      dbev->get_metric_ref (MET_NORMAL)->print_metric_list (dis_file,
+                                                           GTXT ("Available metrics:\n"), false);
+      break;
+    case METRICS:
+      if (arg1)
+       {
+         char *ret = dbev->setMetrics (arg1, false);
+         if (ret != NULL)
+           {
+             fprintf (stderr, GTXT ("Error: %s\n"), ret);
+             proc_cmd (METRIC_LIST, cparam, NULL, NULL);
+             break;
+           }
+       }
+      scratch = dbev->get_metric_list (MET_NORMAL)->get_metrics ();
+      fprintf (dis_file, GTXT ("Current metrics: %s\n"), scratch);
+      free (scratch);
+      proc_cmd (SORT, cparam, NULL, NULL);
+      break;
+    case GMETRIC_LIST:
+      scratch = dbev->get_metric_list (MET_CALL)->get_metrics ();
+      fprintf (dis_file, GTXT ("Current caller-callee metrics: %s\n"), scratch);
+      free (scratch);
+      fprintf (dis_file, GTXT ("Current caller-callee sort Metric: %s\n"),
+              dbev->getSort (MET_DATA));
+      break;
+    case INDX_METRIC_LIST:
+      scratch = dbev->get_metric_list (MET_INDX)->get_metrics ();
+      fprintf (dis_file, GTXT ("Current index-object metrics: %s\n"), scratch);
+      free (scratch);
+      scratch = dbev->getSort (MET_INDX);
+      fprintf (dis_file, GTXT ("Current index-object sort Metric: %s\n"), scratch);
+      free (scratch);
+      break;
+    case SORT:
+      if (arg1)
+       {
+         char *ret = dbev->setSort (arg1, MET_NORMAL, false);
+         if (ret != NULL)
+           {
+             fprintf (stderr, GTXT ("Error: %s\n"), ret);
+             proc_cmd (METRICS, cparam, NULL, NULL);
+             break;
+           }
+         dbev->setSort (arg1, MET_SRCDIS, false);
+         dbev->setSort (arg1, MET_CALL, false);
+         dbev->setSort (arg1, MET_DATA, false);
+         dbev->setSort (arg1, MET_INDX, false);
+         dbev->setSort (arg1, MET_CALL_AGR, false);
+         dbev->setSort (arg1, MET_IO, false);
+         dbev->setSort (arg1, MET_HEAP, false);
+       }
+      scratch = dbev->getSort (MET_NORMAL);
+      scratch1 = dbev->getSortCmd (MET_NORMAL);
+      fprintf (dis_file,
+              GTXT ("Current Sort Metric: %s ( %s )\n"), scratch, scratch1);
+      free (scratch1);
+      free (scratch);
+      break;
+    case OBJECT_SHOW:
+      if (arg1)
+       set_libexpand (arg1, LIBEX_SHOW);
+      obj_list ();
+      break;
+    case OBJECT_HIDE:
+      if (arg1)
+       set_libexpand (arg1, LIBEX_HIDE);
+      obj_list ();
+      break;
+    case OBJECT_API:
+      if (arg1)
+       set_libexpand (arg1, LIBEX_API);
+      obj_list ();
+      break;
+    case OBJECTS_DEFAULT:
+      set_libdefaults ();
+      obj_list ();
+      break;
+    case OBJECT_LIST:
+      obj_list ();
+      break;
+    case OBJECT_SELECT:
+      if (arg1)
+       {
+         if (process_object_select (arg1) != -1)
+           proc_cmd (OBJECT_LIST, cparam, NULL, NULL);
+         else
+           fprintf (stderr, GTXT ("Error: Type \"object_list\" for a list of all load objects.\n"));
+       }
+      else
+       fprintf (stderr, GTXT ("Error: No load object has been specified.\n"));
+      break;
+    case LOADOBJECT_LIST:
+      seg_list ();
+      break;
+    case LOADOBJECT_SELECT:
+      if (arg1)
+       {
+         if (process_object_select (arg1) != -1)
+           proc_cmd (LOADOBJECT_LIST, cparam, NULL, NULL);
+         else
+           fprintf (stderr, GTXT ("Error: Type \"segment_list\" for a list of all segments.\n"));
+       }
+      else
+       fprintf (stderr, GTXT ("Error: No segment has been specified.\n"));
+      break;
+    case SAMPLE_LIST:
+      filter_list (SAMPLE_LIST);
+      break;
+    case SAMPLE_SELECT:
+      if (arg1 && !dbev->set_pattern (SAMPLE_FILTER_IDX, arg1))
+       fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
+      proc_cmd (SAMPLE_LIST, cparam, NULL, NULL);
+      break;
+    case THREAD_LIST:
+      filter_list (THREAD_LIST);
+      break;
+    case THREAD_SELECT:
+      if (arg1 && !dbev->set_pattern (THREAD_FILTER_IDX, arg1))
+       fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
+      proc_cmd (THREAD_LIST, cparam, NULL, NULL);
+      break;
+    case LWP_LIST:
+      filter_list (LWP_LIST);
+      break;
+    case LWP_SELECT:
+      if (arg1 && !dbev->set_pattern (LWP_FILTER_IDX, arg1))
+       fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
+      proc_cmd (LWP_LIST, cparam, NULL, NULL);
+      break;
+    case CPU_LIST:
+      filter_list (CPU_LIST);
+      break;
+    case CPU_SELECT:
+      if (arg1 && !dbev->set_pattern (CPU_FILTER_IDX, arg1))
+       fprintf (stderr, GTXT ("Error: Invalid filter pattern specification %s\n"), arg1);
+      proc_cmd (CPU_LIST, cparam, NULL, NULL);
+      break;
+    case FILTERS:
+      if (arg1 != NULL)
+       {
+         if (strcmp (arg1, NTXT ("True")) == 0)
+           scratch = dbev->set_filter (NULL);
+         else
+           scratch = dbev->set_filter (arg1);
+         if (scratch != NULL)
+           fprintf (stderr, GTXT ("Error: %s\n"), scratch);
+       }
+      scratch = dbev->get_filter ();
+      fprintf (dis_file, GTXT ("current filter setting: \"%s\"\n"),
+              scratch == NULL ? GTXT ("<none>") : scratch);
+      break;
+    case OUTFILE:
+      if (arg1)
+       {
+         set_outfile (arg1, out_file, false);
+         if (inp_file != stdin)
+           dis_file = out_file;
+       }
+      break;
+    case APPENDFILE:
+      if (arg1)
+       {
+         set_outfile (arg1, out_file, true);
+         if (inp_file != stdin)
+           dis_file = out_file;
+       }
+      break;
+    case LIMIT:
+      if (arg1)
+       {
+         limit = (int) strtol (arg1, (char **) NULL, 10);
+         char *res = dbeSetPrintLimit (dbevindex, limit);
+         if (res != NULL)
+           fprintf (stderr, NTXT ("%s\n"), res);
+       }
+
+      limit = dbeGetPrintLimit (dbevindex);
+      fprintf (stderr, GTXT ("Print limit set to %d\n"), limit);
+      break;
+    case NAMEFMT:
+      if (arg1)
+       {
+         status = dbev->set_name_format (arg1);
+         if (status != CMD_OK)
+           fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+       }
+      else
+       fprintf (stderr, GTXT ("Error: No format has been specified.\n"));
+      break;
+    case VIEWMODE:
+      {
+       if (arg1)
+         {
+           status = dbev->set_view_mode (arg1, false);
+           if (status != CMD_OK)
+             fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+         }
+       const char *vname = "unknown";
+       int vm = dbev->get_view_mode ();
+       switch (vm)
+         {
+         case VMODE_USER:
+           vname = "user";
+           break;
+         case VMODE_EXPERT:
+           vname = "expert";
+           break;
+         case VMODE_MACHINE:
+           vname = "machine";
+           break;
+         }
+       fprintf (stderr, GTXT ("Viewmode set to %s\n"), vname);
+      }
+      break;
+
+      // EN_DESC does not make sense after experiments are read, but it does make sense on the command line,
+      //       processed before the experiments are read.
+    case EN_DESC:
+      if (arg1)
+       {
+         status = dbev->set_en_desc (arg1, false);
+         if (status != CMD_OK)
+           fprintf (stderr, GTXT ("Error: %s: %s\n"), Command::get_err_string (status), arg1);
+       }
+      else
+       fprintf (stderr, GTXT ("Error: No descendant processing has been specified.\n"));
+      break;
+    case SETPATH:
+    case ADDPATH:
+      if (arg1)
+       dbeSession->set_search_path (arg1, (cmd_type == SETPATH));
+      fprintf (dis_file, GTXT ("search path:\n"));
+      Vec_loop (char*, dbeSession->get_search_path (), index, name)
+      {
+       fprintf (dis_file, NTXT ("\t%s\n"), name);
+      }
+      break;
+    case PATHMAP:
+      {
+       Vector<pathmap_t*> *pathMaps = dbeSession->get_pathmaps ();
+       if (arg1 != NULL)
+         {
+           if (arg2 == NULL)
+             {
+               fprintf (stderr, GTXT ("Error: No replacement path prefix has been specified.\n"));
+               break;
+             }
+           // add this mapping to the session
+           char *err = Settings::add_pathmap (pathMaps, arg1, arg2);
+           if (err != NULL)
+             {
+               fprintf (stderr, NTXT ("%s"), err);
+               free (err);
+             }
+         }
+       fprintf (dis_file, GTXT ("Path mappings: from -> to\n"));
+       for (int i = 0, sz = pathMaps->size (); i < sz; i++)
+         {
+           pathmap_t *thismap = pathMaps->get (i);
+           fprintf (dis_file, NTXT ("\t`%s' -> `%s'\n"), thismap->old_prefix, thismap->new_prefix);
+         }
+      }
+      break;
+    case SAMPLE_DETAIL:
+      if (get_exp_id (arg1, bgn_index, end_index) != -1)
+       {
+         cd = new er_print_experiment (dbev, bgn_index, end_index, false,
+                                       false, false, true, true);
+         print_cmd (cd);
+         delete cd;
+       }
+      break;
+    case STATISTICS:
+      if (get_exp_id (arg1, bgn_index, end_index) != -1)
+       {
+         cd = new er_print_experiment (dbev, bgn_index, end_index, false,
+                                       false, true, true, false);
+         print_cmd (cd);
+         delete cd;
+       }
+      break;
+    case PRINTMODE:
+      {
+       if (arg1 == NULL)
+         {
+           fprintf (stderr, GTXT ("printmode is set to `%s'\n\n"), dbeGetPrintModeString (dbevindex));
+           break;
+         }
+       char *s = dbeSetPrintMode (dbevindex, arg1);
+       if (s != NULL)
+         {
+           fprintf (stderr, NTXT ("%s\n"), s);
+           break;
+         }
+       fprintf (stderr, GTXT ("printmode is set to `%s'\n\n"), dbeGetPrintModeString (dbevindex));
+      }
+      break;
+    case HEADER:
+      if (get_exp_id (arg1, bgn_index, end_index) != -1)
+       {
+         cd = new er_print_experiment (dbev, bgn_index, end_index, false,
+                                       true, false, false, false);
+         print_cmd (cd);
+         delete cd;
+       }
+      break;
+    case COMPARE:
+      if (arg1 == NULL)
+       {
+         fprintf (out_file, GTXT ("The argument to `compare' must be `on', `off', `delta', or `ratio'\n\n"));
+         break;
+       }
+      else
+       {
+         int cmp;
+         if (strcasecmp (arg1, NTXT ("OFF")) == 0 || strcmp (arg1, NTXT ("0")) == 0)
+           cmp = CMP_DISABLE;
+         else if (strcasecmp (arg1, NTXT ("ON")) == 0 || strcmp (arg1, NTXT ("1")) == 0)
+           cmp = CMP_ENABLE;
+         else if (strcasecmp (arg1, NTXT ("DELTA")) == 0)
+           cmp = CMP_DELTA;
+         else if (strcasecmp (arg1, NTXT ("RATIO")) == 0)
+           cmp = CMP_RATIO;
+         else
+           {
+             fprintf (out_file, GTXT ("The argument to `compare' must be `on', `off', `delta', or `ratio'\n\n"));
+             break;
+           }
+         int oldMode = dbev->get_compare_mode ();
+         dbev->set_compare_mode (cmp);
+         if (oldMode != cmp)
+           {
+             dbev->reset_data (false);
+             dbeSession->reset_data ();
+           }
+       }
+      break;
+    case LEAKS:
+      if (!dbeSession->is_leaklist_available ())
+       {
+         fprintf (out_file, GTXT ("\nHeap trace information was not requested when recording experiments\n\n"));
+         break;
+       }
+      if (dbev->comparingExperiments ())
+       { // XXXX show warning for compare
+         fprintf (out_file, GTXT ("\nNot available when comparing experiments\n\n"));
+         break;
+       }
+      cd = new er_print_leaklist (dbev, true, false, dbev->get_limit ());
+      print_cmd (cd);
+      delete cd;
+      break;
+    case ALLOCS:
+      if (!dbeSession->is_leaklist_available ())
+       {
+         fprintf (out_file, GTXT ("\nHeap trace information was not requested when recording experiments\n\n"));
+         break;
+       }
+      cd = new er_print_leaklist (dbev, false, true, dbev->get_limit ());
+      print_cmd (cd);
+      delete cd;
+      break;
+    case HEAP:
+      if (!dbeSession->is_heapdata_available ())
+       {
+         fprintf (out_file, GTXT ("Heap trace information was not requested when recording experiments\n\n"));
+         break;
+       }
+      cd = new er_print_heapactivity (dbev, Histable::HEAPCALLSTACK, false, dbev->get_limit ());
+      print_cmd (cd);
+      delete cd;
+      break;
+    case HEAPSTAT:
+      if (!dbeSession->is_heapdata_available ())
+       {
+         fprintf (out_file, GTXT ("Heap trace information was not requested when recording experiments\n\n"));
+         break;
+       }
+      cd = new er_print_heapactivity (dbev, Histable::HEAPCALLSTACK, true, dbev->get_limit ());
+      print_cmd (cd);
+      delete cd;
+      break;
+    case IOACTIVITY:
+      if (!dbeSession->is_iodata_available ())
+       {
+         fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
+         break;
+       }
+      if (dbev->comparingExperiments ())
+       { // XXXX show warning for compare
+         fprintf (out_file, GTXT ("\nNot available when comparing experiments\n\n"));
+         break;
+       }
+      cd = new er_print_ioactivity (dbev, Histable::IOACTFILE, false, dbev->get_limit ());
+      print_cmd (cd);
+      delete cd;
+      break;
+    case IOVFD:
+      if (!dbeSession->is_iodata_available ())
+       {
+         fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
+         break;
+       }
+      cd = new er_print_ioactivity (dbev, Histable::IOACTVFD, false, dbev->get_limit ());
+      print_cmd (cd);
+      delete cd;
+      break;
+    case IOCALLSTACK:
+      if (!dbeSession->is_iodata_available ())
+       {
+         fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
+         break;
+       }
+      cd = new er_print_ioactivity (dbev, Histable::IOCALLSTACK, false, dbev->get_limit ());
+      print_cmd (cd);
+      delete cd;
+      break;
+    case IOSTAT:
+      if (!dbeSession->is_iodata_available ())
+       {
+         fprintf (out_file, GTXT ("I/O trace information was not requested when recording experiments\n\n"));
+         break;
+       }
+      cd = new er_print_ioactivity (dbev, Histable::IOACTVFD, true, dbev->get_limit ());
+      print_cmd (cd);
+      delete cd;
+      break;
+    case HELP:
+      Command::print_help(whoami, false, true, out_file);
+      break;
+    case VERSION_cmd:
+      Application::print_version_info ();
+      break;
+    case SCRIPT:
+      if (arg1)
+       {
+         ck_file = fopen (arg1, NTXT ("r"));
+         if (ck_file == NULL)
+           fprintf (stderr, GTXT ("Error: Script file cannot be opened: %s\n"), arg1);
+         else
+           {
+             save_file = inp_file;
+             inp_file = ck_file;
+             proc_script ();
+             inp_file = save_file;
+           }
+       }
+      else
+       fprintf (stderr, GTXT ("Error: No filename has been specified.\n"));
+      break;
+    case QUIT:
+      exit (0);
+      break;
+
+      // commands relating to index Objects
+    case INDXOBJ:
+      if ((cparam == -1) && (arg1 == NULL))
+       {
+         fprintf (stderr, GTXT ("Error: No index object name has been specified.\n"));
+         break;
+       }
+      // automatically load machine model if applicable
+      dbeDetectLoadMachineModel (dbevindex);
+      indxobj (arg1, cparam);
+      break;
+    case INDXOBJLIST:
+      // automatically load machine model if applicable
+      dbeDetectLoadMachineModel (dbevindex);
+      indxo_list (false, out_file);
+      break;
+
+      // define a new IndexObject type
+    case INDXOBJDEF:
+      if (arg1 == NULL)
+       {
+         fprintf (stderr, GTXT ("Error: No index object name has been specified.\n"));
+         break;
+       }
+      if (arg2 == NULL)
+       {
+         fprintf (stderr, GTXT ("Error: No index-expr has been specified.\n"));
+         break;
+       }
+      indxo_define (arg1, arg2, arg3, arg4);
+      break;
+
+      // the commands following this are unsupported/hidden
+    case IFREQ:
+      if (!dbeSession->is_ifreq_available ())
+       {
+         fprintf (out_file, GTXT ("\nInstruction frequency data was not requested when recording experiments\n\n"));
+         break;
+       }
+      ifreq ();
+      break;
+    case DUMPNODES:
+      dump_nodes ();
+      break;
+    case DUMPSTACKS:
+      dump_stacks ();
+      break;
+    case DUMPUNK:
+      dump_unk_pcs ();
+      break;
+    case DUMPFUNC:
+      dump_funcs (arg1);
+      break;
+    case DUMPDOBJS:
+      dump_dataobjects (arg1);
+      break;
+    case DUMPMAP:
+      dump_map ();
+      break;
+    case DUMPENTITIES:
+      dump_entities ();
+      break;
+    case DUMP_PROFILE:
+      dbev->dump_profile (out_file);
+      break;
+    case DUMP_SYNC:
+      dbev->dump_sync (out_file);
+      break;
+    case DUMP_HWC:
+      dbev->dump_hwc (out_file);
+      break;
+    case DUMP_HEAP:
+      if (!dbeSession->is_leaklist_available ())
+       {
+         fprintf (out_file, GTXT ("\nHeap trace information was not requested when recording experiments\n\n"));
+         break;
+       }
+      dbev->dump_heap (out_file);
+      break;
+    case DUMP_IOTRACE:
+      if (!dbeSession->is_iodata_available ())
+       {
+         fprintf (out_file, GTXT ("\nI/O trace information was not requested when recording experiments\n\n"));
+         break;
+       }
+      dbev->dump_iotrace (out_file);
+      break;
+    case DMEM:
+      if (arg1 == NULL)
+       fprintf (stderr, GTXT ("Error: No sample has been specified.\n"));
+      else
+       {
+         Experiment *exp = dbeSession->get_exp (0);
+         if (exp != NULL)
+           exp->DBG_memuse (arg1);
+       }
+      break;
+    case DUMP_GC:
+      if (!dbeSession->has_java ())
+       {
+         fprintf (out_file, GTXT ("\nJava garbage collection information was not requested when recording experiments\n\n"));
+         break;
+       }
+      dbev->dump_gc_events (out_file);
+      break;
+    case DKILL:
+      {
+       if (arg1 == NULL)
+         {
+           fprintf (stderr, GTXT ("Error: No process has been specified.\n"));
+           break;
+         }
+       if (arg2 == NULL)
+         {
+           fprintf (stderr, GTXT ("Error: No signal has been specified.\n"));
+           break;
+         }
+       pid_t p = (pid_t) atoi (arg1);
+       int signum = atoi (arg2);
+       char *ret = dbeSendSignal (p, signum);
+       if (ret != NULL)
+         fprintf (stderr, GTXT ("Error: %s"), ret);
+      }
+      break;
+    case PROCSTATS:
+      dump_stats ();
+      break;
+    case ADD_EXP:
+    case OPEN_EXP:
+      if (arg1 == NULL)
+       fprintf (stderr, GTXT ("Error: No experiment name has been specified.\n"));
+      else
+       {
+         Vector<Vector<char*>*> *groups = new Vector<Vector<char*>*>(1);
+         Vector<char*> *list = new Vector<char*>(1);
+         list->append (arg1);
+         groups->append (list);
+         char *res = dbeOpenExperimentList (dbevindex, groups, cmd_type == OPEN_EXP);
+         if (cmd_type == OPEN_EXP)
+           fprintf (stderr, GTXT ("Previously loaded experiment have been dropped.\n"));
+         if (res != NULL)
+           fprintf (stderr, NTXT ("%s"), res);
+         else
+           fprintf (stderr, GTXT ("Experiment %s has been loaded\n"), arg1);
+         free (res);
+         delete list;
+         delete groups;
+       }
+      break;
+    case DROP_EXP:
+      {
+       if (arg1 == NULL)
+         fprintf (stderr, GTXT ("Error: No experiment name has been specified.\n"));
+       else
+         {
+           int exp_index = dbeSession->find_experiment (arg1);
+           if (exp_index < 0)
+             fprintf (stderr, GTXT ("Error: experiment %s has not been opened.\n"), arg1);
+           else
+             {
+               Vector<int> *expid = new Vector<int> (1);
+               expid->append (exp_index);
+               char *res = dbeDropExperiment (dbevindex, expid);
+               if (res != NULL)
+                 fprintf (stderr, NTXT ("%s"), res);
+               else
+                 fprintf (stderr, GTXT ("Experiment %s has been dropped\n"), arg1);
+               delete expid;
+               free (res);
+             }
+         }
+      }
+      break;
+    case HHELP:
+      // automatically load machine model if applicable
+      dbeDetectLoadMachineModel (dbevindex);
+      Command::print_help (whoami, false, false, out_file);
+      fprintf (out_file, NTXT ("\n"));
+      indxo_list (false, out_file);
+      fprintf (out_file, NTXT ("\n"));
+      mo_list (false, out_file);
+      if (!getenv ("_BUILDING_MANPAGE"))
+       fprintf (out_file, GTXT ("\nSee gprofng(1) for more details\n"));
+      break;
+    case QQUIT:
+      was_QQUIT = true;
+      return;
+    default:
+      fprintf (stderr, GTXT ("Error: Invalid option\n"));
+      break;
+    }
+
+  // check for any processing error messages
+  dump_proc_warnings ();
+  fflush (out_file);
+}
+
+#define MAX_NUM_HEADER      4
+
+void
+er_print::disp_list (int num_header, int size, int align[], char *header[],
+                    char **lists[])
+{
+  size_t maxlen[MAX_NUM_HEADER];
+  char fmt[MAX_NUM_HEADER][64];
+  if (num_header > MAX_NUM_HEADER)
+    abort ();
+  for (int i = 0; i < num_header; i++)
+    {
+      maxlen[i] = strlen (header[i]);
+      for (int j = 0; j < size; j++)
+       {
+         size_t len = strlen (lists[i][j]);
+         if (maxlen[i] < len)
+           maxlen[i] = len;
+       }
+
+      // get format string
+      if ((align[i] == -1) && (i == num_header - 1))
+       snprintf (fmt[i], sizeof (fmt[i]), NTXT ("%%s "));
+      else
+       snprintf (fmt[i], sizeof (fmt[i]), NTXT ("%%%ds "), (int) (align[i] * maxlen[i]));
+
+      // write header
+      fprintf (out_file, fmt[i], header[i]);
+    }
+  putc ('\n', out_file);
+
+  // write separator "==="
+  size_t np = 0;
+  for (int i = 0; (i < num_header) && (np < 132); i++)
+    {
+      size_t nc = maxlen[i];
+      if (nc + np > 132)
+       nc = 132 - np;
+      for (size_t j = 0; j < nc; j++)
+       putc ('=', out_file);
+      putc (' ', out_file);
+      np += nc + 1;
+    }
+  putc ('\n', out_file);
+
+  // write lists
+  for (int j = 0; j < size; j++)
+    {
+      for (int i = 0; i < num_header; i++)
+       fprintf (out_file, fmt[i], lists[i][j]);
+      putc ('\n', out_file);
+    }
+}
+
+void
+er_print::exp_list ()
+{
+  int size, index;
+  int align[MAX_NUM_HEADER];
+  char *header[MAX_NUM_HEADER];
+  char **lists[MAX_NUM_HEADER];
+
+  align[0] = 1;     // right-justify
+  align[1] = 1;     // right-justify
+  align[2] = 1;     // right-justify
+  align[3] = -1;    // left-justify
+  header[0] = GTXT ("ID");
+  header[1] = GTXT ("Sel");
+  header[2] = GTXT ("PID");
+  header[3] = GTXT ("Experiment");
+
+  size = dbeSession->nexps ();
+  lists[0] = new char*[size];
+  lists[1] = new char*[size];
+  lists[2] = new char*[size];
+  lists[3] = new char*[size];
+  for (index = 0; index < size; index++)
+    {
+      lists[0][index] = dbe_sprintf (NTXT ("%d"), index + 1);
+      lists[1][index] = strdup (dbev->get_exp_enable (index) ? GTXT ("yes") : GTXT ("no"));
+      lists[2][index] = dbe_sprintf (NTXT ("%d"), dbeSession->get_exp (index)->getPID ());
+      lists[3][index] = strdup (dbeSession->get_exp (index)->get_expt_name ());
+    }
+  disp_list (4, size, align, header, lists);
+  for (int i = 0; i < 4; i++)
+    {
+      for (int j = 0; j < size; j++)
+       free (lists[i][j]);
+      delete[] lists[i];
+    }
+}
+
+void
+er_print::describe ()
+{
+  Vector<void*> *res = dbeGetFilterKeywords (dbev->vindex);
+  if (res == NULL)
+    return;
+  Vector <char*> *kwCategoryI18N = (Vector<char*>*) res->fetch (1);
+  Vector <char*> *kwKeyword = (Vector<char*>*) res->fetch (3);
+  Vector <char*> *kwFormula = (Vector<char*>*) res->fetch (4);
+  Vector <char*> *kwDescrip = (Vector<char*>*) res->fetch (5);
+  Vector <void*> *kwEnumDescs = (Vector<void*>*) res->fetch (6);
+  String sectionFormat = NTXT ("\n------ %s ------\n");
+  String categoryFormat = NTXT ("\n%s\n");
+  String keywordFormat = NTXT ("   %-20s  %s\n");
+  String empty = NTXT ("");
+  String previousCategory = empty;
+
+  for (int i = 0; i < kwKeyword->size (); i++)
+    {
+      if (kwKeyword->fetch (i) == NULL)
+       {
+         fprintf (dis_file, sectionFormat, kwCategoryI18N->fetch (i));
+         continue;
+       }
+      String cat = kwCategoryI18N->fetch (i);
+      if (dbe_strcmp (previousCategory, cat) != 0)
+       fprintf (dis_file, categoryFormat, cat);
+      previousCategory = cat;
+      Vector <String> *enumDescs = (Vector <String> *) kwEnumDescs->fetch (i);
+      String keyword = kwKeyword->fetch (i);
+      if (kwDescrip->fetch (i) != NULL)
+       {
+         fprintf (dis_file, keywordFormat, keyword, kwDescrip->fetch (i));
+         keyword = empty;
+       }
+      if (kwFormula->fetch (i) != NULL)
+       {
+         fprintf (dis_file, keywordFormat, keyword, kwFormula->fetch (i));
+         keyword = empty;
+         continue;
+       }
+      int numEnums = enumDescs != NULL ? enumDescs->size () : 0;
+      for (int jj = 0; jj < numEnums; jj++)
+       {
+         fprintf (dis_file, keywordFormat, keyword, enumDescs->fetch (jj));
+         keyword = empty;
+       }
+    }
+  destroy (res);
+}
+
+void
+er_print::obj_list ()
+{
+  LoadObject *lo;
+  int index;
+  int align[MAX_NUM_HEADER];
+  char *header[MAX_NUM_HEADER];
+  char **lists[MAX_NUM_HEADER];
+  Vector<LoadObject*> *text_segments = dbeSession->get_text_segments ();
+  if (text_segments->size () == 0)
+    {
+      fprintf (dis_file, GTXT ("There are no load objects in this experiment\n"));
+      return;
+    }
+  align[0] = -1; // left-justify
+  align[1] = -1; // left-justify
+  align[2] = -1; // left-justify
+  align[3] = -1; // left-justify
+  header[0] = GTXT ("Sel");
+  header[1] = GTXT ("Load Object");
+  header[2] = GTXT ("Index");
+  header[3] = GTXT ("Path");
+
+  int size = text_segments->size ();
+  lists[0] = new char*[size];
+  lists[1] = new char*[size];
+  lists[2] = new char*[size];
+  lists[3] = new char*[size];
+
+  char *lo_name;
+  int new_index = 0;
+  Vec_loop (LoadObject*, text_segments, index, lo)
+  {
+    lo_name = lo->get_name ();
+    if (lo_name != NULL)
+      {
+       size_t len = strlen (lo_name);
+       if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
+         continue;
+      }
+    LibExpand expand = dbev->get_lo_expand (lo->seg_idx);
+    switch (expand)
+      {
+      case LIBEX_SHOW:
+       lists[0][new_index] = dbe_strdup (GTXT ("show"));
+       break;
+      case LIBEX_HIDE:
+       lists[0][new_index] = dbe_strdup (GTXT ("hide"));
+       break;
+      case LIBEX_API:
+       lists[0][new_index] = dbe_strdup (GTXT ("API-only"));
+       break;
+      }
+    lists[1][new_index] = dbe_strdup (lo_name);
+    lists[2][new_index] = dbe_sprintf (NTXT ("%d"), lo->seg_idx);
+    lists[3][new_index] = dbe_strdup (lo->get_pathname ());
+    new_index++;
+  }
+  disp_list (4, new_index, align, header, lists);
+  for (int i = 0; i < 4; i++)
+    {
+      for (int j = 0; j < new_index; j++)
+       free (lists[i][j]);
+      delete[] lists[i];
+    }
+  delete text_segments;
+}
+
+void
+er_print::seg_list ()
+{
+  LoadObject *lo;
+  int index;
+  int align[MAX_NUM_HEADER];
+  char *header[MAX_NUM_HEADER];
+  char **lists[MAX_NUM_HEADER];
+
+  // XXX seg_list only prints text segments; should extend to all
+  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+  if (lobjs->size () == 0)
+    {
+      fprintf (dis_file, GTXT ("There are no segments in this experiment\n"));
+      return;
+    }
+  align[0] = -1; // left-justify
+  align[1] = 1;  // right-justify
+  align[2] = -1; // left-justify
+  header[0] = GTXT ("Sel");
+  header[1] = GTXT ("Size");
+  header[2] = GTXT ("Segment");
+
+  int size = lobjs->size ();
+  lists[0] = new char*[size];
+  lists[1] = new char*[size];
+  lists[2] = new char*[size];
+
+  char *lo_name;
+  int new_index = 0;
+  Vec_loop (LoadObject*, lobjs, index, lo)
+  {
+    lo_name = lo->get_name ();
+    if (lo_name != NULL)
+      {
+       size_t len = strlen (lo_name);
+       if (len > 7 && streq (lo_name + len - 7, NTXT (".class>")))
+         continue;
+      }
+    bool expand = dbev->get_lo_expand (lo->seg_idx);
+    lists[0][new_index] = strdup (expand ? GTXT ("yes") : GTXT ("no"));
+    lists[1][new_index] = dbe_sprintf (NTXT ("%lld"), (ll_t) lo->get_size ());
+    lists[2][new_index] = strdup (lo->get_pathname ());
+    new_index++;
+  }
+
+  disp_list (3, new_index, align, header, lists);
+  for (int i = 0; i < 4; i++)
+    {
+      for (int j = 0; j < new_index; j++)
+       free (lists[i][j]);
+      delete[] lists[i];
+    }
+  delete lobjs;
+}
+
+void
+er_print::filter_list (CmdType cmd_type)
+{
+  FilterNumeric *select;
+  int index;
+  int align[MAX_NUM_HEADER];
+  char *header[MAX_NUM_HEADER];
+  char **lists[MAX_NUM_HEADER];
+  char *pattern;
+
+  // first ensure that the data has been read
+  MetricList *mlist = dbev->get_metric_list (MET_INDX);
+  Hist_data *data = dbev->get_hist_data (mlist, Histable::INDEXOBJ, 0, Hist_data::ALL);
+  delete data;
+
+  align[0] = 1;  // right-justify
+  align[1] = -1; // left-justify
+  align[2] = 1;  // right-justify
+  align[3] = 1;  // right-justify
+  header[0] = GTXT ("Exp");
+  header[1] = GTXT ("Sel");
+  header[2] = GTXT ("Total");
+  header[3] = GTXT ("Status");
+
+  int size = dbeSession->nexps ();
+  lists[0] = new char*[size];
+  lists[1] = new char*[size];
+  lists[2] = new char*[size];
+  lists[3] = new char*[size];
+  int new_index = 0;
+  for (index = 0; index < size; index++)
+    {
+      switch (cmd_type)
+       {
+       case SAMPLE_LIST:
+         select = dbev->get_FilterNumeric (index, SAMPLE_FILTER_IDX);
+         break;
+       case THREAD_LIST:
+         select = dbev->get_FilterNumeric (index, THREAD_FILTER_IDX);
+         break;
+       case LWP_LIST:
+         select = dbev->get_FilterNumeric (index, LWP_FILTER_IDX);
+         break;
+       case CPU_LIST:
+         select = dbev->get_FilterNumeric (index, CPU_FILTER_IDX);
+         break;
+       default:
+         abort (); // internal error
+       }
+      if (select == NULL)
+       continue;
+      lists[0][new_index] = dbe_sprintf (NTXT ("%d"), index + 1);
+      pattern = dbev->get_exp_enable (index) ? select->get_pattern () : NULL;
+      lists[1][new_index] = strdup (pattern && *pattern ? pattern : GTXT ("none"));
+      lists[2][new_index] = dbe_sprintf (NTXT ("%lld"), (ll_t) select->nelem ());
+      lists[3][new_index] = select->get_status ();
+      new_index++;
+    }
+  disp_list (3, size, align, header, lists);
+  for (int i = 0; i < 4; i++)
+    {
+      for (int j = 0; j < new_index; j++)
+       free (lists[i][j]);
+      delete[] lists[i];
+    }
+}
+
+int
+er_print::check_exp_id (int exp_id, char *sel)
+{
+  if (exp_id < 0 || exp_id >= dbeSession->nexps ())
+    {
+      fprintf (stderr, GTXT ("Error: Invalid number entered: %s\nType \"exp_list\" for a list of all experiments.\n"),
+              sel);
+      return -1;
+    }
+  return exp_id;
+}
+
+int
+er_print::get_exp_id (char *sel, int &bgn_index, int &end_index)
+{
+  int id, exp_id;
+  if (sel == NULL || strcmp (sel, NTXT ("all")) == 0)
+    {
+      // loop over all experiments
+      bgn_index = 0;
+      end_index = dbeSession->nexps () - 1;
+    }
+  else
+    {
+      id = (int) strtol (sel, (char **) NULL, 10) - 1;
+      exp_id = check_exp_id (id, sel);
+     if (exp_id == -1)
+       return -1;
+      bgn_index = end_index = exp_id;
+    }
+  return 0;
+}
+
+void
+er_print::print_objects ()
+{
+  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+  char *msg = pr_load_objects (lobjs, NTXT (""));
+  delete lobjs;
+  fprintf (out_file, NTXT ("%s\n"), msg);
+  free (msg);
+}
+
+void
+er_print::print_overview ()
+{
+  //fprintf(out_file, NTXT("%s\n"), GTXT("Not implemented yet."));//YXXX
+  Vector<char*> *status = dbeGetOverviewText (dbevindex);
+  StringBuilder sb;
+  sb.append (GTXT ("Experiment(s):\n\n"));
+  for (int i = 0; i < status->size (); i++)
+    sb.appendf (NTXT ("%s\n"), status->fetch (i));
+  sb.append (GTXT ("Metrics:\n"));
+  sb.toFile (out_file);
+
+  Vector<void*> *data = dbeGetRefMetricTree (dbevindex, false);
+  Vector<char *> *metric_cmds = new Vector<char *>();
+  Vector<char *> *non_metric_cmds = new Vector<char *>();
+  print_overview_nodes (data, 0, metric_cmds, non_metric_cmds);
+  Vector<void*> *values = dbeGetRefMetricTreeValues (0, metric_cmds, non_metric_cmds);
+  print_overview_tree (data, 0, values, metric_cmds, non_metric_cmds);
+
+  StringBuilder sb2;
+  sb2.append (GTXT ("\nNotes: '*' indicates hot metrics, '[X]' indicates currently enabled metrics.\n"));
+  sb2.append (GTXT ("       The metrics command can be used to change selections. The metric_list command lists all available metrics.\n"));
+  sb2.toFile (out_file);
+}
+
+void
+er_print::print_overview_nodes (Vector<void*> * data, int level, Vector<char *> *metric_cmds, Vector<char *> *non_metric_cmds)
+{
+  Vector<void*> *fields = (Vector<void*> *) data->fetch (0);
+  Vector<void*> *children = (Vector<void*> *) data->fetch (1);
+  char *name = ((Vector<char*> *)fields->fetch (0))->fetch (0);
+  int vstyles_capable = ((Vector<int>*) fields->fetch (5))->fetch (0); //bitmask e.g.VAL_TIMEVAL
+  bool has_value = ((Vector<bool>*) fields->fetch (10))->fetch (0);
+  bool selectable = (vstyles_capable != 0) ? true : false;
+  if (selectable)
+    metric_cmds->append (name);
+  else if (has_value)
+    non_metric_cmds->append (name);
+
+  level++;
+  for (int i = 0; i < children->size (); i++)
+    print_overview_nodes ((Vector<void*> *)(children->fetch (i)), level, metric_cmds, non_metric_cmds);
+}
+
+void
+er_print::print_overview_tree (Vector<void*> * data, int level, Vector<void*> * values, Vector<char *> *metric_cmds, Vector<char *> *non_metric_cmds)
+{
+  Vector<void*> * fields = (Vector<void*> *) data->fetch (0);
+  Vector<void*> * children = (Vector<void*> *) data->fetch (1);
+  char *name = ((Vector<char*> *)fields->fetch (0))->fetch (0);
+  char *username = ((Vector<char*> *)fields->fetch (1))->fetch (0);
+  int flavors = ((Vector<int>*) fields->fetch (3))->fetch (0); //bitmask e.g. EXCLUSIVE
+  int vstyles_capable = ((Vector<int>*) fields->fetch (5))->fetch (0); //bitmask e.g.VAL_TIMEVAL
+  //    bool aggregation = ((Vector<bool>*) fields->fetch(9))->fetch(0);
+  //    bool has_value = ((Vector<bool>*) fields->fetch(10))->fetch(0);
+  char *unit = ((Vector<char*> *) fields->fetch (11))->fetch (0);
+
+  StringBuilder sb;
+  for (int i = 0; i < level * 2; i++)
+    sb.append (NTXT (" ")); // NOI18N
+
+  bool selectable = (vstyles_capable != 0) ? true : false;
+  if (selectable)
+    {
+      bool isSelected = dbev->get_metric_list (MET_NORMAL)->find_metric_by_name (name) == NULL ? false : true;
+      if (isSelected)
+       sb.append (NTXT ("[X]"));
+      else
+       sb.append (NTXT ("[ ]"));
+    }
+  if ((unit != NULL && dbe_strcmp (unit, UNIT_SECONDS) == 0)
+      || (unit == NULL && vstyles_capable & VAL_TIMEVAL))
+    unit = GTXT ("Seconds");
+
+  bool isHiddenInOverview = ((flavors & BaseMetric::STATIC) != 0);
+  if (name != NULL && dbe_strcmp (name, L1_STATIC) == 0)
+    isHiddenInOverview = true;
+  if (!dbeSession->has_java () && name != NULL && dbe_strcmp (name, L1_GCDURATION) == 0)
+    isHiddenInOverview = true;
+  if (isHiddenInOverview)
+    return;
+
+  sb.append (username == NULL ? NTXT ("") : username); // NOI18N
+  int show = 0;
+  if (name == NULL)
+    show = 0;
+  else if (strstr (name, NTXT ("PROFDATA_TYPE_")) == NULL)
+    show = 1;
+
+  if (show)
+    {
+      sb.append (username == NULL ? NTXT ("") : NTXT (" - ")); // NOI18N
+      sb.append (name == NULL ? NTXT ("") : name); // NOI18N
+    }
+
+  // "Bugs 16624403 and 19539622" (leave this string intact for searches)
+  // add an extra condition for now
+  // once we have proper fixes, eliminate test on Bug16624402_extra_condition
+  int Bug16624402_extra_condition = 1;
+  if (username)
+    {
+      if (strcmp (username, NTXT ("Block Covered %")) == 0) Bug16624402_extra_condition = 0;
+      if (strcmp (username, NTXT ("Instr Covered %")) == 0) Bug16624402_extra_condition = 0;
+    }
+  if (Bug16624402_extra_condition > 0 && values->size () > 0)
+    {
+      Vector<void*> * valueColumns = (Vector<void*> *)values->fetch (0);
+      Vector<void*> * highlightColumns = (Vector<void*> *)values->fetch (1);
+      int jj = 0;
+      int found = 0;
+      for (jj = 0; jj < valueColumns->size (); jj++)
+       {
+         const char *value_name = "";
+         if (jj < metric_cmds->size ())
+           value_name = metric_cmds->fetch (jj);
+         else
+           value_name = non_metric_cmds->fetch (jj - metric_cmds->size ());
+         if (dbe_strcmp (value_name, name) != 0)
+           continue;
+         else
+           {
+             found = 1;
+             break;
+           }
+       }
+      if (found)
+       {
+         Vector<void*> * valueVec = (Vector<void*> *)valueColumns->fetch (jj);
+         Vector<bool> * highlights = (Vector<bool> *)highlightColumns->fetch (jj);
+         for (int kk = 0; kk < valueVec->size (); kk++)
+           {
+             char * value_str;
+             int show_value = 0;
+             switch (valueVec->type ())
+               {
+               case VEC_INTEGER:
+                 value_str = dbe_sprintf (NTXT ("%ld"), (long) (((Vector<int> *)valueVec)->fetch (kk)));
+                 show_value = 1;
+                 break;
+               case VEC_DOUBLE:
+                 value_str = dbe_sprintf (NTXT ("%.3f"), (double) (((Vector<double> *)valueVec)->fetch (kk)));
+                 show_value = 1;
+                 break;
+               case VEC_LLONG:
+                 value_str = dbe_sprintf (NTXT ("%lld"), (long long) (((Vector<long> *)valueVec)->fetch (kk)));
+                 show_value = 1;
+                 break;
+               case VEC_STRING:
+                 value_str = NTXT ("");
+                 break;
+               default:
+                 value_str = NTXT ("");
+               }
+             if (show_value)
+               {
+                 if (kk == 0)
+                   {
+                     sb.append (unit == NULL ? NTXT ("") : NTXT (" ("));
+                     sb.append (unit == NULL ? NTXT ("") : unit);
+                     sb.append (unit == NULL ? NTXT ("") : NTXT (")"));
+                     sb.append (NTXT (":"));
+                   }
+                 bool highlight = highlights->fetch (kk);
+                 const char * hilite = highlight ? NTXT ("*") : NTXT ("");
+                 sb.append (NTXT (" ["));
+                 sb.append (hilite);
+                 sb.append (value_str);
+                 sb.append (NTXT ("]"));
+               }
+           }
+       }
+    }
+  sb.append (NTXT ("\n"));
+  sb.toFile (out_file);
+  level++;
+  for (int i = 0; i < children->size (); i++)
+    print_overview_tree ((Vector<void*> *)(children->fetch (i)), level, values, metric_cmds, non_metric_cmds);
+}
+
+void
+er_print::print_segments ()
+{
+  Vector<LoadObject*> *lobjs = dbeSession->get_text_segments ();
+  char *msg = pr_load_objects (lobjs, NTXT (""));
+  delete lobjs;
+  fprintf (dis_file, NTXT ("Not implemented yet!\n"));
+  free (msg);
+}
+
+void
+er_print::print_dobj (Print_mode mode, MetricList *mlist1,
+                     char *dobj_name, char *sel)
+{
+  Hist_data *hist_data = NULL;
+  char *errstr;
+  er_print_common_display *cd;
+  int list_limit = limit;
+  Histable *sobj = NULL;
+  Dprintf (DEBUG_DATAOBJ, NTXT ("er_print::print_dobj(mode=%d,dobj=%s,sel=%s)\n"),
+          mode, (dobj_name == NULL) ? NTXT ("0") : dobj_name, (sel == NULL) ? NTXT ("0") : sel);
+  char *name = dbev->getSort (MET_DATA);
+  switch (mode)
+    {
+    case MODE_LIST:
+      hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::ALL);
+      break;
+    case MODE_DETAIL:
+      // if specified, find the dataobject from the name
+      if (dobj_name && strcmp (dobj_name, NTXT ("<All>")))
+       {
+         if (!dbeSession->find_obj (dis_file, inp_file, sobj, dobj_name,
+                                    sel, Histable::DOBJECT, (inp_file != stdin)))
+           return;
+         if (sobj == NULL)
+           { // dataobject/segment not found
+             hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::DETAIL);
+             if (!dbeSession->find_obj (dis_file, inp_file, sobj, dobj_name,
+                                        sel, Histable::DOBJECT, (inp_file != stdin)))
+               return;
+             if (sobj == NULL)
+               { // dataobject/segment not found
+                 fprintf (stderr, GTXT ("Error: No dataobject with given name `%s' found.\n"),
+                          dobj_name);
+                 return;
+               }
+           }
+
+         list_limit = 1;
+       }
+      if (!hist_data)
+       hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::DETAIL);
+      break;
+    case MODE_ANNOTATED:
+      hist_data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::LAYOUT);
+      break;
+    default: // MODE_GPROF is not relevant for DataObjects
+      abort ();
+    }
+
+  if (hist_data->get_status () != Hist_data::SUCCESS)
+    {
+      // XXXX is this error message adequate?
+      errstr = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+      if (errstr)
+       {
+         fprintf (stderr, GTXT ("Error: %s\n"), errstr);
+         free (errstr);
+       }
+      delete hist_data;
+      return;
+    }
+  cd = (er_print_common_display *) new er_print_histogram (dbev, hist_data,
+                                                          hist_data->get_metric_list (), mode, list_limit, name, sobj, false, false);
+  free (name);
+  print_cmd (cd);
+
+  delete hist_data;
+  delete cd;
+}
+
+void
+er_print::print_func (Histable::Type type, Print_mode mode, MetricList *mlist1,
+                     MetricList *mlist2, char *func_name, char *sel)
+{
+  Hist_data *hist_data;
+  Hist_data::HistItem *hitem;
+  int index;
+  char *errstr;
+  int list_limit = limit;
+  Histable *sobj = NULL;
+  MetricList *mlist;
+  StringBuilder sb;
+  char *sname = dbev->getSort (MET_NORMAL);
+  sb.append (sname);
+  free (sname);
+
+  switch (mode)
+    {
+    case MODE_DETAIL:
+      {
+       // The first metric list, mlist1, is only used to pick out the sort
+       //    mlist2 is the one used to generate the data
+       char *prevsort = NULL;
+       // if specified, find the function from the function name
+       if (func_name && strcmp (func_name, NTXT ("<All>")))
+         {
+           if ((!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
+                                       sel, Histable::FUNCTION, (inp_file != stdin)) || (sobj == NULL)) &&
+               !dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
+                                      sel, Histable::LOADOBJECT, (inp_file != stdin)))
+             return;
+           if (sobj == NULL)
+             { // function/segment object not found
+               fprintf (stderr, GTXT ("Error: No function with given name `%s' found.\n"),
+                        func_name);
+               return;
+             }
+           list_limit = 1;
+         }
+       else
+         {
+           // find the sort metric from the reference list
+           prevsort = mlist2->get_sort_cmd ();
+
+           // find the current sort metric from the current list
+           char *cursort = mlist1->get_sort_cmd ();
+
+           // find the corresponding metric in the reference list
+           (void) mlist2->set_sort (cursort, false);
+           free (cursort);
+           // if it fails, nothing is needed
+         }
+       hist_data = dbev->get_hist_data (mlist2, type, 0, Hist_data::ALL);
+
+       // restore
+       if (sobj == NULL)
+         {
+           if (prevsort == NULL)
+             abort ();
+           (void) mlist2->set_sort (prevsort, false);
+         }
+       mlist = mlist2;
+       free (prevsort);
+       break;
+      }
+    case MODE_GPROF:
+      // if specified, find the function from the function name
+      if (func_name && strcmp (func_name, NTXT ("<All>")))
+       {
+         if (!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
+                                    sel, Histable::FUNCTION, (inp_file != stdin)))
+           return;
+         if (sobj == NULL)
+           { // function/segment object not found
+             fprintf (stderr, GTXT ("Error: No function with given name `%s' found.\n"),
+                      func_name);
+             return;
+           }
+         list_limit = 1;
+         sb.setLength (0);
+       }
+      sb.append (GTXT ("\nCallers and callees sorted by metric: "));
+      sname = dbev->getSort (MET_CALL);
+      sb.append (sname);
+      free (sname);
+
+      // Use mlist2 to generate the sort order.
+      // mlist1 is used to generate the data.
+      hist_data = dbev->get_hist_data (mlist2, type, 0, Hist_data::ALL);
+      mlist = mlist1;
+      break;
+    default:
+      hist_data = dbev->get_hist_data (mlist1, type, 0, Hist_data::ALL);
+      mlist = mlist1;
+    }
+
+  if (hist_data->get_status () != Hist_data::SUCCESS)
+    {
+      errstr = DbeView::status_str (DbeView::DBEVIEW_NO_DATA);
+      if (errstr)
+       {
+         fprintf (stderr, GTXT ("Error: %s\n"), errstr);
+         free (errstr);
+       }
+      delete hist_data;
+      return;
+    }
+
+  if (type == Histable::FUNCTION)
+    {
+      for (index = 0; index < hist_data->size (); index++)
+       {
+         hitem = hist_data->fetch (index);
+         if (hitem->obj->get_type () == Histable::FUNCTION)
+           // fetch the name, since that will force a format conversion
+           ((Function *) hitem->obj)->get_name ();
+       }
+    }
+
+  char *name = sb.toString ();
+  er_print_histogram *cd = new er_print_histogram (dbev, hist_data,
+                                                  mlist, mode, list_limit, name, sobj, false, false);
+  print_cmd (cd);
+  delete hist_data;
+  free (name);
+  delete cd;
+}
+
+void
+er_print::print_gprof (CmdType cmd_type, char *func_name, char *sel)
+{
+  Histable *sobj = NULL;
+  if (func_name != NULL)
+    {
+      if ((!dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
+                                 sel, Histable::FUNCTION, (inp_file != stdin))
+          || sobj == NULL)
+         && !dbeSession->find_obj (dis_file, inp_file, sobj, func_name,
+                                   sel, Histable::LOADOBJECT, (inp_file != stdin)))
+       return;
+      if (sobj == NULL)
+       { // function/segment object not found
+         fprintf (stderr, GTXT ("Error: No function with given name `%s' found.\n"),
+                  func_name);
+         return;
+       }
+    }
+  if (cmd_type == CPREPEND)
+    {
+      if (sobj == NULL)
+       {
+         fprintf (stderr, GTXT ("Error: No function name has been specified.\n"));
+         return;
+       }
+      cstack->insert (0, sobj);
+    }
+  else if (cmd_type == CAPPEND)
+    {
+      if (sobj == NULL)
+       {
+         fprintf (stderr, GTXT ("Error: No function name has been specified.\n"));
+         return;
+       }
+      cstack->append (sobj);
+    }
+  else if (cmd_type == CSINGLE)
+    {
+      if (sobj != NULL)
+       {
+         cstack->reset ();
+         cstack->append (sobj);
+       }
+      else if (cstack->size () == 0)
+       {
+         fprintf (stderr, GTXT ("Error: No function name has been specified.\n"));
+         return;
+       }
+    }
+  else if (cmd_type == CRMFIRST)
+    {
+      if (cstack->size () <= 1)
+       {
+         fprintf (stderr, GTXT ("Warning: there is only one function in the stack segment; cannot remove it.\n"));
+         return;
+       }
+      cstack->remove (0);
+    }
+  else if (cmd_type == CRMLAST)
+    {
+      if (cstack->size () <= 1)
+       {
+         fprintf (stderr, GTXT ("Warning: there is only one function in the stack segment; cannot remove it.\n"));
+         return;
+       }
+      cstack->remove (cstack->size () - 1);
+    }
+
+  er_print_gprof *cd = new er_print_gprof (dbev, cstack);
+  print_cmd (cd);
+  delete cd;
+}
+
+/*
+ * Method print_ctree() prints Functions Call Tree.
+ */
+void
+er_print::print_ctree (CmdType cmd_type)
+{
+  if (cmd_type != CALLTREE)
+    {
+      fprintf (stderr, GTXT ("Error: Invalid command type: %d\n"), cmd_type);
+      return;
+    }
+
+  Histable *sobj = dbeSession->get_Total_Function ();
+  Vector<Histable*> *ctree_cstack = new Vector<Histable*>();
+  ctree_cstack->reset ();
+  er_print_ctree *cd = new er_print_ctree (dbev, ctree_cstack, sobj, limit);
+  print_cmd (cd);
+  delete ctree_cstack;
+  delete cd;
+}
+
+void
+er_print::memobj (char *name, int cparam)
+{
+  int type;
+  if (name != NULL)
+    {
+      // find the memory object index for the name
+      MemObjType_t *mot = MemorySpace::findMemSpaceByName (name);
+      if (mot == NULL)
+       {
+         // unknown type, report the error
+         fprintf (stderr, GTXT ("Error: Unknown Memory Object type: %s\n"), name);
+         return;
+       }
+      type = mot->type;
+    }
+  else
+    {
+      MemObjType_t *mot = MemorySpace::findMemSpaceByIndex (cparam);
+      if (mot == NULL)
+       {
+         // unknown type, report the error
+         fprintf (stderr, GTXT ("Error: Unknown Memory Object type: %s\n"), name);
+         return;
+       }
+      type = cparam;
+    }
+  dbePrintData (0, DSP_MEMOBJ, type, NULL, NULL, out_file);
+}
+
+void
+er_print::mo_define (char *moname, char *mo_index_exp, char *machmodel, char *short_desc, char *long_desc)
+{
+  char *ret = MemorySpace::mobj_define (moname, mo_index_exp, machmodel, short_desc, long_desc);
+  if (ret != NULL)
+    fprintf (stderr, GTXT ("mobj_define for %s failed: %s\n"), moname, ret);
+}
+
+void
+er_print::mo_list (bool showtab, FILE *outf)
+{
+  Vector<bool> *mtab = NULL;
+  Vector<void*>*res = MemorySpace::getMemObjects ();
+  if (showtab)
+    mtab = dbev->get_MemTabState ();
+  if (res == NULL)
+    // Since we checked already, this is an internal error
+    abort ();
+
+  // unpack the return
+  // Vector<char*> *index = (Vector<int> *)res->fetch(0);  // not used
+  Vector<char*> *mo_names = (Vector<char*> *)res->fetch (1);
+  // Vector<char*> *mnemonic = (Vector<char> *)res->fetch(2);  // not used
+  Vector<char*> *mo_expr = (Vector<char*> *)res->fetch (3);
+  Vector<char*> *mo_mach_m = (Vector<char*> *)res->fetch (4);
+  // Vector<char*> *tmpOrder = (Vector<int> *)res->fetch(5);  // not used
+
+  int size = mo_names->size ();
+  if (size == 0)
+    {
+      if (!getenv ("_BUILDING_MANPAGE"))
+       fprintf (outf, GTXT (" No Memory Object Types Defined\n"));
+    }
+  else
+    {
+      if (!getenv ("_BUILDING_MANPAGE"))
+       fprintf (outf, GTXT (" Memory Object Types Available:\n"));
+      else
+       fprintf (outf, GTXT ("*Memory Object Types*\n"));
+      for (int i = 0; i < size; i++)
+       {
+         if (mtab)
+           fprintf (outf, NTXT ("  %c %s\n"), mtab->fetch (i) ? 'T' : 'F',
+                    mo_names->fetch (i));
+         else
+           {
+             if (mo_mach_m->fetch (i) != NULL)
+               fprintf (outf, NTXT ("  %s\t\t\"%s\"\t\t(machinemodel: %s)\n"),
+                        mo_names->fetch (i), mo_expr->fetch (i), mo_mach_m->fetch (i));
+             else
+               fprintf (outf, NTXT ("  %s\t\t\"%s\"\n"),
+                        mo_names->fetch (i), mo_expr->fetch (i));
+           }
+       }
+    }
+  delete mo_names;
+  delete mo_expr;
+  delete mo_mach_m;
+  delete res;
+}
+
+void
+er_print::indxobj (char *name, int cparam)
+{
+  int type;
+  if (name != NULL)
+    {
+      // find the index object index for the name
+      type = dbeSession->findIndexSpaceByName (name);
+      if (type < 0)
+       {
+         // unknown type, report the error
+         fprintf (stderr, GTXT ("Error: Unknown Index Object type: %s\n"), name);
+         return;
+       }
+    }
+  else
+    {
+      char *indxname = dbeSession->getIndexSpaceName (cparam);
+      if (indxname == NULL)
+       {
+         // unknown type, report the error
+         fprintf (stderr, GTXT ("Error: Unknown Index Object type: %d\n"), cparam);
+         return;
+       }
+      type = cparam;
+    }
+  dbePrintData (0, DSP_INDXOBJ, type, NULL, NULL, out_file);
+}
+
+void
+er_print::indxo_define (char *ioname, char *io_index_exp, char *sdesc, char *ldesc)
+{
+  char *ret = dbeDefineIndxObj (ioname, io_index_exp, sdesc, ldesc);
+  if (ret != NULL)
+    fprintf (stderr, GTXT ("indxobj_define for %s failed: %s\n"), ioname, ret);
+}
+
+void
+er_print::indxo_list (bool showtab, FILE *outf)
+{
+  Vector<bool> *indxtab = NULL;
+  char *name;
+  char *i18n_name;
+  if (!getenv ("_BUILDING_MANPAGE"))
+    fprintf (outf, GTXT (" Index Object Types Available:\n"));
+  else
+    fprintf (outf, GTXT ("*Index Object Types*\n"));
+  Vector<void*>*res = dbeGetIndxObjDescriptions (0);
+  if (showtab)
+    indxtab = dbev->get_IndxTabState ();
+  if (res == NULL)  // If none is defined
+    return;
+  Vector<char*> *indxo_names = (Vector<char*> *)res->fetch (1);
+  Vector<char*> *indxo_i18nnames = (Vector<char*> *)res->fetch (3);
+  Vector<char*> *indxo_exprlist = (Vector<char*> *)res->fetch (5);
+  int size = indxo_names->size ();
+  for (int i = 0; i < size; i++)
+    {
+      name = indxo_names->fetch (i);
+      i18n_name = indxo_i18nnames->fetch (i);
+      if (indxtab)
+       {
+         if ((i18n_name != NULL) && (strcmp (i18n_name, name) != 0))
+           fprintf (outf, NTXT ("  %c %s (%s)\n"), indxtab->fetch (i) ? 'T' : 'F',
+                    i18n_name, name);
+         else
+           fprintf (outf, NTXT ("  %c %s\n"), indxtab->fetch (i) ? 'T' : 'F', name);
+       }
+      else
+       {
+         if (i18n_name != NULL && strcmp (i18n_name, indxo_names->fetch (i)) != 0)
+           fprintf (outf, NTXT ("  %s (%s)"), i18n_name, name);
+         else
+           fprintf (outf, NTXT ("  %s"), name);
+       }
+      char *exprs = indxo_exprlist->fetch (i);
+      if (exprs != NULL)
+       fprintf (outf, NTXT (" \t%s\n"), exprs);
+      else
+       fprintf (outf, NTXT ("\n"));
+    }
+  delete indxo_names;
+  if (showtab)
+    delete res;
+}
+
+void
+er_print::ifreq ()
+{
+  dbev->ifreq (out_file);
+}
+
+void
+er_print::dump_nodes ()
+{
+  dbev->dump_nodes (out_file);
+}
+
+void
+er_print::dump_stacks ()
+{
+  dbeSession->dump_stacks (out_file);
+}
+
+void
+er_print::dump_unk_pcs ()
+{
+  // Dump the nodes associated with the <Unknown> function
+  dbev->get_path_tree ()->dumpNodes (out_file, dbeSession->get_Unknown_Function ());
+
+  // Dump the nodes associated with the <no Java callstack recorded> function
+  Vector<Function *> *matches = dbeSession->match_func_names ("<no Java callstack recorded>", dbev->get_name_format ());
+  if (matches == NULL || matches->size () == 0)
+    fprintf (out_file, GTXT ("No %s functions found\n"), "<no Java callstack recorded>");
+  else
+    {
+      Function *fitem;
+      int index;
+      Vec_loop (Function*, matches, index, fitem)
+      {
+       dbev->get_path_tree ()->dumpNodes (out_file, fitem);
+      }
+      delete matches;
+    }
+}
+
+void
+er_print::dump_funcs (char *arg1)
+{
+  if (arg1 == NULL || strlen (arg1) == 0)
+    dbeSession->dump_segments (out_file);
+  else
+    {
+      Vector<Function *> *matches = dbeSession->match_func_names (arg1, dbev->get_name_format ());
+      if (matches == NULL)
+       {
+         fprintf (stderr, GTXT ("Invalid argument `%s' -- not a regular expression\n"), arg1);
+         return;
+       }
+      fprintf (out_file, GTXT ("%d Function's match `%s'\n"), (int) matches->size (), arg1);
+      Function *fitem;
+      int index;
+      Vec_loop (Function*, matches, index, fitem)
+      {
+       fprintf (out_file, NTXT (" %5lld -- %s (%s) [%s]\n"),
+                (ll_t) fitem->id, fitem->get_name (),
+                (fitem->module ? fitem->module->file_name : NTXT ("<unknown>")),
+                ((fitem->module && fitem->module->loadobject) ?
+                 get_basename (fitem->module->loadobject->get_name ()) : NTXT ("<unknown>")));
+      }
+      delete matches;
+    }
+}
+
+void
+er_print::dump_dataobjects (char *arg1)
+{
+  // Force computation of data objects, to update master table; discard it
+  MetricList *mlist1 = dbev->get_metric_list (MET_DATA);
+  Hist_data *data = dbev->get_hist_data (mlist1, Histable::DOBJECT, 0, Hist_data::ALL);
+  delete data;
+
+  if (arg1 == NULL || strlen (arg1) == 0)
+    dbeSession->dump_dataobjects (out_file);
+  else
+    {
+      Vector<DataObject *> *matches = dbeSession->match_dobj_names (arg1);
+      if (matches == NULL)
+       {
+         fprintf (stderr, GTXT ("Invalid argument `%s' -- not a regular expression\n"), arg1);
+         return;
+       }
+      fprintf (out_file, GTXT ("%d DataObject's match `%s'\n"), (int) matches->size (), arg1);
+      DataObject *ditem;
+      int index;
+      Vec_loop (DataObject*, matches, index, ditem)
+      {
+       fprintf (out_file, NTXT (" %5lld -- %s\n"), (ll_t) ditem->id, ditem->get_name ());
+      }
+      delete matches;
+    }
+}
+
+void
+er_print::dump_map ()
+{
+  dbeSession->dump_map (out_file);
+}
+
+void
+er_print::dump_entities ()
+{
+  int ent_prop_ids[] = {PROP_THRID, PROP_LWPID, PROP_CPUID, PROP_EXPID, -1};
+
+  // loop over experiments
+  for (int exp_id = 0; exp_id < dbeSession->nexps (); exp_id++)
+    {
+      Experiment *exp = dbeSession->get_exp (exp_id);
+      fprintf (out_file, GTXT ("Experiment %d (%s)\n"),
+              exp_id, exp->get_expt_name ());
+
+      for (int kk = 0; ent_prop_ids[kk] != -1; kk++)
+       {
+         int ent_prop_id = ent_prop_ids[kk];
+         Vector<void*> *elist = dbeGetEntities (0, exp_id, ent_prop_id);
+         if (!elist)
+           continue;
+         Vector<int> *entity_vals = (Vector<int> *) elist->fetch (0);
+         Vector<char*> *jthr_names = (Vector<char*> *)elist->fetch (1);
+         Vector<char*> *jthr_g_names = (Vector<char*> *)elist->fetch (2);
+         Vector<char*> *jthr_p_names = (Vector<char*> *)elist->fetch (3);
+         Vector<char*> *entity_name = (Vector<char*> *)elist->fetch (4);
+         int nent = entity_vals->size ();
+         char *entName = entity_name->fetch (0);
+         if (!entName)
+           entName = NTXT ("<unknown>");
+         fprintf (out_file, GTXT ("  %s\n"), entName);
+         for (int i = 0; i < nent; i++)
+             fprintf (out_file, GTXT ("    %s=%d: %s, %s, %s\n"),
+                      entName, entity_vals->fetch (i),
+                      jthr_names->fetch (i) != NULL ? jthr_names->fetch (i) : NTXT ("N/A"),
+                      jthr_g_names->fetch (i) != NULL ? jthr_g_names->fetch (i) : NTXT ("N/A"),
+                      jthr_p_names->fetch (i) != NULL ? jthr_names->fetch (i) : NTXT ("N/A"));
+         destroy (elist);
+       }
+    }
+}
+
+void
+er_print::dump_stats ()
+{
+  Emsg *m = dbev->get_path_tree ()->fetch_stats ();
+  while (m != NULL)
+    {
+      fprintf (out_file, NTXT ("%s\n"), m->get_msg ());
+      m = m->next;
+    }
+  dbev->get_path_tree ()->delete_stats ();
+}
+
+void
+er_print::dump_proc_warnings ()
+{
+  PathTree *p = dbev->get_path_tree ();
+  if (p == NULL)
+    return;
+  Emsg *m = p->fetch_warnings ();
+  while (m != NULL)
+    {
+      fprintf (out_file, NTXT ("%s\n"), m->get_msg ());
+      m = m->next;
+    }
+  dbev->get_path_tree ()->delete_warnings ();
+}
+
+void
+er_print::print_cmd (er_print_common_display *cd)
+{
+  cd->set_out_file (out_file);
+  cd->data_dump ();
+}
+
+FILE *
+er_print::set_outfile (char *cmd, FILE *&set_file, bool append)
+{
+  FILE *new_file;
+  char *home;
+  if (!strcasecmp (cmd, NTXT ("-")))
+    {
+      new_file = stdout;
+      out_fname = NTXT ("<stdout>");
+    }
+  else if (!strcasecmp (cmd, NTXT ("--")))
+    {
+      new_file = stderr;
+      out_fname = NTXT ("<stderr>");
+    }
+  else
+    {
+      char *fname;
+      char *path = NULL;
+      // Handle ~ in file names
+      home = getenv (NTXT ("HOME"));
+      if ((fname = strstr (cmd, NTXT ("~/"))) != NULL && home != NULL)
+       path = dbe_sprintf (NTXT ("%s/%s"), home, fname + 2);
+      else if ((fname = strstr (cmd, NTXT ("~"))) != NULL && home != NULL)
+       path = dbe_sprintf (NTXT ("/home/%s"), fname + 1);
+      else
+       path = strdup (cmd);
+      new_file = fopen (path, append ? NTXT ("a") : NTXT ("w"));
+      if (new_file == NULL)
+       {
+         fprintf (stderr, GTXT ("Error: Unable to open file: %s\n"), cmd);
+         free (path);
+         return NULL;
+       }
+      out_fname = path;
+    }
+  if (set_file && set_file != stdout)
+    fclose (set_file);
+  set_file = new_file;
+  return set_file;
+}
diff --git a/gprofng/src/gp-print.h b/gprofng/src/gp-print.h
new file mode 100644 (file)
index 0000000..80c922f
--- /dev/null
@@ -0,0 +1,118 @@
+/* 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 _GP_PRINT_H
+#define _ER_PRINT_H
+
+#include "Command.h"
+#include "DbeApplication.h"
+#include "Histable.h"
+#include "Print.h"
+
+void ipc_mainLoop (int argc, char *argv[]);
+
+class DbeView;
+template <class ITEM> class Vector;
+
+// er_print object
+class er_print : public DbeApplication
+{
+public:
+
+  er_print (int argc, char *argv[]);
+  virtual ~er_print ();
+  void start (int argc, char *argv[]);
+  bool free_memory_before_exit ();
+
+private:
+
+  char *error_msg;
+  DbeView *dbev;
+  char *out_fname;
+  FILE *inp_file;
+  FILE *dis_file;
+  FILE *out_file;
+  int dbevindex;
+  char *cov_string;
+  int limit;
+  Vector<Histable*> *cstack;
+  bool was_QQUIT;
+
+  // override methods in base class
+  int check_args (int argc, char *argv[]);
+  void usage ();
+
+  int is_valid_seg_name (char *seg_name, int prev);
+  int cmp_seg_name (char *full_name, char *seg_name);
+  int process_object_select (char *cov);
+  int set_libexpand (char *cov, enum LibExpand expand);
+  int set_libdefaults ();
+
+  bool end_command (char *cmd);
+  void run (int argc, char *argv[]);
+  void proc_script ();
+  void proc_cmd (CmdType cmd_type, int cparam, char *arg1, char *arg2,
+                char *arg3 = NULL, char *arg4 = NULL, bool xdefault = true);
+  void disp_list (int no_header, int size, int align[],
+                 char *header[], char **lists[]);
+  void exp_list ();
+  void describe ();
+  void obj_list ();
+  void seg_list ();
+  void print_objects ();
+  void print_overview ();
+  void print_overview_nodes (Vector<void*> *data, int level,
+                            Vector<char *> *metric_cmds, Vector<char *> *non_metric_cmds);
+  void print_overview_tree (Vector<void*> *data, int level, Vector<void*> *values,
+                           Vector<char *> *metric_cmds, Vector<char *> *non_metric_cmds);
+  void print_segments ();
+  void filter_list (CmdType cmd_type);
+  int check_exp_id (int exp_id, char *sel);
+  int get_exp_id (char *sel, int &bgn_index, int &end_index);
+  void print_func (Histable::Type type, Print_mode mode,
+                  MetricList *mlist1, MetricList *mlist2,
+                  char *func_name = NULL, char *sel = NULL);
+  void print_gprof (CmdType cmd_type, char *func_name, char *sel);
+  void print_ctree (CmdType cmd_type);
+  void print_dobj (Print_mode type, MetricList *mlist1,
+                  char *dobj_name = NULL, char *sel = NULL);
+  void memobj (char *, int);
+  void mo_list (bool showtab, FILE *outf);
+  void mo_define (char *, char *, char *, char *, char *);
+  void indxobj (char *, int);
+  void indxo_list (bool showtab, FILE *outf);
+  void indxo_define (char *, char *, char *, char *);
+  void ifreq ();
+  void dump_nodes ();
+  void dump_stacks ();
+  void dump_unk_pcs ();
+  void dump_funcs (char *);
+  void dump_dataobjects (char *);
+  void dump_map ();
+  void dump_entities ();
+  void dump_stats ();
+  void dump_proc_warnings ();
+  void send_signal ();
+  void print_cmd (er_print_common_display *);
+  FILE *set_outfile (char *cmd, FILE *&set_file, bool append);
+  void gen_mapfile (char *seg_name, char *cmd);
+};
+
+#endif /* _ER_PRINT_H */
diff --git a/gprofng/src/gprofng.cc b/gprofng/src/gprofng.cc
new file mode 100644 (file)
index 0000000..1bf5679
--- /dev/null
@@ -0,0 +1,301 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <getopt.h>
+
+#include "Application.h"
+#include "i18n.h"
+#include "util.h"
+
+static int verbose = 0;
+
+class Gprofng : Application
+{
+public:
+  Gprofng (int _argc, char *_argv[]);
+  ~Gprofng ();
+  void start();
+  void usage();
+
+private:
+  void exec_cmd(char *tool_name, int argc, char **argv);
+  int argc;
+  char **argv;
+};
+
+int
+main (int argc, char *argv[])
+{
+  Gprofng *gprofng = new Gprofng (argc, argv);
+  gprofng->start();
+  delete gprofng;
+  return 0;
+}
+
+Gprofng::Gprofng (int _argc, char *_argv[]) : Application(_argc, _argv, NULL)
+{
+  argc = _argc;
+  argv = _argv;
+}
+
+Gprofng::~Gprofng () { }
+
+void
+Gprofng::usage ()
+{
+  /*
+   * Isolate the first line because it has an argument.
+   * Otherwise it would be at the end of this long list.
+   */
+  printf ( GTXT (
+    "Usage: %s [OPTION(S)] COMMAND [KEYWORD] [ARGUMENTS]\n"), whoami);
+
+  printf ( GTXT (
+    "\n"
+    "This is the driver for the GPROFNG tools suite to gather and analyze performance data.\n"
+    "\n"
+    "Options:\n"
+    "\n"
+    " --version           print the version number and exit.\n"
+    " --help              print usage information and exit.\n"
+    " --check             verify if the hardware and software environment is supported.\n"
+    " --verbose {on|off}  enable (on) or disable (off) verbose mode; the default is \"off\".\n"
+    "\n"
+    "Commands:\n"
+    "\n"
+    "The driver supports various commands. These are listed below.\n"
+    "\n"
+    "It is also possible to invoke the lower level commands directly, but since these \n"
+    "are subject to change, in particular the options, we recommend to use the driver.\n"
+    "\n"
+    "The man pages for the commands below can be viewed using the command name with\n"
+    "\"gprofng\" replaced by \"gp\" and the spaces replaced by a dash (\"-\"). For\n"
+    "example the man page name for \"gprofng collect app\" is \"gp-collect-app\".\n"
+    "\n"
+    "The following combination of commands and keywords are supported:\n"
+    "\n"
+    "Collect performance data\n"
+    "\n"
+    " gprofng collect app     collect application performance data.\n"
+    "\n"
+    "Display the performance results\n"
+    "\n"
+    " gprofng display text    display the performance data in ASCII format.\n"
+    " gprofng display html    generate an HTML file from one or more experiments.\n"
+/*
+    " gprofng display gui     invoke the GUI to graphically analyze the results.\n"
+*/
+    " gprofng display src     display source or disassembly with compiler annotations.\n"
+    "\n"
+    "Miscellaneous commands\n"
+    "\n"
+    " gprofng archive         include binaries and source code in an experiment directory.\n"
+    "\n"
+    "Environment:\n"
+    "\n"
+    "The following environment variables are supported:\n"
+    "\n"
+    " GPROFNG_MAX_CALL_STACK_DEPTH  set the depth of the call stack (default is 256).\n"
+    "\n"
+    " GPROFNG_USE_JAVA_OPTIONS      may be set when profiling a C/C++ application\n"
+    "                               that uses dlopen() to execute Java code.\n"
+    "\n"
+    " GPROFNG_SSH_REMOTE_DISPLAY    use this variable to define the ssh command\n"
+    "                               executed by the remote display tool.\n"
+    "\n"
+    " GPROFNG_SKIP_VALIDATION       set this variable to disable checking hardware,\n"
+    "                               system, and Java versions.\n"
+    "\n"
+    " GPROFNG_ALLOW_CORE_DUMP       set this variable to allow a core file to be\n"
+    "                               generated; otherwise an error report is created on /tmp.\n"
+    "\n"
+    " GPROFNG_ARCHIVE               use this variable to define the settings for automatic\n"
+    "                               archiving upon experiment recording completion.\n"
+    "\n"
+    " GPROFNG_ARCHIVE_COMMON_DIR    set this variable to the location of the common archive.\n"
+    "\n"
+    " GPROFNG_JAVA_MAX_CALL_STACK_DEPTH  set the depth of the Java call stack; the default\n"
+    "                                    is 256; set to 0 to disable capturing of call stacks.\n"
+    "\n"
+    " GPROFNG_JAVA_NATIVE_MAX_CALL_STACK_DEPTH  set the depth of the Java native call stack;\n"
+    "                                           the default is 256; set to 0 to disable capturing\n"
+    "                                           of call stacks (JNI and assembly call stacks\n"
+    "                                           are not captured).\n"
+    "\n"
+    "Documentation:\n"
+    "\n"
+    "A getting started guide for gprofng is maintained as a Texinfo manual. If the info and\n"
+    "gprofng programs are properly installed at your site, the command \"info gprofng\"\n"
+    "should give you access to this document.\n"
+    "\n"
+    "See also:\n"
+    "\n"
+    "gp-archive(1), gp-collect-app(1), gp-display-html(1), gp-display-src(1), gp-display-text(1)\n"));
+
+/*
+  printf ( GTXT (
+    "Usage: %s [--verbose] [--version] [--help] <tool-name> [<keyword>] <args>\n"
+    "\n%s\n"
+    "   archive         Archive binaries and sources\n"
+    "   collect [app]   Collect performance data\n"
+    "   display [text]  Print an ASCII report\n"
+    "   display gui     Graphical tool for analyzing an experiment\n"
+    "   display html    Generate an HTML file from an experiment\n"
+    "   display src     Print source or dissasembly\n"),
+    whoami, getenv ("_BUILDING_MANPAGE")
+          ? "*Available subcommands*"
+          : "Available Subcommands");
+*/
+}
+
+void
+Gprofng::exec_cmd (char *tool_name, int argc, char **argv)
+{
+  static const struct
+  {
+    const char *tool_name;
+    const char *keyword;
+    const char *app_name;
+  } app_names [] = {
+    { "archive", NULL, "gp-archive"},
+    { "collect", "app", "gp-collect-app"},
+    { "collect", "kernel", "gp-collect-kernel"},
+    { "display", "text", "gp-display-text"},
+    { "display", "gui", "gp-display-gui"},
+    { "display", "html", "gp-display-html"},
+    { "display", "src", "gp-display-src"},
+    { NULL, NULL}
+  };
+
+  const char *keyword = argc > 1 ? argv[1] : "";
+  int first = -1;
+  int find_tool_name = -1;
+  for (int i = 0; app_names[i].tool_name; i++)
+    if (!strcmp (tool_name, app_names[i].tool_name))
+      {
+       if (app_names[i].keyword == NULL)
+         {
+           first = i;
+           break;
+         }
+       if (!strcmp (keyword, app_names[i].keyword))
+         {
+           first = i;
+           argc--;
+           argv++;
+           break;
+         }
+       if (find_tool_name == -1)
+         find_tool_name = i;
+      }
+
+  if (first == -1)
+    {
+      if (find_tool_name == -1)
+       fprintf (stderr, GTXT ("%s: error: keyword '%s' is not supported\n"),
+                get_basename (get_name ()), tool_name);
+      else if (*keyword == 0)
+       fprintf (stderr, GTXT ("%s %s: error: no qualifier\n"),
+                get_basename (get_name ()), tool_name);
+      else
+       fprintf (stderr, GTXT ("%s %s: error: qualifier '%s' is not supported\n"),
+                get_basename (get_name ()), tool_name, keyword);
+      exit (1);
+    }
+
+  const char *aname = app_names[first].app_name;;
+
+  char **arr = (char **) malloc ((argc + 3) * sizeof (char *));
+  int n = 0;
+  char *pname = get_name ();
+  arr[n++] = dbe_sprintf ("%.*s%s", (int) (get_basename (pname) - pname),
+                           pname, aname);
+  if (app_names[first].keyword)
+    arr[n++] = dbe_sprintf ("--whoami=%s %s %s", whoami, tool_name,
+                           app_names[first].keyword);
+  else
+    arr[n++] = dbe_sprintf ("--whoami=%s %s", whoami, tool_name);
+  for (int i = 1; i < argc; i++)
+    arr[n++] = argv[i];
+  arr[n] = NULL;
+  if (verbose)
+    {
+      printf ("gprofng::exec\n");
+      for (int i = 0; arr[i]; i++)
+       printf ("%5d: %s\n", i, arr[i]);
+      printf("\n");
+    }
+  execv (arr[0], arr);
+
+  // If execv returns, it must have failed.
+  fprintf (stderr, GTXT ("%s failed: %s\n"), arr[0], STR (strerror (errno)));
+  exit(1);
+}
+
+void
+Gprofng::start ()
+{
+  if (argc == 1)
+    {
+      usage ();
+      exit (0);
+    }
+  for (int i = 1; i < argc; i++)
+    {
+      char *s = argv[i];
+      if (*s != '-')
+       {
+         exec_cmd(s, argc - i, argv + i);
+         return;
+       }
+      else if (!strcmp (s, "--help"))
+       {
+         usage ();
+         exit (0);
+       }
+      else if (!strcmp (s, "--version") || !strcmp (s, "-v"))
+       {
+          Application::print_version_info ();
+          exit (0);
+       }
+      else if (!strcmp (s, "--verbose"))
+       verbose = 1;
+      else if (!strcmp (s, "--check"))
+       {
+         fprintf (stderr, GTXT ("%s: error: --check is not implemented yet\n"),
+                  get_basename (get_name ()));
+         exit (1);
+       }
+      else
+       {
+         fprintf (stderr, GTXT ("%s: error: unknown option %s\n"),
+                  get_basename (get_name ()), s);
+         exit(1);
+       }
+    }
+  fprintf (stderr, GTXT ("%s: error: expected argument after options\n"),
+          get_basename (get_name ()));
+}
diff --git a/gprofng/src/gprofng.h2m b/gprofng/src/gprofng.h2m
new file mode 100644 (file)
index 0000000..8786768
--- /dev/null
@@ -0,0 +1,4 @@
+[SEE ALSO]
+
+.B
+\fBgprofng-archive\fR(1), \fBgprofng-collect\fR(1), \fBgprofng-display-text\fR(1), \fBgprofng-display-src\fR(1), \fBgprofng-display-html\fR(1), \fBgprofng-display-gui\fR(1)
diff --git a/gprofng/src/gprofng.rc b/gprofng/src/gprofng.rc
new file mode 100644 (file)
index 0000000..3870220
--- /dev/null
@@ -0,0 +1,132 @@
+#   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/>.
+#
+# Specify which classes of compiler commentary will be shown
+# with annotated source.
+scc all
+
+# Specify which classes of compiler commentary will be shown
+# with annotated disassembly
+dcc all:src
+
+# Set the default function-list metrics
+# for heap data, show inclusive leaks and bytes leaked; not allocations
+dmetrics i.heapleakbytes:e!heapleakbytes
+dmetrics i.heapleakcnt:e!heapleakcnt
+dmetrics i.heapallocbytes:e!heapallocbytes
+dmetrics i.heapalloccnt:e!heapalloccnt:
+
+# Clock profiling data
+#   Note: use same display order of LMS_* in: er.rc, TimelineVariable.java, 
+#     Ovw_data.h, BaseMetricTreeNode.cc and Experiment.cc metric registration
+dmetrics i!total:e!.total
+#   Show total cpu time
+dmetrics ei.totalcpu
+dmetrics i!.user:e!.user
+dmetrics i!system:e!.system
+dmetrics i!trap:e!.trap
+dmetrics i!lock:e!.lock
+dmetrics i!datapfault:e!.datapfault
+dmetrics i!textpfault:e!.textpfault
+dmetrics i!kernelpfault:e!.kernelpfault
+dmetrics i!stop:e!.stop
+dmetrics i!wait:e!.wait
+dmetrics i!sleep:e!.sleep
+
+# for kernel clock profiling data, show inclusive and exclusive KCPU
+dmetrics ei.kcpu
+###dmetrics ie.kcpu
+
+# for count data, show exclusive metrics only
+dmetrics i!bit:e.bit
+
+# for er_generic data, show exclusive metrics only
+dmetrics i!icount:e.icount
+
+# Hide implementation hack. Functionmark column only serves
+# to force zero-count functions to be displayed.
+dmetrics e!bit_FM
+
+# for kernel profiles, show inclusive and exclusive kucycles and kcycles
+# (kucycles and kcycles are for 12.3 and older experiments, Obsolete TBR)
+dmetrics ei.kucycles:ei.kcycles
+###dmetrics ie.kucycles:ie.kcycles
+
+# for derived HWC metrics, show exclusive only
+dmetrics i!IPC:e!.IPC
+dmetrics i!CPI:e!.CPI
+dmetrics i!K_IPC:e!.K_IPC
+dmetrics i!K_CPI:e!.K_CPI
+
+# for HWC, show exclusive only
+dmetrics i!hwc:e.hwc
+
+# for synctrace, show inclusive only
+dmetrics i.sync:e!sync
+dmetrics i.syncn:e!syncn
+
+# Set the default function-list metrics for OMP profiling
+dmetrics i.ompwork:e!ompwork
+dmetrics i.ompwait:e!ompwait
+dmetrics i!.masterthread:e!.masterthread
+
+#set the default function-list metrics for deadlock detection
+dmetrics i!deadlocks:e.deadlocks
+
+# io data
+dmetrics i.ioreadtime:e!ioreadtime
+dmetrics i.iowritetime:e!iowritetime
+dmetrics i.ioothertime:e!ioothertime
+dmetrics i.ioerrortime:e!ioerrortime
+dmetrics i!.ioreadcnt:e!ioreadcnt
+dmetrics i!.ioreadbytes:e!ioreadbytes
+dmetrics i!.iowritecnt:e!iowritecnt
+dmetrics i!.iowritebytes:e!iowritebytes
+dmetrics i!.ioothercnt:e!ioothercnt
+dmetrics i!.ioerrorcnt:e!ioerrorcnt
+
+# for any other unnamed metrics, don't show them
+dmetrics ie!.any
+
+# don't show size or address; show name
+dmetrics !size:!address:name
+
+# Select the default function-list sorting metric
+dsort ei.any:name
+###dsort ie.any:name
+
+# Set function name style
+name long
+
+# Set View mode to user
+viewmode user
+
+# Set compare mode
+compare off
+
+# Set enabling descendants to on
+en_desc on
+
+# Set path where the gprofng libraries are installed
+preload_libdirs ../lib:../lib32:../lib64
+
+# Add search path for annotated source and disasm
+addpath $expts:.
+
+# Add controls for specific load objects
+#  object_hide <Unknown>
+
+# version "@(#)er.rc 1.62 11/10/31"
diff --git a/gprofng/src/i18n.cc b/gprofng/src/i18n.cc
new file mode 100644 (file)
index 0000000..32c9960
--- /dev/null
@@ -0,0 +1,30 @@
+/* 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 "i18n.h"
+
+extern "C"
+void
+init_locale (char *Path) //set up for internationalization
+{
+  bindtextdomain (PACKAGE_NAME, LOCALEDIR);
+  textdomain (PACKAGE_NAME);
+}
diff --git a/gprofng/src/i18n.h b/gprofng/src/i18n.h
new file mode 100644 (file)
index 0000000..d02ec0e
--- /dev/null
@@ -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.  */
+
+#ifndef _I18N_H
+#define _I18N_H
+
+#include <libintl.h>
+
+#define GTXT(x) gettext(x)      /* x - string literal to be i18n-ed */
+#define PTXT(x) gettext(x)      /* x - expression to be i18n-ed */
+#define STXT(x) ((char *) (x))  /* x - static string literal to be i18n-ed */
+#define NTXT(x) ((char *) (x))  /* x - string literal not to be i18n-ed */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+  void init_locale (char *Path);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _I18N_H */
diff --git a/gprofng/src/info.h b/gprofng/src/info.h
new file mode 100644 (file)
index 0000000..5b05833
--- /dev/null
@@ -0,0 +1,73 @@
+/* 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 _INFO_H
+#define _INFO_H
+
+/* Header file for .info section format */
+#include <inttypes.h>
+
+/* The format of the .info section from a single object file is:
+ * Fixed-length info_header
+ * Variable length string padded to a multiple of 4 bytes, giving
+ *  the name of the source file from which this contribution comes.
+ * Zero or more entries.
+ *
+ * In an executable, there will be multiple occurrences of the above.
+ * The size of the info section will be a multiple of 4 bytes.
+ */
+
+struct info_header
+{
+  char endian;      /* 0 for big, 1 for little */
+  char magic[3];    /* The string "SUN" */
+  uint32_t cnt;     /* number of entries for this section */
+  uint16_t len;     /* The length of the header, including the string */
+  uint16_t version; /* The version number of this block */
+  uint16_t phase;   /* The compiler phase that produced this info */
+  uint16_t spare;
+};
+
+#define PHASE_UNKNOWN       0
+#define PHASE_F77           1
+#define PHASE_CC            2
+#define PHASE_CPLUS         3
+#define PHASE_F95           4
+#define PHASE_IROPT         5
+#define PHASE_MAX           255
+#define F95_COPYINOUT       ((PHASE_F95 << 24) | 1)
+
+/* An entry consists of a fixed-size struct entry, possibly followed by
+ * a variable length data structure whose format is determined by the
+ * type of an entry. The size of an entry is a multiple of 4 bytes.
+ */
+
+struct entry_header
+{
+  uint32_t type;    /* The type of this entry. High 8 bits is the phase.
+                    * Low 24 bits is the type. */
+  uint16_t len;     /* length of this entry */
+  uint16_t col;     /* Column number in source line */
+  uint32_t msgnum;  /* Message number. High 8 bits is the phase.
+                    * Low 24 bits is the type. */
+  uint32_t line;    /* Line number in source file */
+};
+
+#endif
diff --git a/gprofng/src/ipc.cc b/gprofng/src/ipc.cc
new file mode 100644 (file)
index 0000000..932423c
--- /dev/null
@@ -0,0 +1,2829 @@
+/* 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 <stdio.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <fcntl.h>      // creat
+#include <unistd.h>     // sleep
+#include <pthread.h>    // pthread_exit
+#include <sys/wait.h>   // wait
+#include <locale.h>
+
+#include "DbeApplication.h"
+#include "Histable.h"
+#include "ipcio.h"
+#include "Dbe.h"
+#include "DbeSession.h"
+#include "DbeThread.h"
+#include "DbeView.h"
+
+int ipc_flags = 0;
+IPCTraceLevel ipc_trace_level = TRACE_LVL_0;
+int ipc_single_threaded_mode = 0;
+const char *IPC_PROTOCOL_UNKNOWN = "IPC_PROTOCOL_UNKNOWN";
+const char *IPC_PROTOCOL_CURR = IPC_PROTOCOL_STR;
+char const *ipc_protocol = NULL;
+
+DbeThreadPool *ipcThreadPool;
+
+extern int currentRequestID;
+extern int currentChannelID;
+extern BufferPool *responseBufferPool;
+extern bool cancelNeeded (int);
+extern void reexec ();
+
+/* Simple implementation of support for cancel of open experiment. Since we have only one cancellable
+   operation supported at this moment, we are using just a global variable.
+   As we support more and more cancellable ops we need a more sophisticated data struture such
+   as a mt-safe array to keep track of all cancellable requests/channels and update the supporting
+   routines - setCancellableChannel, cancelNeeded (in ipcio.cc) setCancelRequestedCh */
+int cancellableChannelID = 0xFFFFFFFF;
+int cancelRequestedChannelID;
+
+static const char *table_name (int);
+
+#define VSIZE(v)        ((long long) ((v) ? (v)->size() : 0))
+
+inline const char*
+bool2str (bool v)
+{
+  return v ? "true" : "false";
+}
+
+inline char*
+str2str (String v)
+{
+  return (char*) (v ? v : "NULL");
+}
+
+inline char*
+str2s (String v)
+{
+  return (char*) (v ? v : "");
+}
+
+inline DbeView *
+getView (int index)
+{
+  return dbeSession->getView (index);
+}
+
+extern "C"
+{
+  typedef void (*SignalHandler)(int);
+}
+
+/*
+ * Fatal error handlers
+ */
+extern "C" void fatalErrorHadler (int sig, siginfo_t *info, void *context);
+extern "C" void sigSEGV_handler (int sig, siginfo_t *info, void *context);
+extern "C" void sigABRT_handler (int sig, siginfo_t *info, void *context);
+static char fatalErrorBuffer1[1024 * 8];
+static char fatalErrorBuffer2[1024 * 8];
+static int fatalErrorCode = 1;
+static int fatalErrorCounter = 0;
+static void *fatalErrorContext = 0;
+static siginfo_t *fatalErrorInfo = 0;
+static char *fatalErrorDynamicMemory = NULL;
+
+extern "C" void
+fatalErrorHadler (int sig, siginfo_t *info, void *context)
+{
+  if (fatalErrorCounter > 0)
+    { // Need synchronization here
+      //sleep(10); // Wait 10 seconds to make sure previous processing is done
+      return; // exit(fatalErrorCode); // Already in processing
+    }
+  fatalErrorCounter = 1;
+  fatalErrorCode = sig;
+  fatalErrorContext = context;
+  fatalErrorInfo = info;
+  // Free reserved memory
+  if (fatalErrorDynamicMemory != NULL)
+    {
+      free (fatalErrorDynamicMemory);
+      fatalErrorDynamicMemory = NULL;
+    }
+  // Get process ID
+  pid_t pid = getpid ();
+  // Create dump file
+  snprintf (fatalErrorBuffer1, sizeof (fatalErrorBuffer1), "/tmp/analyzer.%lld",
+           (long long) pid);
+  mkdir (fatalErrorBuffer1, 0700);
+  snprintf (fatalErrorBuffer1, sizeof (fatalErrorBuffer1),
+           "/tmp/analyzer.%lld/crash.sig%d.%lld", (long long) pid, sig,
+           (long long) pid);
+  // Dump stack trace in background using pstack
+  snprintf (fatalErrorBuffer2, sizeof (fatalErrorBuffer2),
+           "/usr/bin/pstack %lld > %s.pstack", (long long) pid, fatalErrorBuffer1);
+  system (fatalErrorBuffer2);
+  int fd = creat (fatalErrorBuffer1, 0600);
+  if (fd >= 0)
+    {
+      // Write error message
+      snprintf (fatalErrorBuffer2, sizeof (fatalErrorBuffer2),
+               "A fatal error has been detected by er_print: Signal %lld\n",
+               (long long) sig);
+      write (fd, fatalErrorBuffer2, strlen (fatalErrorBuffer2));
+//      snprintf (fatalErrorBuffer2, sizeof (fatalErrorBuffer2),
+//                "If you would like to submit a bug report, please use your support contract.\n"));
+//      write(fd, fatalErrorBuffer2, strlen(fatalErrorBuffer2));
+      snprintf (fatalErrorBuffer2, sizeof (fatalErrorBuffer2),
+               "Protocol Version: %d\n", IPC_VERSION_NUMBER);
+      write (fd, fatalErrorBuffer2, strlen (fatalErrorBuffer2));
+      close (fd);
+      // Send postmortem error message to the GUI
+      // snprintf(fatalErrorBuffer1, sizeof (fatalErrorBuffer1),
+      //         "%s: %s: /tmp/analyzer.%lld",
+      //         "Unexpected signal in er_print",
+      //         "Crash dump",
+      //         (long long) pid);
+      // res = write(2, fatalErrorBuffer2, strlen(fatalErrorBuffer1));
+    }
+  wait (0); // wait for pstack
+  //sleep(10); // Wait 10 seconds to make sure processing of fatal error is done
+  // Exit with correct status
+  exit (fatalErrorCode);
+}
+
+// SIGABRT Handler
+extern "C" void
+sigABRT_handler (int sig, siginfo_t *info, void *context)
+{
+  fatalErrorHadler (sig, info, context);
+  pthread_exit (&fatalErrorCode);
+}
+
+// SIGSEGV Handler
+extern "C" void
+sigSEGV_handler (int sig, siginfo_t *info, void *context)
+{
+  //if (fatalErrorCounter > 0) sleep(1); // Wait 1 second
+  fatalErrorHadler (sig, info, context);
+  pthread_exit (&fatalErrorCode);
+}
+
+// SIGTERM Handler
+extern "C" void sigterm_handler (int sig, siginfo_t *info, void *context);
+struct sigaction old_sigterm_handler;
+
+volatile int term_flag;
+int error_flag;
+
+extern "C" void
+sigterm_handler (int, siginfo_t *, void *)
+{
+  if (fatalErrorCounter > 0)
+    {
+      //sleep(10); // Wait 10 seconds to make sure processing of fatal error is done
+      //return; // Fatal error processing will exit it
+      pthread_exit (&fatalErrorCode);
+    }
+  term_flag = 1;
+}
+
+#define ipc_log ipc_default_log
+#define ipc_request_trace ipc_request_log
+#define ipc_response_trace ipc_response_log
+static const char *ipc_log_name = NULL;
+static const char *ipc_request_log_name = NULL;
+static const char *ipc_response_log_name = NULL;
+FILE *requestLogFileP = stderr;
+FILE *responseLogFileP = stderr;
+hrtime_t begin_time;
+long long delta_time = 0;
+int ipc_delay_microsec = 0;
+
+void
+ipc_default_log (const char *fmt, ...)
+{
+  if (!ipc_log_name || !ipc_flags)
+    return;
+  if (ipc_trace_level >= TRACE_LVL_3)
+    {
+      hrtime_t cur_time = gethrtime ();
+      unsigned long long time_stamp = (cur_time - begin_time) / 1000000 + delta_time;
+      fprintf (stderr, "%7llu: ", time_stamp);
+    }
+  va_list vp;
+  va_start (vp, fmt);
+  vfprintf (stderr, fmt, vp);
+  va_end (vp);
+  fflush (stderr);
+}
+
+extern "C" void sigint_handler (int sig, siginfo_t *info, void *context);
+struct sigaction old_sigint_handler;
+
+extern "C" void
+sigint_handler (int, siginfo_t *, void *)
+{
+  ipc_log ("SIGINT signal happens\n");
+}
+
+void
+ipc_request_log (IPCTraceLevel trace_level, const char *fmt, ...)
+{
+  if (!ipc_request_log_name || !ipc_flags || trace_level > ipc_trace_level)
+    return;
+  fprintf (responseLogFileP, "thr: %llu ", (unsigned long long) pthread_self ());
+  if (ipc_trace_level >= TRACE_LVL_3)
+    {
+      hrtime_t cur_time = gethrtime ();
+      unsigned long long time_stamp = (cur_time - begin_time) / 1000000 + delta_time;
+      fprintf (requestLogFileP, "%7llu: ", time_stamp);
+    }
+  va_list vp;
+  va_start (vp, fmt);
+  vfprintf (requestLogFileP, fmt, vp);
+  va_end (vp);
+  fflush (requestLogFileP);
+}
+
+void
+ipc_response_log (IPCTraceLevel trace_level, const char *fmt, ...)
+{
+  if (!ipc_response_log_name || !ipc_flags || trace_level > ipc_trace_level)
+    return;
+  fprintf (responseLogFileP, "thr: %llu ", (unsigned long long) pthread_self ());
+  if (ipc_trace_level >= TRACE_LVL_3)
+    {
+      hrtime_t cur_time = gethrtime ();
+      unsigned long long time_stamp = (cur_time - begin_time) / 1000000 + delta_time;
+      fprintf (responseLogFileP, "%7llu: ", time_stamp);
+    }
+  va_list vp;
+  va_start (vp, fmt);
+  vfprintf (responseLogFileP, fmt, vp);
+  va_end (vp);
+  fflush (responseLogFileP);
+}
+
+#ifdef IPC_LOG
+void
+ipc_dump (char *s, Vector<bool> *v)
+{
+  if (v == NULL)
+    {
+      ipc_log ("    Vector<bool> %s is NULL\n", str2s (s));
+      return;
+    }
+  ipc_log ("    Vector<bool> %s size=%lld\n", str2s (s), VSIZE (v));
+  for (int i = 0; i < v->size (); i++)
+    ipc_log ("      [%d]: %s\n", i, bool2str (v->fetch (i)));
+}
+
+void
+ipc_dump (char *s, Vector<String> *v)
+{
+  if (v == NULL)
+    {
+      ipc_log ("    Vector<bool> %s is NULL\n", str2s (s));
+      return;
+    }
+  ipc_log ("    Vector<String> %s size=%lld\n", str2s (s), VSIZE (v));
+  for (int i = 0; i < v->size (); i++)
+    {
+      String str = v->fetch (i);
+      ipc_log ("      [%d]: '%s'\n", i, str2str (str));
+    }
+}
+
+void
+ipc_dump (char *s, Vector<Obj> *v)
+{
+  if (v == NULL)
+    {
+      ipc_log ("    Vector<Obj> %s is NULL\n", str2s (s));
+      return;
+    }
+  ipc_log ("    Vector<void *> %s size=%lld\n", str2s (s), VSIZE (v));
+  for (int i = 0; i < v->size (); i++)
+    ipc_log ("      [%d]: 0x%08llx\n", i, (long long) (v->fetch (i)));
+}
+
+#else
+#define ipc_dump(s, v)
+#endif
+
+static MetricList *
+readMetricListV2 (int dbevindex, IPCrequest* req)
+{
+  MetricType mtype = (MetricType) readInt (req);
+  Vector<int> *type = (Vector<int>*)readArray (req);
+  Vector<int> *subtype = (Vector<int>*)readArray (req);
+  Vector<bool> *sort = (Vector<bool>*)readArray (req);
+  Vector<int> *vis = (Vector<int>*)readArray (req);
+  Vector<char*> *cmd = (Vector<char*>*)readArray (req);
+  Vector<char*> *expr_spec = (Vector<char*>*)readArray (req);
+  Vector<char*> *legends = (Vector<char*>*)readArray (req);
+  MetricList *mlist = dbeGetMetricListV2 (dbevindex, mtype, type, subtype, sort,
+                                         vis, cmd, expr_spec, legends);
+  return mlist;
+}
+
+static void
+setCancellableChannel (int chID)
+{
+  cancellableChannelID = chID;
+}
+
+/* Add more entries here for other cancellable operations */
+static void
+checkCancellableOp (char *inp, IPCrequest* req)
+{
+  if (!strcmp (inp, "setFilterStr"))
+    setCancellableChannel (currentChannelID);
+  else if (!strcmp (inp, "openExperimentList"))
+    setCancellableChannel (currentChannelID);
+  else if (!strcmp (inp, "getFiles") || !strcmp (inp, "getFileAttributes"))
+    {
+      setCancellableChannel (currentChannelID);
+      req->setCancelImmediate ();
+    }
+}
+
+/* This is what used to be the core of ipc_mainLoop before asynch ipc.
+   Read the details of the request from the request buffer: name, args etc
+   do the work by calling the appropriate dbe routine(s) and write the
+   response to a response buffer and queue it up in the response queue */
+
+int
+ipc_doWork (void *arg)
+{
+  IPCrequest *req = (IPCrequest *) arg;
+  currentRequestID = req->getRequestID ();
+  currentChannelID = req->getChannelID ();
+  req->setStatus (IN_PROGRESS);
+  String inp = readString (req);
+  if (inp == NULL)
+    {
+      ipc_log ("NULL ipc command received, exiting\n");
+      return 0;
+    }
+  ipc_log ("ipc: %s Req %x Ch %x\n", inp, currentRequestID, currentChannelID);
+  checkCancellableOp (inp, req);
+  if (!strcmp (inp, "initApplication"))
+    {
+      bool nbm = readBoolean (req);
+      String arg1 = readString (req);
+      String arg2 = readString (req);
+      Vector<String> *arg3 = (Vector<String>*)readArray (req);
+      ipc_log ("  nbm: %s, arg1: '%s', arg2: '%s'\n", bool2str (nbm), str2str (arg1), str2str (arg2));
+      ipc_dump ("arg3", arg3);
+      // set the session to be interactive
+      dbeSession->set_interactive (true);
+      if (nbm)
+       theApplication->set_name ("analyzer-NBM");
+      else
+       theApplication->set_name ("analyzer");
+
+         // XXX Why does it reset the install directory????  Or a licensing directory???
+      // Vector<String> *res = theDbeApplication->initApplication (arg1, arg2, &setProgress);
+      Vector<String> *res = theDbeApplication->initApplication (NULL, NULL, &setProgress);
+      writeArray (res, req);
+      free (arg1);
+      free (arg2);
+      destroy (arg3);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "syncTime"))
+    {
+      long long anl_time = readLong (req);
+      hrtime_t cur_time = gethrtime ();
+      long long time_stamp = (cur_time - begin_time) / 1000000;
+      delta_time = anl_time - time_stamp;
+      ipc_log (" syncTime %llu %llu \n", anl_time, delta_time);
+      writeString (NULL, req);
+    }
+  else if (!strcmp (inp, "getInitMessages"))
+    {
+      Vector<String> *res = dbeGetInitMessages ();
+      ipc_log ("  returned = %lld msgs\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "reExec"))
+    {
+      ipc_log ("  started reexec()\n");
+      reexec ();
+    }
+  else if (!strcmp (inp, "dbeCreateDirectories"))
+    {
+      String arg1 = readString (req); // path
+      ipc_log ("  arg = %s\n", arg1);
+      String res = dbeCreateDirectories (arg1);
+      writeString (res, req);
+      free (arg1);
+      free (res);
+    }
+  else if (!strcmp (inp, "dbeDeleteFile"))
+    {
+      String arg1 = readString (req); // path
+      ipc_log ("  arg = %s\n", arg1);
+      String res = dbeDeleteFile (arg1);
+      writeString (res, req);
+      free (arg1);
+      free (res);
+    }
+  else if (!strcmp (inp, "dbeReadFile"))
+    {
+      String arg1 = readString (req);
+      ipc_log ("  arg = %s\n", arg1); // path
+      Vector<String> *res = dbeReadFile (arg1);
+      writeArray (res, req);
+      free (arg1);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "dbeWriteFile"))
+    {
+      String arg1 = readString (req); // path
+      String arg2 = readString (req); // contents
+      ipc_log ("  arg1 = %s  arg2 = %s\n", arg1, arg2);
+      int res = dbeWriteFile (arg1, arg2);
+      writeInt (res, req);
+      free (arg1);
+    }
+  else if (!strcmp (inp, "getExpPreview"))
+    {
+      // XXX add another argument == DbeView index
+      String arg1 = readString (req);
+      ipc_log ("  arg = %s\n", arg1);
+      Vector<String> *res = dbeGetExpPreview (0, arg1);
+      writeArray (res, req);
+      free (arg1);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getFileAttributes"))
+    {
+      String arg1 = readString (req); // filename
+      String arg2 = readString (req); // format
+      ipc_log ("  arg1 = %s  arg2 = %s\n", arg1, arg2);
+      String res = dbeGetFileAttributes (arg1, arg2);
+      writeString (res, req);
+      free (arg1);
+      free (arg2);
+      free (res);
+    }
+  else if (!strcmp (inp, "getFiles"))
+    {
+      String arg1 = readString (req); // dirname
+      String arg2 = readString (req); // format
+      ipc_log ("  arg1 = %s  arg2 = %s\n", arg1, arg2);
+      String res = dbeGetFiles (arg1, arg2);
+      writeString (res, req);
+      free (arg1);
+      free (arg2);
+      free (res);
+    }
+  else if (!strcmp (inp, "getOSFamily"))
+    writeString ("Linux", req);
+  else if (!strcmp (inp, "getRunningProcesses"))
+    {
+      String arg1 = readString (req); // format
+      ipc_log ("  arg = %s\n", arg1);
+      String res = dbeGetRunningProcesses (arg1);
+      writeString (res, req);
+      free (arg1);
+      free (res);
+    }
+  else if (!strcmp (inp, "getCurrentDirectory"))
+    {
+      char buf [2048];
+      String res = getcwd (buf, (size_t) sizeof (buf)); // Get current directory
+      writeString (res, req);
+    }
+  else if (!strcmp (inp, "getHomeDirectory"))
+    {
+      String res = getenv ("HOME"); // Get HOME directory
+      writeString (res, req);
+    }
+  else if (!strcmp (inp, "setCurrentDirectory"))
+    {
+      String arg1 = readString (req); // dirname
+      ipc_log ("  arg = %s\n", arg1);
+      int res = chdir (arg1); // Change directory
+      writeInt (res, req);
+      free (arg1);
+    }
+  else if (!strcmp (inp, "getLocale"))
+    {
+      String res = setlocale (LC_ALL, ""); // Get locale
+      writeString (res, req);
+    }
+  else if (!strcmp (inp, "setLocale"))
+    {
+      String arg1 = readString (req); // locale
+      ipc_log ("  arg = %s\n", arg1);
+      String res = setlocale (LC_ALL, arg1); // Set locale
+      writeString (res, req);
+      free (arg1);
+    }
+  else if (!strcmp (inp, "readRCFile"))
+    {
+      int arg1 = readInt (req);
+      String arg2 = readString (req); // file name
+      ipc_log ("  arg1=%d, arg2=%s\n", arg1, arg2);
+      String res = dbeReadRCFile (arg1, arg2); // Read RC File
+      writeString (res, req);
+      free (res);
+    }
+  else if (!strcmp (inp, "dbeGetExpParams"))
+    {
+      // XXX add another argument == DbeView index
+      String arg1 = readString (req);
+      ipc_log ("  arg = %s\n", arg1);
+      String res = dbeGetExpParams (0, arg1);
+      writeString (res, req);
+      free (arg1);
+      free (res);
+    }
+  else if (!strcmp (inp, "getExperimentsGroups"))
+    {
+      Vector<Vector<char*>*> *groups = dbeGetExperimensGroups ();
+      writeArray (groups, req);
+      destroy (groups);
+    }
+  else if (!strcmp (inp, "setExperimentsGroups"))
+    {
+      Vector<Vector<char*>*> *groups = (Vector<Vector<char*>*> *)readArray (req);
+      ipc_log ("  groups.size = %lld\n", VSIZE (groups));
+      char *msg_str = dbeSetExperimentsGroups (groups);
+      writeString (msg_str, req);
+      free (msg_str);
+      destroy (groups);
+    }
+  else if (!strcmp (inp, "dropExperiment"))
+    {
+      int arg1 = readInt (req);
+      Vector<int> *arg2 = (Vector<int>*)readArray (req);
+      ipc_log ("  arg = %d, exps = %lld\n", arg1, VSIZE (arg2));
+      char *res = dbeDropExperiment (arg1, arg2);
+      writeString (res, req);
+      free (res);
+      delete arg2;
+    }
+  else if (!strcmp (inp, "getUserExpId"))
+    {
+      Vector<int> *arg = (Vector<int>*)readArray (req);
+      ipc_log ("  expIds = %lld\n", VSIZE (arg));
+      Vector<int> *res = dbeGetUserExpId (arg);
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "getFounderExpId"))
+    {
+      Vector<int> *arg = (Vector<int>*)readArray (req);
+      ipc_log ("  expIds = %lld\n", VSIZE (arg));
+      Vector<int> *res = dbeGetFounderExpId (arg);
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "getExpGroupId"))
+    {
+      Vector<int> *arg = (Vector<int>*)readArray (req);
+      ipc_log ("  expIds = %lld\n", VSIZE (arg));
+      Vector<int> *res = dbeGetExpGroupId (arg);
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "getExpsProperty"))
+    {
+      String arg = readString (req);
+      Vector<String> *res = dbeGetExpsProperty (arg);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getExpName"))
+    {
+      // XXX add argument == DbeView index
+      Vector<String> *res = dbeGetExpName (0);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getExpState"))
+    {
+      // XXX add argument == DbeView index
+      Vector<int> *res = dbeGetExpState (0);
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "getExpEnable"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  arg1 = %d\n", arg1);
+      Vector<bool> *res = dbeGetExpEnable (arg1);
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "setExpEnable"))
+    {
+      int arg1 = readInt (req);
+      Vector<bool> *arg2 = (Vector<bool>*)readArray (req);
+      ipc_log ("  arg1=%d\n", arg1);
+      ipc_dump ("arg2", arg2);
+      bool b = dbeSetExpEnable (arg1, arg2);
+      writeBoolean (b, req);
+      ipc_log ("  dbeSetExpEnable returns %s\n", bool2str (b));
+      delete arg2;
+    }
+  else if (!strcmp (inp, "getExpInfo"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<String> *res = dbeGetExpInfo (arg1);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getViewModeEnable"))
+    {
+      bool res = dbeGetViewModeEnable ();
+      writeBoolean (res, req);
+    }
+  else if (!strcmp (inp, "getJavaEnable"))
+    {
+      bool res = dbeGetJavaEnable ();
+      writeBoolean (res, req);
+    }
+  else if (!strcmp (inp, "updateNotes"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      int arg3 = readInt (req);
+      String arg4 = readString (req);
+      bool arg5 = readBoolean (req);
+      ipc_log ("  args = %d, %d\n", arg1, arg2);
+      int i = dbeUpdateNotes (arg1, arg2, arg3, arg4, arg5);
+      writeInt (i, req);
+    }
+  else if (!strcmp (inp, "getLoadObjectList"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  arg = %d\n", arg1);
+      Vector<void *> *res = dbeGetLoadObjectList (arg1);
+      if (res == NULL)
+       ipc_log ("  returning = NULL for LoadObjectList\n");
+      else
+       {
+         Vector<char*> *s = (Vector<char*> *) res->fetch (0);
+         ipc_log ("  returning = %lld vectors for %lld LoadObjects\n",
+                  VSIZE (res), VSIZE (s));
+       }
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getLoadObjectName"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  arg = %d\n", arg1);
+      Vector<String> *res = dbeGetLoadObjectName (arg1);
+      ipc_log ("  returning = %lld strings\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getTabListInfo"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  arg = %d\n", arg1);
+      Vector<void*> *res = dbeGetTabListInfo (arg1);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getSearchPath"))
+    {
+      // XXX add argument == DbeView index
+      ipc_log ("  no args\n");
+      Vector<String> *res = dbeGetSearchPath (0);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "setSearchPath"))
+    {
+      // XXX add another argument == DbeView index
+      Vector<String> *res = (Vector<String>*)readArray (req);
+      ipc_log ("  %lld strings\n", VSIZE (res));
+      dbeSetSearchPath (0, res);
+      writeString (NULL, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getPathmaps"))
+    {
+      Vector<void*> *res = dbeGetPathmaps (0);
+      ipc_log ("  returns = %lld objects, number of pathmaps = %lld\n",
+              VSIZE (res), VSIZE ((Vector<int>*)res->fetch (0)));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "setPathmaps"))
+    {
+      Vector<String> *from = (Vector<String>*)readArray (req);
+      Vector<String> *to = (Vector<String>*)readArray (req);
+      char *res = dbeSetPathmaps (from, to);
+      writeString (res, req);
+      free (res);
+      if (from)
+       {
+         from->destroy ();
+         delete from;
+       }
+      if (to)
+       {
+         to->destroy ();
+         delete to;
+       }
+    }
+  else if (!strcmp (inp, "addPathmap"))
+    {
+      // XXX add another argument == DbeView index
+      String arg1 = readString (req);
+      String arg2 = readString (req);
+      ipc_log ("  args = '%s', '%s'\n", arg1 ? arg1 : "NULL", arg2 ? arg2 : "NULL");
+      char *res = dbeAddPathmap (0, arg1, arg2);
+      ipc_log ("  returns = '%s'\n", (res != NULL ? res : "NULL"));
+      writeString (res, req);
+      free (arg1);
+      free (arg2);
+    }
+  else if (!strcmp (inp, "getMsg"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      ipc_log ("  args = %d, %d\n", arg1, arg2);
+      String res = dbeGetMsg (arg1, arg2);
+      ipc_log ("  returns = '%s'\n", (res != NULL ? res : "<NULL>"));
+      writeString (res, req);
+      free (res);
+    }
+  else if (!strcmp (inp, "initView"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      ipc_log ("  new view = %d; clone of view %d\n", arg1, arg2);
+      dbeInitView (arg1, arg2);
+      writeString (NULL, req);
+    }
+  else if (!strcmp (inp, "disposeWindow"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      dbeDeleteView (arg1);
+      writeString (NULL, req);
+    }
+#if 0
+  else if (!strcmp (inp, "createMapfile"))
+    {
+      int arg1 = readInt ();
+      String arg2 = readString ();
+      int arg3 = readInt ();
+      ipc_log ("  args = %d, %s, %d\n", arg1, arg2, arg3);
+      String res = dbeCreateMapfile (arg1, arg2, arg3);
+      writeString (res);
+      free (arg2);
+      free (res);
+    }
+#endif
+  else if (!strcmp (inp, "setCompareModeV2"))
+    {
+      int dbevindex = readInt (req);
+      int cmp_mode = readInt (req);
+      getView (dbevindex)->set_compare_mode (cmp_mode);
+      writeResponseGeneric (RESPONSE_STATUS_SUCCESS, currentRequestID, currentChannelID);
+    }
+  else if (!strcmp (inp, "getCompareModeV2"))
+    {
+      int dbevindex = readInt (req);
+      int res = CMP_DISABLE;
+      if (dbeSession->expGroups && dbeSession->expGroups->size () > 1)
+       res = getView (dbevindex)->get_compare_mode ();
+      ipc_log ("  %s: %d returns %d\n", inp, dbevindex, res);
+      writeInt (res, req);
+    }
+  else if (!strcmp (inp, "getRefMetricsV2"))
+    {
+      Vector<void*> *res = dbeGetRefMetricsV2 ();
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "setCurMetricsV2"))
+    {
+      int dbevindex = readInt (req);
+      int cmp_mode = readInt (req);
+      MetricList *mlist = readMetricListV2 (dbevindex, req);
+      getView (dbevindex)->reset_metric_list (mlist, cmp_mode);
+      writeResponseGeneric (RESPONSE_STATUS_SUCCESS, currentRequestID, currentChannelID);
+    }
+  else if (!strcmp (inp, "getCurMetricsV2"))
+    {
+      int arg1 = readInt (req);
+      MetricType arg2 = (MetricType) readInt (req);
+      ipc_log ("  args = %d, %d\n", arg1, arg2);
+      Vector<void*> *res = dbeGetCurMetricsV2 (arg1, arg2);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getRefMetricTree"))
+    {
+      int dbevindex = readInt (req);
+      bool include_unregistered = readBoolean (req);
+      ipc_log ("  args = %d, %d\n", dbevindex, include_unregistered);
+      Vector<void*> *res = dbeGetRefMetricTree (dbevindex, include_unregistered);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getRefMetricTreeValues"))
+    {
+      int dbevindex = readInt (req);
+      Vector<String> *metcmds = (Vector<String>*)readArray (req);
+      Vector<String> *nonmetcmds = (Vector<String>*)readArray (req);
+      ipc_log ("  args = %d, metcmds->size()=%lld, nonmetcmds->size()=%lld\n",
+              dbevindex, VSIZE (metcmds), VSIZE (nonmetcmds));
+      ipc_dump ("metcmds", metcmds);
+      ipc_dump ("nonmetcmds", nonmetcmds);
+      Vector<void*> *res = dbeGetRefMetricTreeValues (dbevindex, metcmds, nonmetcmds);
+#ifdef IPC_LOG
+      if (res != NULL)
+       ipc_log ("  returns = %lld objects, length = %lld\n",
+                VSIZE (res), VSIZE (((Vector<int>*)res->fetch (0))));
+      else
+       ipc_log ("  returns NULL\n");
+#endif
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getOverviewText"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<char*> *res = dbeGetOverviewText (arg1);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "setSort"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      MetricType arg3 = (MetricType) readInt (req);
+      bool arg4 = readBoolean (req);
+      ipc_log ("  args = %d, %d, %d, %c\n", arg1, arg2, arg3, (arg4 ? 'T' : 'F'));
+      dbeSetSort (arg1, arg2, arg3, arg4);
+      writeString (NULL, req);
+    }
+
+  else if (!strcmp (inp, "getAnoValue"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<int> *res = dbeGetAnoValue (arg1);
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "setAnoValue"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d, array\n", arg1);
+      Vector<int> *arg2 = (Vector<int>*)readArray (req);
+      dbeSetAnoValue (arg1, arg2);
+      writeString (NULL, req);
+      delete arg2;
+    }
+  else if (!strcmp (inp, "getNameFormat"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      int b = dbeGetNameFormat (arg1);
+      writeInt (b, req);
+    }
+  else if (!strcmp (inp, "getSoName"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      bool b = dbeGetSoName (arg1);
+      writeBoolean (b, req);
+    }
+  else if (!strcmp (inp, "setNameFormat"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      bool arg3 = readBoolean (req);
+      ipc_log ("  args = %d, %d, %d\n", arg1, arg2, arg3);
+      dbeSetNameFormat (arg1, arg2, arg3);
+      writeString (NULL, req);
+    }
+  else if (!strcmp (inp, "getViewMode"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      int i = dbeGetViewMode (arg1);
+      ipc_log ("  returns = %d\n", i);
+      writeInt (i, req);
+    }
+  else if (!strcmp (inp, "setViewMode"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      ipc_log ("  args = %d, %d\n", arg1, arg2);
+      dbeSetViewMode (arg1, arg2);
+      writeString (NULL, req);
+    }
+  else if (!strcmp (inp, "getTLValue"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<void*> *res = dbeGetTLValue (arg1);
+      ipc_log ("  returns = %lld void*'s\n", VSIZE (res));
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "setTLValue"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      String tldata_cmd = readString (req);
+      int entity_prop_id = readInt (req);
+      int align = readInt (req);
+      int depth = readInt (req);
+      dbeSetTLValue (arg1, tldata_cmd, entity_prop_id, align, depth);
+      writeString (NULL, req);
+      free (tldata_cmd);
+    }
+  else if (!strcmp (inp, "getExpFounderDescendants"))
+    {
+      Vector<void*> *res = dbeGetExpFounderDescendants ();
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getExpSelection"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<void*> *res = dbeGetExpSelection (arg1);
+      writeArray (res, req);
+      destroy (res);
+    }
+
+  else if (!strcmp (inp, "setFilterStr"))
+    {
+      int arg1 = readInt (req);
+      String arg2 = readString (req);
+      ipc_log ("  args = %d, %s\n", arg1, arg2);
+      String res = dbeSetFilterStr (arg1, arg2);
+      ipc_log ("  returns = '%s'\n", res ? res : "NULL");
+      writeString (res, req);
+      free (arg2);
+      free (res);
+    }
+
+  else if (!strcmp (inp, "getFilterStr"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      String res = dbeGetFilterStr (arg1);
+      ipc_log ("  returns = '%s'\n", res ? res : "NULL");
+      writeString (res, req);
+      free (res);
+    }
+
+  else if (!strcmp (inp, "validateFilterExpression"))
+    {
+      String arg1 = readString (req);
+      int res = dbeValidateFilterExpression (arg1);
+      ipc_log ("  validateFilterExpression('%s') returned %d\n", str2str (arg1), res);
+      free (arg1);
+      writeInt (res, req);
+    }
+
+  else if (!strcmp (inp, "getFilterKeywords"))
+    {
+      int dbevindex = readInt (req);
+      Vector<void*>*res = dbeGetFilterKeywords (dbevindex);
+      writeArray (res, req);
+      destroy (res);
+    }
+
+  else if (!strcmp (inp, "getFilters"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      ipc_log ("  args: view = %d, experiment = %d\n", arg1, arg2);
+      Vector<void*>*res = dbeGetFilters (arg1, arg2);
+      ipc_log ("  -- returned %lld Filters\n", VSIZE (res));
+      writeArray (res, req);
+      delete res;
+    }
+
+  else if (!strcmp (inp, "updateFilters"))
+    {
+      int arg1 = readInt (req);
+      Vector<bool> *arg2 = (Vector<bool>*)readArray (req);
+      Vector<String> *arg3 = (Vector<String>*)readArray (req);
+      ipc_log ("arg1=%d arg2->size()=%lld  arg3->size()=%lld\n",
+              arg1, VSIZE (arg2), VSIZE (arg3));
+      ipc_dump ("arg2", arg2);
+      ipc_dump ("arg3", arg3);
+      bool b = dbeUpdateFilters (arg1, arg2, arg3);
+      writeBoolean (b, req);
+      ipc_log ("  returns %s\n", (b == true ? "true" : "false"));
+      delete arg2;
+      delete arg3;
+    }
+  else if (!strcmp (inp, "getLoadObjectState"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d \n", arg1);
+      Vector<int> *res = dbeGetLoadObjectState (arg1);
+      ipc_log ("  returning = %lld int's\n", VSIZE (res));
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "setLoadObjectState"))
+    {
+      int arg1 = readInt (req);
+      Vector<int> *arg2 = (Vector<int>*)readArray (req);
+      ipc_log ("  args = %d, %lld objects\n", arg1, VSIZE (arg2));
+      dbeSetLoadObjectState (arg1, arg2);
+      writeString (NULL, req);
+      delete arg2;
+    }
+  else if (!strcmp (inp, "setLoadObjectDefaults"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      dbeSetLoadObjectDefaults (arg1);
+      writeString (NULL, req);
+    }
+  else if (!strcmp (inp, "getMemTabSelectionState"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  arg = %d\n", arg1);
+      Vector<bool> *res = dbeGetMemTabSelectionState (arg1);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "setMemTabSelectionState"))
+    {
+      int arg1 = readInt (req);
+      Vector<bool> *arg2 = (Vector<bool> *)readArray (req);
+      ipc_log ("  args = %d\n  arg2 = %lld objects\n", arg1, VSIZE (arg2));
+      dbeSetMemTabSelectionState (arg1, arg2);
+      writeString (NULL, req);
+      destroy (arg2);
+    }
+  else if (!strcmp (inp, "getIndxTabSelectionState"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  arg = %d\n", arg1);
+      Vector<bool> *res = dbeGetIndxTabSelectionState (arg1);
+      ipc_log ("  -- returned %lld-vector [bool]\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "setIndxTabSelectionState"))
+    {
+      int arg1 = readInt (req);
+      Vector<bool> *arg2 = (Vector<bool> *)readArray (req);
+      ipc_log ("  args = %d\n  arg2 = %lld objects\n", arg1, VSIZE (arg2));
+      dbeSetIndxTabSelectionState (arg1, arg2);
+      writeString (NULL, req);
+      destroy (arg2);
+    }
+  else if (!strcmp (inp, "getTabSelectionState"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<bool> *res = dbeGetTabSelectionState (arg1);
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "setTabSelectionState"))
+    {
+      int arg1 = readInt (req);
+      Vector<bool> *arg2 = (Vector<bool>*)readArray (req);
+      ipc_log ("  args = %d\n  arg2 = %lld objects\n", arg1, VSIZE (arg2));
+      dbeSetTabSelectionState (arg1, arg2);
+      writeString (NULL, req);
+      delete arg2;
+    }
+  else if (!strcmp (inp, "getMemObjects"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<void*> *res = dbeGetMemObjects (arg1);
+
+#ifdef IPC_LOG
+      if (res == NULL)
+       ipc_log ("  -- returned NULL\n");
+      else
+       {
+         Vector<int> *mo_types = (Vector<int> *)res->fetch (0);
+         ipc_log ("  -- returned %lld-vector [ %lld-vectors]\n",
+                  VSIZE (res), VSIZE (mo_types));
+       }
+#endif
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "loadMachineModel"))
+    {
+      String arg1 = readString (req);
+#ifdef IPC_LOG
+      ipc_log ("  arg = `%s'\n", arg1);
+#endif
+      String sts = dbeLoadMachineModel (arg1);
+#ifdef IPC_LOG
+      ipc_log ("  returns '%s'\n", sts ? sts : "NULL");
+#endif
+      writeString (sts, req);
+      free (arg1);
+    }
+  else if (!strcmp (inp, "getMachineModel"))
+    {
+      String sts = dbeGetMachineModel ();
+#ifdef IPC_LOG
+      ipc_log ("  returns '%s'\n", sts ? sts : "NULL");
+#endif
+      writeString (sts, req);
+    }
+  else if (!strcmp (inp, "getCPUVerMachineModel"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<char*> *res = dbeGetCPUVerMachineModel (arg1);
+      writeArray (res, req);
+      ipc_log ("  returns %lld char*'s\n", VSIZE (res));
+      destroy (res);
+    }
+  else if (!strcmp (inp, "listMachineModels"))
+    {
+      Vector<String> *res = dbeListMachineModels ();
+#ifdef IPC_LOG
+      if (res != NULL)
+       ipc_log ("  returns = %lld strings\n", VSIZE (res));
+      else
+       ipc_log ("  returns NULL\n");
+#endif
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "defineMemObj"))
+    {
+      String arg1 = readString (req);
+      String arg2 = readString (req);
+      String arg3 = readString (req);
+      String arg4 = readString (req);
+#ifdef IPC_LOG
+      ipc_log ("  args = %s, %s, %s, %s\n", arg1, arg2, arg3 == NULL ? "NULL" : arg3, arg4 == NULL ? "NULL" : arg4);
+#endif
+      String sts = dbeDefineMemObj (arg1, arg2, NULL, arg3, arg4);
+#ifdef IPC_LOG
+      ipc_log ("  returns '%s'\n", sts ? sts : "NULL");
+#endif
+      writeString (sts, req);
+      free (arg1);
+      free (arg2);
+      free (arg3);
+      free (arg4);
+    }
+  else if (!strcmp (inp, "deleteMemObj"))
+    {
+      String arg1 = readString (req);
+#ifdef IPC_LOG
+      ipc_log ("  args = %s\n", arg1);
+#endif
+      String sts = dbeDeleteMemObj (arg1);
+#ifdef IPC_LOG
+      ipc_log ("  returns '%s'\n", sts ? sts : "NULL");
+#endif
+      writeString (sts, req);
+      free (arg1);
+    }
+  else if (!strcmp (inp, "getIndxObjDescriptions"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<void*> *res = dbeGetIndxObjDescriptions (arg1);
+#ifdef IPC_LOG
+      if (res == NULL)
+       ipc_log ("  -- returned NULL\n");
+      else
+       {
+         Vector<int> *indxo_types = (Vector<int> *)res->fetch (0);
+         ipc_log ("  -- returned %lld-vector [ %lld-vectors]\n",
+                  VSIZE (res), VSIZE (indxo_types));
+       }
+#endif
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getCustomIndxObjects"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<void*> *res = dbeGetCustomIndxObjects (arg1);
+#ifdef IPC_LOG
+      if (res == NULL)
+       ipc_log ("  -- returned NULL\n");
+      else
+       {
+         Vector<char *> *indxo_names = (Vector<char *> *)res->fetch (0);
+         ipc_log ("  -- returned %lld-vector [ %lld-vectors]\n",
+                  VSIZE (res), VSIZE (indxo_names));
+       }
+#endif
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "defineIndxObj"))
+    {
+      String arg1 = readString (req);
+      String arg2 = readString (req);
+      String arg3 = readString (req);
+      String arg4 = readString (req);
+      ipc_log ("  args = %s, %s, %s, %s\n", arg1, arg2, arg3 == NULL ? "NULL" : arg3, arg4 == NULL ? "NULL" : arg4);
+      String sts = dbeDefineIndxObj (arg1, arg2, arg3, arg4);
+      ipc_log ("  returns '%s'\n", sts ? sts : "NULL");
+      writeString (sts, req);
+      free (arg1);
+      free (arg2);
+      free (arg3);
+      free (arg4);
+    }
+  else if (!strcmp (inp, "setSelObj"))
+    {
+      int arg1 = readInt (req);
+      Obj arg2 = readObject (req);
+      int arg3 = readInt (req);
+      int arg4 = readInt (req);
+      ipc_log ("  args = %d, %ld, %s, %d\n", arg1, (long) arg2, table_name (arg3), arg4);
+      dbeSetSelObj (arg1, arg2, arg3, arg4);
+      writeString (NULL, req);
+    }
+  else if (!strcmp (inp, "setSelObjV2"))
+    {
+      int arg1 = readInt (req);
+      uint64_t arg2 = readLong (req);
+      ipc_log ("  args = %d, %ld\n", arg1, arg2);
+      dbeSetSelObjV2 (arg1, arg2);
+      writeString (NULL, req);
+    }
+  else if (!strcmp (inp, "getSelObj"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      int arg3 = readInt (req);
+      ipc_log ("  args = %d, %s, %d\n", arg1, table_name (arg2), arg3);
+      Obj i = dbeGetSelObj (arg1, arg2, arg3);
+      ipc_log ("  returns = %ld (0x%08lx)\n", (long) i, (long) i);
+      writeObject (i, req);
+    }
+  else if (!strcmp (inp, "getSelObjV2"))
+    {
+      int arg1 = readInt (req);
+      String arg2 = readString (req);
+      ipc_log ("  arg1 = %d  agr2 = %s\n", arg1, arg2 ? arg2 : "NULL");
+      Obj res = dbeGetSelObjV2 (arg1, arg2);
+      ipc_log ("  returns = %lld\n", (long long) res);
+      writeObject (res, req);
+      free (arg2);
+    }
+  else if (!strcmp (inp, "getSelObjIO"))
+    {
+      int arg1 = readInt (req);
+      uint64_t arg2 = readLong (req);
+      int arg3 = readInt (req);
+      ipc_log ("  arg1 = %d, arg2 = %lld, arg3 = %d\n", arg1, (long long) arg2, arg3);
+      Vector<uint64_t> *res = dbeGetSelObjIO (arg1, arg2, arg3);
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "getSelObjsIO"))
+    {
+      int arg1 = readInt (req);
+      Vector<uint64_t> *arg2 = (Vector<uint64_t>*)readArray (req);
+      int arg3 = readInt (req);
+      ipc_log ("  arg1 = %d, arg2 size = %lld, arg3 = %d\n",
+              arg1, VSIZE (arg2), arg3);
+      Vector<uint64_t> *res = dbeGetSelObjsIO (arg1, arg2, arg3);
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "getSelObjHeapTimestamp"))
+    {
+      int arg1 = readInt (req);
+      uint64_t arg2 = readLong (req);
+      ipc_log ("  arg1 = %d, arg2 = %llu\n", arg1, (unsigned long long) arg2);
+      uint64_t st = dbeGetSelObjHeapTimestamp (arg1, arg2);
+      ipc_log ("  returns = %llu\n", (unsigned long long) st);
+      writeLong (st, req);
+    }
+  else if (!strcmp (inp, "getSelObjHeapUserExpId"))
+    {
+      int arg1 = readInt (req);
+      uint64_t arg2 = readLong (req);
+      ipc_log ("  arg1 = %d, arg2 = %llu\n", arg1, (unsigned long long) arg2);
+      int userExpId = dbeGetSelObjHeapUserExpId (arg1, arg2);
+      ipc_log ("  returns = %d\n", userExpId);
+      writeInt (userExpId, req);
+    }
+  else if (!strcmp (inp, "getSelIndex"))
+    {
+      int arg1 = readInt (req);
+      Obj arg2 = readObject (req);
+      int arg3 = readInt (req);
+      int arg4 = readInt (req);
+      ipc_log ("  args = %d, 0x%08lx, %s, %d\n", arg1, (long) arg2, table_name (arg3), arg4);
+      int i = dbeGetSelIndex (arg1, arg2, arg3, arg4);
+      ipc_log ("  returns = %d\n", i);
+      writeInt (i, req);
+    }
+  else if (!strcmp (inp, "printData"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      int arg3 = readInt (req);
+      String arg4 = readString (req);
+      String arg5 = readString (req);
+      ipc_log ("  args = %d, %s, %d, `%s', `%s'\n",
+              arg1, table_name (arg2), arg3,
+              (arg4 == NULL ? "NULL" : arg4),
+              (arg5 == NULL ? "NULL" : arg5));
+      String res = dbePrintData (arg1, arg2, arg3, arg4, arg5, NULL);
+      writeString (res, req);
+      free (arg4);
+      free (arg5);
+      free (res);
+    }
+  else if (!strcmp (inp, "getPrintLimit"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      int i = dbeGetPrintLimit (arg1);
+      ipc_log ("  returns = %d\n", i);
+      writeInt (i, req);
+    }
+  else if (!strcmp (inp, "setPrintLimit"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      ipc_log ("  args = %d, %d\n", arg1, arg2);
+      String res = dbeSetPrintLimit (arg1, arg2);
+      writeString (res, req);
+      free (res);
+    }
+  else if (!strcmp (inp, "getPrintMode"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      int i = dbeGetPrintMode (arg1);
+      ipc_log ("  returns = %d\n", i);
+      writeInt (i, req);
+    }
+  else if (!strcmp (inp, "setPrintMode"))
+    {
+      int arg1 = readInt (req);
+      String arg2 = readString (req);
+      ipc_log ("  args = %d, %s\n", arg1, arg2);
+      String res = dbeSetPrintMode (arg1, arg2);
+      writeString (res, req);
+      free (arg2);
+      free (res);
+    }
+  else if (!strcmp (inp, "getPrintDelim"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      char i = dbeGetPrintDelim (arg1);
+      ipc_log ("  returns = %c\n", i);
+      writeInt ((int) i, req);
+    }
+  else if (!strcmp (inp, "getHotMarks"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      ipc_log ("  args = %d, %s (%d) \n", arg1, table_name (arg2), arg2);
+      Vector<void*> *res = dbeGetHotMarks (arg1, arg2);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getHotMarksInc"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      ipc_log ("  args = %d, %s (%d) \n", arg1, table_name (arg2), arg2);
+      Vector<void*> *res = dbeGetHotMarksInc (arg1, arg2);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getSummaryHotMarks"))
+    {
+      int arg1 = readInt (req);
+      Vector<Obj> *arg2 = (Vector<Obj>*)readArray (req);
+      int arg3 = readInt (req);
+      ipc_log ("  args = %d, 0x%llx, %s (%d)\n", arg1, (long long) arg2, table_name (arg3), arg3);
+      Vector<void*> *res = dbeGetSummaryHotMarks (arg1, arg2, arg3);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getFuncId"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      int arg3 = readInt (req);
+      int arg4 = readInt (req);
+      ipc_log ("  args = %d, %s, %d, %d\n", arg1, table_name (arg2), arg3, arg4);
+      Vector<uint64_t> *res = dbeGetFuncId (arg1, arg2, arg3, arg4);
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "getFuncCalleeInfo"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      Vector<int> *arg3 = (Vector<int>*)readArray (req);
+      int arg4 = readInt (req);
+      ipc_log ("  args = %d, %s, %lld, %d\n", arg1, table_name (arg2), VSIZE (arg3), arg4);
+      Vector<void*> *res = dbeGetFuncCalleeInfo (arg1, arg2, arg3, arg4);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getFuncCallerInfo"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      Vector<int> *arg3 = (Vector<int>*)readArray (req);
+      int arg4 = readInt (req);
+      ipc_log ("  args = %d, %s, %lld, %d\n", arg1, table_name (arg2), VSIZE (arg3), arg4);
+      Vector<void*> *res = dbeGetFuncCallerInfo (arg1, arg2, arg3, arg4);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "setFuncData"))
+    {
+      int arg1 = readInt (req);
+      Obj arg2 = readObject (req);
+      int arg3 = readInt (req);
+      int arg4 = readInt (req);
+      ipc_log ("  args = %d, %ld, %s, %d\n", arg1, (long) arg2, table_name (arg3), arg4);
+      int i = dbeSetFuncData (arg1, arg2, arg3, arg4);
+      ipc_log ("  returns = %d\n", i);
+      writeInt (i, req);
+    }
+  else if (!strcmp (inp, "setFuncDataV2"))
+    {
+      int dbevindex = readInt (req);
+      Obj sel_obj = readObject (req);
+      int type = readInt (req);
+      int subtype = readInt (req);
+      Vector<long long> *longs = new Vector<long long>(2);
+      Vector<char *> *strings = new Vector<char *>(2);
+
+      longs->append (dbeSetFuncData (dbevindex, sel_obj, type, subtype));
+      strings->append (dbeGetMsg (dbevindex, ERROR_MSG));
+      String sf_name = NULL;
+      long long sf_id = 0;
+      switch (type)
+       {
+       case DSP_SOURCE:
+       case DSP_DISASM:
+         {
+           Histable *obj = (Histable *) sel_obj;
+           if (obj)
+             {
+               Histable *sf = obj->convertto (Histable::SOURCEFILE);
+               if (sf)
+                 {
+                   sf_id = sf->id;
+                   sf_name = dbe_strdup (sf->get_name ());
+                 }
+             }
+           break;
+         }
+       }
+      longs->append (sf_id);
+      strings->append (sf_name);
+      ipc_log ("  setFuncData(%d, %ld, %s, %d)  returns (%lld, %lld)\n   (%s, %s)\n",
+              dbevindex, (long) sel_obj, table_name (type), subtype, longs->get (0), longs->get (1),
+              STR (strings->get (0)), STR (strings->get (1)));
+
+      Vector<void *> *res = new Vector<void *>(2);
+      res->append (longs);
+      res->append (strings);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getFuncList"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      int arg3 = readInt (req);
+      ipc_log ("  args = %d, %s, %d\n", arg1, table_name (arg2), arg3);
+      Vector<void*> *res = dbeGetFuncList (arg1, arg2, arg3);
+#ifdef IPC_LOG
+      if (res != NULL)
+       ipc_log ("  returns = %lld objects, length = %lld\n",
+                VSIZE (res), VSIZE ((Vector<int>*)res->fetch (0)));
+      else
+       ipc_log ("  returns NULL\n");
+#endif
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getFuncListV2"))
+    {
+      int dbevindex = readInt (req);
+      int mtype = readInt (req);
+      Obj sel_obj = readObject (req);
+      int type = readInt (req);
+      int subtype = readInt (req);
+      Vector<void*> *res = dbeGetFuncListV2 (dbevindex, mtype, sel_obj, type, subtype);
+      ipc_log ("  args = %d 0x%x %ld, %s, %d returns = %d objects, length = %d\n",
+              dbevindex, mtype, (long) sel_obj, table_name (type), subtype,
+              (int) (res ? res->size () : 0),
+              (int) (res ? ((Vector<int>*)res->fetch (0))->size () : 0));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getFuncListMini"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      int arg3 = readInt (req);
+      ipc_log ("  args = %d, %s, %d\n", arg1, table_name (arg2), arg3);
+      Vector<void*> *res = dbeGetFuncListMini (arg1, arg2, arg3);
+#ifdef IPC_LOG
+      if (res != NULL)
+       ipc_log ("  returns = %lld objects, length = %lld\n",
+                VSIZE (res), VSIZE ((Vector<int>*)res->fetch (0)));
+      else
+       ipc_log ("  returns NULL\n");
+#endif
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "dbeGetTotals"))
+    {
+      int dbevindex = readInt (req);
+      int dsptype = readInt (req);
+      int subtype = readInt (req);
+      Vector<void *> *res = dbeGetTotals (dbevindex, dsptype, subtype);
+      ipc_log ("  dbeGetTotals(%d, %d, %d) returns %lld objects\n",
+              dbevindex, dsptype, subtype, VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getComparableObjsV2"))
+    {
+      int arg1 = readInt (req);
+      Obj arg2 = readObject (req);
+      int arg3 = readInt (req);
+      Vector<Obj> *res = dbeGetComparableObjsV2 (arg1, arg2, arg3);
+      ipc_log ("  args = %d 0x%lx %d\n", arg1, (long) arg2, arg3);
+      ipc_dump ("getComparableObjsV2:res", res);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "dbeConvertSelObj"))
+    {
+      Obj obj = readObject (req);
+      int type = readInt (req);
+      Obj res = dbeConvertSelObj (obj, type);
+      ipc_log ("  args = %lld %d res=%lld \n", (long long) obj, type,
+              (long long) res);
+      writeObject (res, req);
+    }
+  else if (!strcmp (inp, "getTableDataV2"))
+    {
+      int arg1 = readInt (req);
+      String arg2 = readString (req);
+      String arg3 = readString (req);
+      String arg4 = readString (req);
+      String arg5 = readString (req);
+      Vector<uint64_t> *arg6 = (Vector<uint64_t>*)readArray (req);
+      ipc_log ("  args = %d, %s, %s, %s, %s, %lld\n", arg1, STR (arg2),
+              STR (arg3), STR (arg4), STR (arg5), VSIZE (arg6));
+      Vector<void*> *res = dbeGetTableDataV2 (arg1, arg2, arg3, arg4, arg5, arg6);
+#ifdef IPC_LOG
+      if (res != NULL)
+       ipc_log ("  returns = %lld objects, length = %lld\n",
+                VSIZE (res), VSIZE ((Vector<int>*)res->fetch (0)));
+      else
+       ipc_log ("  returns NULL\n");
+#endif
+      writeArray (res, req);
+      //destroy( arg6 );
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getCallTreeNumLevels"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      int res = dbeGetCallTreeNumLevels (arg1);
+#ifdef IPC_LOG
+      ipc_log ("  returns = %d\n", res);
+#endif
+      writeInt (res, req);
+    }
+  else if (!strcmp (inp, "getCallTreeLevel"))
+    {
+      int arg1 = readInt (req);
+      String arg2 = readString (req);
+      int arg3 = readInt (req);
+      ipc_log ("  args = %d, %s, %d\n", arg1, arg2, arg3);
+      Vector<void*> *res = dbeGetCallTreeLevel (arg1, arg2, arg3);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getCallTreeChildren"))
+    {
+      int arg1 = readInt (req);
+      String arg2 = readString (req);
+      Vector<int> *arg3 = (Vector<int> *) readArray (req); /*NodeIdx array*/
+      ipc_log ("  args = %d, %s, vec_size=%lld\n", arg1, arg2, (long long) (arg3 ? arg3->size () : 0));
+      Vector<void*> *res = dbeGetCallTreeChildren (arg1, arg2, arg3);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getCallTreeLevels"))
+    {
+      int arg1 = readInt (req);
+      String arg2 = readString (req);
+      ipc_log ("  args = %d, %s\n", arg1, arg2);
+      Vector<void*> *res = dbeGetCallTreeLevels (arg1, arg2);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getCallTreeLevelFuncs"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      int arg3 = readInt (req);
+      ipc_log ("  args = %d, %d, %d\n", arg1, arg2, arg3);
+      Vector<void*> *res = dbeGetCallTreeLevelFuncs (arg1, arg2, arg3);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getCallTreeFuncs"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<void*> *res = dbeGetCallTreeFuncs (arg1);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getGroupIds"))
+    {
+      int arg1 = readInt (req);
+      Vector<int> *res = dbeGetGroupIds (arg1);
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "getNames"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      Obj arg3 = readObject (req);
+#ifdef IPC_LOG
+      ipc_log ("  args = %d, %s 0x%lx\n", arg1, table_name (arg2), (long) arg3);
+#endif
+      Vector<String> *res = dbeGetNames (arg1, arg2, arg3);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getTotalMax"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      int arg3 = readInt (req);
+      ipc_log ("  args = %d, %s, %d\n", arg1, table_name (arg2), arg3);
+      Vector<void*> *res = dbeGetTotalMax (arg1, arg2, arg3);
+#ifdef IPC_LOG
+      if (res != NULL)
+       ipc_log ("  returns = %lld vectors, length %lld\n",
+                VSIZE (res), VSIZE ((Vector<void*>*)res->fetch (0)));
+      else
+       ipc_log ("  returns NULL\n");
+#endif
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "composeFilterClause"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      int arg3 = readInt (req);
+      Vector<int> *arg4 = (Vector<int>*)readArray (req);
+      ipc_log ("  args = %d, %s, %d, %lld selections\n",
+              arg1, table_name (arg2), arg3, VSIZE (arg4));
+      String s = dbeComposeFilterClause (arg1, arg2, arg3, arg4);
+      ipc_log ("  returns %s\n", (s == NULL ? "<NULL>" : s));
+      writeString (s, req);
+    }
+  else if (!strcmp (inp, "getStatisOverviewList"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<Object> *res = dbeGetStatisOverviewList (arg1);
+      ipc_log ("  dbeStatisGetOverviewList returns = %lld objects\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getStatisList"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<Object> *res = dbeGetStatisList (arg1);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getSummary"))
+    {
+      int arg1 = readInt (req);
+      Vector<Obj> *arg2 = (Vector<Obj>*)readArray (req);
+      int arg3 = readInt (req);
+      int arg4 = readInt (req);
+      ipc_log ("  args = %d, 0x%llx, %s (%d), %d\n", arg1, (long long) arg2, table_name (arg3), arg3, arg4);
+      Vector<Object> *res = dbeGetSummary (arg1, arg2, arg3, arg4);
+      ipc_log ("  dbeGetSummary returns = %lld objects\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getSummaryV2"))
+    {
+      int dbevindex = readInt (req);
+      Vector<Obj> *sel_objs = (Vector<Obj>*)readArray (req);
+      int type = readInt (req);
+      int subtype = readInt (req);
+      Vector<void*> *res = dbeGetSummaryV2 (dbevindex, sel_objs, type, subtype);
+      ipc_log ("  args = %d, [%lld], %s (%d), %d res=[%lld] 0x%llx \n",
+              dbevindex, VSIZE (sel_objs), table_name (type), type, subtype,
+              VSIZE (res), (unsigned long long) res);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getExpName1"))
+    {
+      // XXX add an argument = DbeView index
+      String arg1 = readString (req);
+      ipc_log ("  arg = `%s'\n", arg1 ? arg1 : "NULL");
+      String res = dbeGetExpName (0, arg1);
+      writeString (res, req);
+      ipc_log ("  returns `%s'\n", res ? res : "NULL");
+      free (arg1);
+      free (res);
+    }
+  else if (!strcmp (inp, "getHwcHelp"))
+    {
+      // XXX add an argument = DbeView index
+      bool forKernel = readBoolean (req);
+      Vector<String> *res = dbeGetHwcHelp (0, forKernel);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getHwcSets"))
+    {
+      // XXX add an argument = DbeView index
+      bool forKernel = readBoolean (req);
+      Vector<Vector<char*>*> *res = dbeGetHwcSets (0, forKernel);
+      writeArray (res, req);
+      ipc_log ("  returns %lld char*'s\n", VSIZE (res));
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getHwcsAll"))
+    {
+      // XXX add an argument = DbeView index
+      bool forKernel = readBoolean (req);
+      Vector<void*> *res = dbeGetHwcsAll (0, forKernel);
+      writeArray (res, req);
+      ipc_log ("  returns %lld char*'s\n", VSIZE (res));
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getHwcAttrList"))
+    {
+      // XXX add an argument = DbeView index
+      bool forKernel = readBoolean (req);
+      Vector<char*> *res = dbeGetHwcAttrList (0, forKernel);
+      ipc_log ("  returns %lld char*'s\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getHwcMaxConcurrent"))
+    {
+      // XXX add an argument = DbeView index
+      bool forKernel = readBoolean (req);
+      int res = dbeGetHwcMaxConcurrent (0, forKernel);
+      writeInt (res, req);
+    }
+  else if (!strcmp (inp, "getIfreqData"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<char*> *res = dbeGetIfreqData (arg1);
+      ipc_log ("  returns %lld char*'s\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getNewLeakListInfo"))
+    {
+      int arg1 = readInt (req);
+      bool arg2 = readBoolean (req);
+      ipc_log ("  args = %d, %d\n", arg1, arg2);
+      Vector<void*> *res = dbeGetLeakListInfo (arg1, arg2);
+      ipc_log ("  returns %lld void*'s\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getObject"))
+    {
+      int arg1 = readInt (req);
+      Obj arg2 = readObject (req);
+      Obj arg3 = readObject (req);
+      Obj i = dbeGetObject (arg1, arg2, arg3);
+      writeObject (i, req);
+    }
+  else if (!strcmp (inp, "getExpVerboseName"))
+    {
+      Vector<int> *arg = (Vector<int>*)readArray (req);
+      ipc_log ("  expIds = %lld\n", VSIZE (arg));
+      Vector<String> *res = dbeGetExpVerboseName (arg);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getName"))
+    {
+      // XXX add an argument = DbeView index
+      int arg1 = readInt (req);
+      String res = dbeGetName (0, arg1);
+      writeString (res, req);
+      free (res);
+    }
+  else if (!strcmp (inp, "getStartTime"))
+    {
+      // XXX add an argument = DbeView index
+      int arg1 = readInt (req);
+      long long l = dbeGetStartTime (0, arg1);
+      ipc_log ("  returns = %llu\n", l);
+      writeLong (l, req);
+    }
+  else if (!strcmp (inp, "getRelativeStartTime"))
+    {
+      // XXX add an argument = DbeView index
+      int arg1 = readInt (req);
+      long long l = dbeGetRelativeStartTime (0, arg1);
+      ipc_log ("  returns = %llu\n", l);
+      writeLong (l, req);
+    }
+  else if (!strcmp (inp, "getEndTime"))
+    {
+      // XXX add an argument = DbeView index
+      int arg1 = readInt (req);
+      long long l = dbeGetEndTime (0, arg1);
+      ipc_log ("  returns = %llu\n", l);
+      writeLong (l, req);
+    }
+  else if (!strcmp (inp, "getClock"))
+    {
+      // XXX add an argument = DbeView index
+      int arg1 = readInt (req);
+      int i = dbeGetClock (0, arg1);
+      writeInt (i, req);
+    }
+    /*
+           else if ( !strcmp( inp, "getFounderExpId" ) ) {
+                   // XXX add an argument = DbeView index
+               int       arg1 = readInt(req);
+               int i = dbeGetFounderExpId(0, arg1 );
+               writeInt( i, req );
+           }
+     */
+  else if (!strcmp (inp, "getEntityProps"))
+    {
+      int arg1 = readInt (req);
+      ipc_log ("  args = %d\n", arg1);
+      Vector<void*> *res = dbeGetEntityProps (arg1);
+      writeArray (res, req);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getEntities"))
+    {
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      int arg3 = readInt (req);
+      ipc_log ("  args = %d, %d, %d\n", arg1, arg2, arg3);
+      Vector<void*> *res = dbeGetEntities (arg1, arg2, arg3);
+      writeArray (res, req);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getEntitiesV2"))
+    {
+      int arg1 = readInt (req);
+      Vector<int> *arg2 = (Vector<int>*)readArray (req);
+      int arg3 = readInt (req);
+      ipc_log ("  args = %d, %lld, %d\n", arg1, VSIZE (arg2), arg3);
+      Vector<void*> *res = dbeGetEntitiesV2 (arg1, arg2, arg3);
+      writeArray (res, req);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getTLDetails"))
+    {//TBR
+      int arg1 = readInt (req);
+      int arg2 = readInt (req);
+      int arg3 = readInt (req);
+      int arg4 = readInt (req);
+      long long arg5 = readLong (req);
+      ipc_log (" dbevindex= %d, exp_id = %d, data_id = %d, "
+              "entity_prop_id = %d, event_id = %lld\n",
+              arg1, arg2, arg3, arg4, arg5);
+      Vector<void*> *res = dbeGetTLDetails (arg1, arg2, arg3, arg4, arg5);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getStackNames"))
+    {
+      int arg1 = readInt (req);
+      Obj arg2 = readObject (req);
+      ipc_log ("  args = %d, %ld\n", arg1, (long) arg2);
+      Vector<String> *res = dbeGetStackNames (arg1, arg2);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getStackFunctions"))
+    {
+      // XXX add an argument = DbeView index
+      Obj arg1 = readObject (req);
+      ipc_log ("  args = %ld\n", (long) arg1);
+      Vector<Obj> *res = dbeGetStackFunctions (0, arg1);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "getStacksFunctions"))
+    {
+      // XXX add an argument = DbeView index
+      Vector<Obj> *arg1 = (Vector<Obj>*)readArray (req);
+      ipc_log ("  argc = %ld\n", (long) arg1->size ());
+      Vector<void*> *res = dbeGetStacksFunctions (0, arg1);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "getStackPCs"))
+    {
+      // XXX add an argument = DbeView index
+      Obj arg1 = readObject (req);
+      ipc_log ("  args = %ld\n", (long) arg1);
+      Vector<Obj> *res = dbeGetStackPCs (0, arg1);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      writeArray (res, req);
+      delete res;
+    }
+  else if (!strcmp (inp, "getIOStatistics"))
+    {
+      int dbevindex = readInt (req);
+      Vector<Vector<char*>*> *res = dbeGetIOStatistics (dbevindex);
+      writeArray (res, req);
+      ipc_log ("  returns %lld char*'s\n", VSIZE (res));
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getHeapStatistics"))
+    {
+      int dbevindex = readInt (req);
+      Vector<Vector<char*>*> *res = dbeGetHeapStatistics (dbevindex);
+      writeArray (res, req);
+      ipc_log ("  returns %lld char*'s\n", VSIZE (res));
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getSamples"))
+    {
+      int dbev_id = readInt (req);
+      int exp_id = readInt (req);
+      int64_t lo = readLong (req);
+      int64_t hi = readLong (req);
+      ipc_log ("  dbevindex= %d, exp_id = %d, lo_idx:%lld, hi_idx:%lld\n",
+              dbev_id, exp_id, (long long) lo, (long long) hi);
+      Vector<void*> *res = dbeGetSamples (dbev_id, exp_id, lo, hi);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getGCEvents"))
+    {
+      int dbev_id = readInt (req);
+      int exp_id = readInt (req);
+      int64_t lo = readLong (req);
+      int64_t hi = readLong (req);
+      ipc_log ("  dbevindex= %d, exp_id = %d, lo_idx:%lld, hi_idx:%lld\n",
+              dbev_id, exp_id, (long long) lo, (long long) hi);
+      Vector<void*> *res = dbeGetGCEvents (dbev_id, exp_id, lo, hi);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getFuncNames"))
+    {
+      int arg1 = readInt (req);
+      Vector<Obj> *arg2 = (Vector<Obj>*)readArray (req);
+      ipc_log ("  arg1 = %d, arg2 absent, size = %lld\n", arg1, VSIZE (arg2));
+      Vector<String> *res = dbeGetFuncNames (arg1, arg2);
+      writeArray (res, req);
+      delete arg2;
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getFuncIds"))
+    {
+      int arg1 = readInt (req);
+      Vector<Obj> *arg2 = (Vector<Obj>*)readArray (req);
+      ipc_log ("  arg1 = %d, arg2 absent, size = %lld\n", arg1, VSIZE (arg2));
+      Vector<uint64_t> *res = dbeGetFuncIds (arg1, arg2);
+      writeArray (res, req);
+      delete arg2;
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getObjNamesV2"))
+    {
+      int arg1 = readInt (req);
+      Vector<uint64_t> *arg2 = (Vector<uint64_t>*)readArray (req);
+      ipc_log ("  arg1 = %d, arg2 absent, size = %lld\n", arg1, VSIZE (arg2));
+      Vector<String> *res = dbeGetObjNamesV2 (arg1, arg2);
+      writeArray (res, req);
+      delete arg2;
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getFuncName"))
+    {
+      int arg1 = readInt (req);
+      Obj arg2 = readObject (req);
+      ipc_log ("  arg1 = %d, arg2 = %lld\n", arg1, (long long) arg2);
+      String res = dbeGetFuncName (arg1, arg2);
+      ipc_log ("  returning = %s\n", res ? res : "NULL");
+      writeString (res, req);
+      free (res);
+    }
+  else if (!strcmp (inp, "getObjNameV2"))
+    {
+      int arg1 = readInt (req);
+      uint64_t arg2 = readLong (req);
+      ipc_log ("  arg1 = %d, arg2 = %llu\n", arg1, (unsigned long long) arg2);
+      String res = dbeGetObjNameV2 (arg1, arg2);
+      ipc_log ("  returning = %s\n", res ? res : "NULL");
+      writeString (res, req);
+      free (res);
+    }
+  else if (!strcmp (inp, "getDataspaceTypeDesc"))
+    {
+      // XXX add an argument = DbeView index
+      Obj arg1 = readObject (req);
+      ipc_log ("  arg1 absent, index = %ld\n", (long) arg1);
+      String res = dbeGetDataspaceTypeDesc (0, arg1);
+      ipc_log ("  returning = %s\n", res ? res : "NULL");
+      writeString (res, req);
+      free (res);
+    }
+    /*
+     *   New Interface with Timeline
+     */
+#if 0 //YXXX TBR
+  else if (!strcmp (inp, "dbeInit"))
+    dbeInit ();
+  else if (!strcmp (inp, "getDefaultExperimentName"))
+    {
+      String res = dbeGetDefaultExperimentName ();
+      ipc_log ("  returning = %s\n", res);
+      writeString (res);
+      free (res);
+    }
+  else if (!strcmp (inp, "getExperimentState"))
+    {
+      String res = dbeGetExperimentState ();
+      ipc_log ("  returning = %s\n", res);
+      writeString (res);
+      free (res);
+    }
+  else if (!strcmp (inp, "getExpStartTime"))
+    {
+      long long l = dbeGetExpStartTime ();
+      ipc_log ("  returns = %llu\n", l);
+      writeLong (l);
+    }
+  else if (!strcmp (inp, "getExpEndTime"))
+    {
+      long long l = dbeGetExpEndTime ();
+      ipc_log ("  returns = %llu\n", l);
+      writeLong (l);
+    }
+#endif
+  else if (!strcmp (inp, "getDataDescriptorsV2"))
+    {//TBR? TBD
+      int exp_id = readInt (req);
+      ipc_log (" exp_id = %d\n", exp_id);
+      Vector<void*> *res = dbeGetDataDescriptorsV2 (exp_id);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getDataPropertiesV2"))
+    {//TBR? TBD
+      int exp_id = readInt (req);
+      int arg2 = readInt (req);
+      ipc_log (" exp_id = %d, data_idx = %d\n", exp_id, arg2);
+      Vector<void*> *res = dbeGetDataPropertiesV2 (exp_id, arg2);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getExperimentTimeInfo"))
+    {
+      Vector<int> *exp_ids = (Vector<int>*)readArray (req);
+      ipc_log ("  cnt = %lld\n", VSIZE (exp_ids));
+      Vector<void*> *res = dbeGetExperimentTimeInfo (exp_ids);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getExperimentDataDescriptors"))
+    {
+      Vector<int> *exp_ids = (Vector<int>*)readArray (req);
+      ipc_log ("  cnt = %lld\n", VSIZE (exp_ids));
+      Vector<void*> *res = dbeGetExperimentDataDescriptors (exp_ids);
+      ipc_log ("  returns = %lld objects\n", VSIZE (res));
+      writeArray (res, req);
+      destroy (res);
+    }
+#if 0 //YXXX TBR?
+  else if (!strcmp (inp, "getExprValues"))
+    {//TBR? TBD
+      int arg1 = readInt ();
+      String arg2 = readString ();
+      ipc_log ("  data_idx = %d expr = %s\n", arg1, arg2 ? arg2 : "NULL");
+      Vector<long long> *res = dbeGetExprValues (arg1, arg2);
+      ipc_log ("  returns = %d objects\n", res ? res->size () : 0);
+      writeArray (res);
+      delete res;
+      free (arg2);
+    }
+#endif
+  else if (!strcmp (inp, "hasTLData"))
+    {
+      int dbevindex = readInt (req);
+      Vector<int> *exp_ids = (Vector<int>*)readArray (req);
+      Vector<int> *data_ids = (Vector<int>*)readArray (req);
+      Vector<int> *eprop_ids = (Vector<int>*)readArray (req);
+      Vector<int> *eprop_vals = (Vector<int>*)readArray (req);
+      Vector<int> *auxs = (Vector<int>*)readArray (req);
+      ipc_log ("  dbev_id = %d, cnt = %lld\n", dbevindex, VSIZE (exp_ids));
+      Vector<bool> *res = dbeHasTLData (dbevindex,
+                                       exp_ids, data_ids, eprop_ids, eprop_vals, auxs);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getTLData"))
+    {
+      int dbevindex = readInt (req);
+      int exp_id = readInt (req);
+      int tldata_type = readInt (req);
+      int entity_prop_id = readInt (req);
+      int entity_prop_val = readInt (req);
+      int aux = readInt (req);
+      long long arg5 = readLong (req);
+      long long arg6 = readLong (req);
+      int arg7 = readInt (req);
+      bool getReps = readBoolean (req);
+      Vector<String> *secondaryProps = (Vector<String>*)readArray (req);
+
+      ipc_log ("  args = %d:%d; tldata_type=%d entity_prop_id=%d ent=%d aux=%d"
+              "\n    tstart=%lld delta=%lld ndeltas=%d getReps=%d nProps=%lld\n",
+              dbevindex, exp_id,
+              tldata_type, entity_prop_id, entity_prop_val, aux,
+              arg5, arg6, arg7, (int) getReps, VSIZE (secondaryProps));
+      Vector<void*> *res = dbeGetTLData (dbevindex, exp_id,
+                                        tldata_type, entity_prop_id, entity_prop_val, aux,
+                                        arg5, arg6, arg7, getReps, secondaryProps);
+#ifdef IPC_LOG
+      if (res)
+       {
+         Vector<Obj> *reps = (Vector<Obj>*)res->fetch (0);
+         Vector<Obj> *props = (Vector<Obj>*)res->fetch (1);
+         if (reps)
+           {
+             Vector <long long> *fids = (Vector <long long> *)reps->fetch (2);
+             int sz = fids ? fids->size () : 0;
+             ipc_log ("  returning TL reps (dDscrs); nreps=%d:", sz);
+             int i;
+             for (i = 0; i < sz && i < 7; i++)
+               ipc_log (" %lld", fids->fetch (i));
+             if (i < sz)
+               ipc_log (" ... %lld", fids->fetch (sz - 1));
+             ipc_log ("\n");
+           }
+         if (props)
+           {
+             int nprops = props->size ();
+             ipc_log ("  returning values for %d properties:\n", nprops);
+             assert (secondaryProps->size () == nprops);
+           }
+       }
+      else
+       ipc_log ("  returning NULL\n");
+#endif
+      writeArray (res, req);
+      destroy (res);
+      destroy (secondaryProps);
+    }
+  else if (!strcmp (inp, "getTLEventCenterTime"))
+    {
+      int dbevindex = readInt (req);
+      int exp_id = readInt (req);
+      int tldata_type = readInt (req);
+      int entity_prop_id = readInt (req);
+      int entity_prop_val = readInt (req);
+      int aux = readInt (req);
+      long long event_id = readLong (req);
+      long long move_count = readLong (req);
+      ipc_log ("  args = %d:%d; tldata_type = %d entity_prop_id = %d "
+              "ent = %d aux = %d idx = %lld move=%lld\n",
+              dbevindex, exp_id,
+              tldata_type, entity_prop_id, entity_prop_val, aux, event_id, move_count);
+      Vector<long long> * res = dbeGetTLEventCenterTime (dbevindex, exp_id,
+                                                        tldata_type, entity_prop_id, entity_prop_val, aux, event_id, move_count);
+      ipc_log ("  returning  idx = %lld, time = %lld\n",
+              res ? res->fetch (0) : -1, res ? res->fetch (1) : -1);
+      writeArray (res, req);
+    }
+  else if (!strcmp (inp, "getTLEventIdxNearTime"))
+    {
+      int dbevindex = readInt (req);
+      int exp_id = readInt (req);
+      int tldata_type = readInt (req);
+      int entity_prop_id = readInt (req);
+      int entity_prop_val = readInt (req);
+      int aux = readInt (req);
+      int searchDirection = readInt (req);
+      long long value = readLong (req);
+      ipc_log ("  args = %d:%d; tldata_type = %d entity_prop_id = %d "
+              "ent = %d aux = %d direction = %d value = %lld(0x%llx)\n",
+              dbevindex, exp_id,
+              tldata_type, entity_prop_id, entity_prop_val, aux,
+              searchDirection, value, value);
+      long long res = dbeGetTLEventIdxNearTime (dbevindex, exp_id,
+                                               tldata_type, entity_prop_id, entity_prop_val, aux,
+                                               searchDirection, value);
+      ipc_log ("  returning = %lld\n", res);
+      writeLong (res, req);
+    }
+  else if (!strcmp (inp, "getAggregatedValue"))
+    {
+      int arg1 = readInt (req);
+      String arg2 = readString (req);
+      String arg3 = readString (req);
+      String arg4 = readString (req);
+      long long arg5 = readLong (req);
+      long long arg6 = readLong (req);
+      int arg7 = readInt (req);
+      String arg8 = readString (req);
+      String arg9 = readString (req);
+      ipc_log ("  data_idx = %d lfilter = \"%s\" fexpr = \"%s\" "
+              "time = \"%s\" tstart = %lld delta = %lld "
+              "num = %d key = \"%s\" aggr = \"%s\"\n",
+              arg1, arg2 ? arg2 : "NULL", arg3 ? arg3 : "NULL",
+              arg4 ? arg4 : "NULL", arg5, arg6,
+              arg7, arg8 ? arg8 : "NULL", arg9 ? arg9 : "NULL");
+      Vector<long long> *res = dbeGetAggregatedValue (arg1, arg2, arg3,
+                                                     arg4, arg5, arg6, arg7, arg8, arg9);
+#ifdef IPC_LOG
+      if (res)
+       {
+         int sz = res->size ();
+         ipc_log ("  returning = %d values:", sz);
+         if (sz > 10)
+           sz = 10;
+         for (int i = 0; i < sz; i++)
+           ipc_log (" %lld", res->fetch (i));
+         ipc_log ("\n");
+       }
+      else
+       ipc_log ("  returning NULL\n");
+#endif
+      writeArray (res, req);
+      delete res;
+      free (arg2);
+      free (arg3);
+      free (arg4);
+      free (arg8);
+      free (arg9);
+    }
+#if 0//YXXX TBR
+  else if (!strcmp (inp, "getExprValue"))
+    {
+      int exp_id = readInt ();
+      int arg1 = readInt ();
+      int arg2 = readInt ();
+      String arg3 = readString ();
+      ipc_log ("  exp_id %d, data_id = %d, event_id = %d, expr = %s\n",
+              exp_id, arg1, arg2, arg3 ? arg3 : "NULL");
+      String res = dbeGetExprValue (exp_id, arg1, arg2, arg3);
+      ipc_log ("  returning = %s\n", res ? res : "");
+      writeString (res);
+      free (res);
+      free (arg3);
+    }
+  else if (!strcmp (inp, "getListValues"))
+    {
+      Obj arg1 = readObject ();
+      ipc_log ("  stack = %lu\n", (long) arg1);
+      Vector<Obj> *res = dbeGetListValues (arg1);
+      ipc_log ("  returns = %d objects\n", res ? res->size () : 0);
+      writeArray (res);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getListNames"))
+    {
+      Obj arg1 = readObject ();
+      ipc_log ("  stack = %lu\n", (long) arg1);
+      Vector<String> *res = dbeGetListNames (arg1);
+      ipc_log ("  returns = %d objects\n", res ? res->size () : 0);
+      writeArray (res);
+      destroy (res);
+    }
+#endif
+  else if (!strcmp (inp, "getLineInfo"))
+    {
+      Obj arg1 = readObject (req);
+      ipc_log ("  pc = %lu\n", (long) arg1);
+      Vector<String> *res = dbeGetLineInfo (arg1);
+      ipc_log ("  returning File name: '%s'\n", res ? res->fetch (0) : "");
+      ipc_log ("  returning Lineno:    '%s'\n", res ? res->fetch (1) : "");
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "setAlias"))
+    {
+      String arg1 = readString (req);
+      String arg2 = readString (req);
+      String arg3 = readString (req);
+      ipc_log ("  name=\"%s\" uname=\"%s\" expr=\"%s\"\n",
+              arg1 ? arg1 : "", arg2 ? arg2 : "", arg3 ? arg3 : "");
+      int res = dbeSetAlias (arg1, arg2, arg3);
+      ipc_log ("  returning = %d\n", res);
+      writeInt (res, req);
+    }
+  else if (!strcmp (inp, "getAlias"))
+    {
+      String arg1 = readString (req);
+      ipc_log ("  name=\"%s\"\n", arg1 ? arg1 : "");
+      Vector<char*> *res = dbeGetAlias (arg1);
+      ipc_log ("  returning uname: '%s'\n", res && res->fetch (0) ? res->fetch (0) : "");
+      ipc_log ("  returning expr:  '%s'\n", res && res->fetch (1) ? res->fetch (0) : "");
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getXYPlotData"))
+    {
+      int arg1 = readInt (req);
+      String arg2 = readString (req);
+      String arg3 = readString (req);
+      String arg4 = readString (req);
+      String arg5 = readString (req);
+      String arg6 = readString (req);
+      String arg7 = readString (req);
+      String arg8 = readString (req);
+      String arg9 = readString (req);
+      ipc_log ("  data_idx = %d lfilter = \"%s\" arg = \"%s\" "
+              "func1 = \"%s\" aggr1 = \"%s\" "
+              "func2 = \"%s\" aggr2 = \"%s\" "
+              "func3 = \"%s\" aggr3 = \"%s\" \n",
+              arg1, arg2 ? arg2 : "NULL", arg3 ? arg3 : "NULL",
+              arg4 ? arg4 : "NULL", arg5 ? arg5 : "NULL", arg6 ? arg6 : "NULL",
+              arg7 ? arg7 : "NULL", arg8 ? arg8 : "NULL", arg9 ? arg9 : "NULL");
+      Vector<Vector<long long>*> *res = dbeGetXYPlotData (arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
+
+#ifdef IPC_LOG
+      if (res)
+       {
+         long nvals = res->size ();
+         for (long i = 0; i < nvals; ++i)
+           {
+             Vector<long long> *vals = res->fetch (i);
+             long long sz = VSIZE (vals);
+             ipc_log ("  returning = %lld values:", sz);
+             if (sz > 10)
+               sz = 10;
+             for (long j = 0; j < sz; j++)
+               ipc_log (" %lld", vals->fetch (j));
+             ipc_log ("\n");
+           }
+       }
+      else
+       ipc_log ("  returning NULL\n");
+#endif
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (strcmp (inp, "dbe_archive") == 0)
+    {
+      Vector<long long> *ids = (Vector<long long> *) readArray (req);
+      Vector<const char*> *locations = (Vector<const char*> *) readArray (req);
+      dbe_archive (ids, locations);
+      delete ids;
+      destroy (locations);
+      writeResponseGeneric (RESPONSE_STATUS_SUCCESS, currentRequestID, currentChannelID);
+    }
+  else if (strcmp (inp, "dbeSetLocations") == 0)
+    {
+      Vector<const char*> *fnames = (Vector<const char*> *) readArray (req);
+      Vector<const char*> *locations = (Vector<const char*> *) readArray (req);
+      dbeSetLocations (fnames, locations);
+      destroy (fnames);
+      destroy (locations);
+      writeResponseGeneric (RESPONSE_STATUS_SUCCESS, currentRequestID, currentChannelID);
+    }
+  else if (strcmp (inp, "dbeResolvedWith_setpath") == 0)
+    {
+      char *path = readString (req);
+      Vector<void *> *res = dbeResolvedWith_setpath (path);
+      free (path);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (strcmp (inp, "dbeResolvedWith_pathmap") == 0)
+    {
+      char *old_prefix = readString (req);
+      char *new_prefix = readString (req);
+      Vector<void *> *res = dbeResolvedWith_pathmap (old_prefix, new_prefix);
+      free (old_prefix);
+      free (new_prefix);
+      writeArray (res, req);
+      destroy (res);
+    }
+  else if (!strcmp (inp, "getCollectorControlValue"))
+    {
+      /* int dbevindex =*/ readInt (req);
+      char *control = readString (req);
+      ipc_log ("  args = %s\n", control);
+      char *ret = dbeGetCollectorControlValue (control);
+      ipc_log ("  returning %s\n", STR (ret));
+      writeString (ret, req);
+    }
+  else if (!strcmp (inp, "setCollectorControlValue"))
+    {
+      /* int dbevindex =*/ readInt (req);
+      char *control = readString (req);
+      char *value = readString (req);
+#ifdef IPC_LOG
+      ipc_log ("  args = %s %s\n", control, value);
+#endif
+      char *ret = dbeSetCollectorControlValue (control, value);
+#ifdef IPC_LOG
+      if (ret)
+       ipc_log ("  returning %s\n", ret);
+      else
+       ipc_log ("  returning NULL\n");
+#endif
+      writeString (ret, req);
+    }
+  else if (!strcmp (inp, "unsetCollectorControlValue"))
+    {
+      /* int dbevindex =*/ readInt (req);
+      char *control = readString (req);
+      ipc_log ("  args = %s\n", control);
+      char *ret = dbeUnsetCollectorControlValue (control);
+      ipc_log ("  returning %s\n", STR (ret));
+      writeString (ret, req);
+    }
+  else if (!strcmp (inp, "getSignalValue"))
+    {
+      String arg1 = readString (req);
+      ipc_log ("  arg1=\"%s\"\n", arg1 ? arg1 : "");
+      int res = dbeGetSignalValue (arg1);
+      ipc_log ("  returning = %d\n", res);
+      writeInt (res, req);
+    }
+  else if (!strcmp (inp, "sendSignal"))
+    {
+      long long p = readLong (req);
+      int signum = readInt (req);
+      ipc_log ("  args = %llu, %d\n", (long long) p, signum);
+      char * ret = dbeSendSignal ((pid_t) p, signum);
+#ifdef IPC_LOG
+      if (ret)
+       ipc_log ("  returning %s\n", ret);
+      else
+       ipc_log ("  returning NULL\n");
+#endif
+      writeString (ret, req);
+    }
+  else if (!strcmp (inp, "checkConnection"))
+    {
+      String arg1 = readString (req);
+      ipc_log ("  arg = `%s'\n", arg1 ? arg1 : "NULL");
+      String res = dbeCheckConnection (arg1);
+      writeString (res, req);
+      ipc_log ("  returns `%s'\n", res ? res : "NULL");
+      free (arg1);
+      free (res);
+    }
+  else if (!strcmp (inp, "QUIT"))
+    {
+#ifdef IPC_LOG
+      ipc_log ("  %s\n", inp);
+#endif
+      exit (0);
+    }
+  else
+    {
+      ipc_log ("Unrecognized input cmd \"%s\"; Aborting.\n", inp);
+      return 1;
+    }
+  ipc_log ("  processing IPC command %s complete\n", inp);
+  free (inp);
+  fflush (stdout);
+  if (req->getStatus () != CANCELLED_IMMEDIATE)
+    // wake up the main working thread, let it take care of delete
+    req->setStatus (COMPLETED);
+  delete req;
+  return 0;
+}
+
+void
+check_env_args (int argc, char *argv[])
+{
+  int indx = 2; // Skip "-IPC"
+  const char *MINUS_E = "-E";
+  const char *SP_ER_PRINT_TRACE_LEVEL = "SP_ER_PRINT_TRACE_LEVEL";
+  const char *SP_IPC_PROTOCOL = "SP_IPC_PROTOCOL";
+  const char SEPARATOR = '=';
+  char *cmd_env_var = NULL;
+  while (argc - indx >= 2)
+    {
+      char *option = argv[indx++];
+      if (!streq (option, MINUS_E))
+       continue;
+      cmd_env_var = argv[indx++];
+      char *separator = strchr (cmd_env_var, SEPARATOR);
+      if (!separator)
+       // Unrecognized option. Fatal error?
+       continue;
+      char *cmd_env_var_val = separator + 1;
+      if (!strncmp (cmd_env_var, SP_ER_PRINT_TRACE_LEVEL,
+                   strlen (SP_ER_PRINT_TRACE_LEVEL)))
+       {
+         if (streq (cmd_env_var_val, "1"))
+           ipc_trace_level = TRACE_LVL_1;
+         else if (streq (cmd_env_var_val, "2"))
+           ipc_trace_level = TRACE_LVL_2;
+         else if (streq (cmd_env_var_val, "3"))
+           ipc_trace_level = TRACE_LVL_3;
+         else if (streq (cmd_env_var_val, "4"))
+           ipc_trace_level = TRACE_LVL_4;
+         continue;
+       }
+      if (!strncmp (cmd_env_var, SP_IPC_PROTOCOL, strlen (SP_IPC_PROTOCOL)))
+       {
+         if (streq (cmd_env_var_val, IPC_PROTOCOL_CURR))
+           // Only one protocol is currently supported
+           ipc_protocol = IPC_PROTOCOL_CURR;
+         else
+           ipc_protocol = IPC_PROTOCOL_UNKNOWN;
+         continue;
+       }
+      // Unrecognized option. Fatal error?
+    }
+}
+
+void
+print_ipc_protocol_confirmation ()
+{
+  if (NULL != ipc_protocol)
+    {
+      fprintf (stdout, "ER_IPC: %s\n", ipc_protocol);
+      fflush (stdout);
+    }
+}
+
+void
+ipc_mainLoop (int argc, char *argv[])
+{
+  if (getenv ("GPROFNG_DBE_DELAY"))
+    sleep (20);
+#ifdef IPC_LOG
+  ipc_flags = 1;
+#endif
+  // check_env_args(argc, argv);
+
+  char *er_print_trace_level = getenv ("SP_ER_PRINT_TRACE_LEVEL");
+  if (er_print_trace_level != NULL)
+    {
+      if (streq (er_print_trace_level, "1"))
+       ipc_trace_level = TRACE_LVL_1;
+      else if (streq (er_print_trace_level, "2"))
+       ipc_trace_level = TRACE_LVL_2;
+      else if (streq (er_print_trace_level, "3"))
+       ipc_trace_level = TRACE_LVL_3;
+      else if (streq (er_print_trace_level, "4"))
+       ipc_trace_level = TRACE_LVL_4;
+    }
+  check_env_args (argc, argv);
+  print_ipc_protocol_confirmation ();
+
+  if (ipc_flags || getenv ("SP_ER_PRINT_IPC_FLAG") || ipc_trace_level > TRACE_LVL_0)
+    {
+      ipc_flags = 1;
+      if (ipc_trace_level == TRACE_LVL_0)
+       ipc_trace_level = TRACE_LVL_1;
+      // reopen stderr as file "ipc_log"
+      ipc_log_name = getenv ("SP_ER_PRINT_IPC_LOG");
+      if (ipc_log_name == NULL)
+       ipc_log_name = "ipc_log";
+      freopen (ipc_log_name, "w", stderr);
+      if (ipc_trace_level >= TRACE_LVL_2)
+       {
+         ipc_request_log_name = "ipc_request_log";
+         ipc_response_log_name = "ipc_response_log";
+         requestLogFileP = fopen (ipc_request_log_name, "w");
+         responseLogFileP = fopen (ipc_response_log_name, "w");
+       }
+      else
+       {
+         ipc_request_log_name = "ipc_log";
+         ipc_response_log_name = "ipc_log";
+       }
+      begin_time = gethrtime ();
+    }
+  else
+    // Reopen stderr as /dev/null
+    freopen ("/dev/null", "w", stderr);
+
+  struct sigaction act;
+  memset (&act, 0, sizeof (struct sigaction));
+  term_flag = 0;
+  /* install a handler for TERM */
+  ipc_request_trace (TRACE_LVL_1, "Installing SIGTERM handler to abort on error\n");
+  sigemptyset (&act.sa_mask);
+  act.sa_handler = (SignalHandler) sigterm_handler;
+  act.sa_flags = SA_RESTART | SA_SIGINFO;
+  if (sigaction (SIGTERM, &act, &old_sigterm_handler) == -1)
+    {
+      ipc_request_trace (TRACE_LVL_1, "Unable to install SIGTERM handler\n");
+      abort ();
+    }
+  /* install a handler for INT */
+  ipc_request_trace (TRACE_LVL_1, "Installing SIGINT handler to send message to analyzer\n");
+  sigemptyset (&act.sa_mask);
+  act.sa_handler = (SignalHandler) sigint_handler;
+  act.sa_flags = SA_RESTART | SA_SIGINFO;
+  if (sigaction (SIGINT, &act, &old_sigint_handler) == -1)
+    {
+      ipc_request_trace (TRACE_LVL_1, "Unable to install SIGINT handler\n");
+      abort ();
+    }
+  ipc_log ("Installed SIGINT handler to handle Ctrl-C properly\n");
+  int er_print_catch_crash = 1; // Default: catch fatal signals
+  char *s = getenv ("GPROFNG_ALLOW_CORE_DUMP");
+  if (s && (strcasecmp (s, "no") == 0 || strcmp (s, "0") == 0))
+    er_print_catch_crash = 0;
+  if (er_print_catch_crash)
+    {
+      /* reserve memory for fatal error processing */
+      fatalErrorDynamicMemory = (char *) malloc (4 * 1024 * 1024); // reserve 4 MB
+      /* install a handler for SIGABRT */
+      ipc_request_trace (TRACE_LVL_1, "Installing SIGABRT handler to send message to analyzer\n");
+      sigemptyset (&act.sa_mask);
+      act.sa_handler = (SignalHandler) sigABRT_handler;
+      act.sa_flags = SA_RESTART | SA_SIGINFO;
+      if (sigaction (SIGABRT, &act, NULL) == -1)
+       {
+         ipc_request_trace (TRACE_LVL_1, "Unable to install SIGABRT handler\n");
+         // abort();
+       }
+      else
+       ipc_log ("Installed SIGABRT handler to handle crash properly\n");
+      /* install a handler for SIGSEGV */
+      ipc_request_trace (TRACE_LVL_1, "Installing SIGABRT handler to send message to analyzer\n");
+      sigemptyset (&act.sa_mask);
+      act.sa_handler = (SignalHandler) sigSEGV_handler;
+      act.sa_flags = SA_RESTART | SA_SIGINFO;
+      if (sigaction (SIGSEGV, &act, NULL) == -1)
+       {
+         ipc_request_trace (TRACE_LVL_1, "Unable to install SIGSEGV handler\n");
+         // abort();
+       }
+      else
+       ipc_log ("Installed SIGSEGV handler to handle crash properly\n");
+    }
+  ipc_request_trace (TRACE_LVL_1, "Entering ipc_mainLoop; run dir `%s'\n",
+                    theApplication->get_run_dir ());
+  cancelRequestedChannelID = 0xFFFFFFFF;
+  ipcThreadPool = new DbeThreadPool (0); // DbeThreadPool (-1);
+  responseBufferPool = new BufferPool ();
+  ipc_log (ipc_single_threaded_mode ?
+          "RUNNING er_print -IPC IN SINGLE THREADED MODE\n" :
+          "RUNNING er_print -IPC IN MULTITHREAD MODE\n");
+
+  /* Send "Ready" signal to the GUI */
+  setProgress (100, "Restart engine");
+
+  /* start listening for requests */
+  error_flag = 0;
+  for (;;)
+    {
+      readRequestHeader ();
+      if (term_flag == 1 || error_flag == 1)
+       {
+         ipc_request_trace (TRACE_LVL_1, "SIGTERM received, exiting\n");
+         return;
+       }
+    }
+}
+
+static const char *
+table_name (int flavor)
+{
+  static char def_name[64];
+
+  switch ((FuncListDisp_type) flavor)
+    {
+    case DSP_FUNCTION:
+      return ("FUNCTION");
+    case DSP_LINE:
+      return ("LINE");
+    case DSP_PC:
+      return ("PC");
+    case DSP_SOURCE:
+      return ("SOURCE");
+    case DSP_DISASM:
+      return ("DISASM");
+    case DSP_SELF:
+      return ("SELF");
+    case DSP_CALLER:
+      return ("CALLER");
+    case DSP_CALLEE:
+      return ("CALLEE");
+    case DSP_CALLTREE:
+      return ("CALLTREE");
+    case DSP_TIMELINE:
+      return ("TIMELINE");
+    case DSP_STATIS:
+      return ("STATIS");
+    case DSP_EXP:
+      return ("EXP");
+    case DSP_LEAKLIST:
+      return ("LEAKLIST");
+    case DSP_HEAPCALLSTACK:
+      return ("HEAP");
+    case DSP_MEMOBJ:
+      return ("MEMOBJ");
+    case DSP_DATAOBJ:
+      return ("DATAOBJ");
+    case DSP_DLAYOUT:
+      return ("DLAYOUT");
+    case DSP_SRC_FILE:
+      return ("SRC_FILE");
+    case DSP_IFREQ:
+      return ("IFREQ");
+    case DSP_RACES:
+      return ("RACES");
+    case DSP_INDXOBJ:
+      return ("INDXOBJ");
+    case DSP_DUALSOURCE:
+      return ("DUALSOURCE");
+    case DSP_SOURCE_DISASM:
+      return ("SOURCE_DISASM");
+    case DSP_DEADLOCKS:
+      return ("DEADLOCKS");
+    case DSP_SOURCE_V2:
+      return ("SOURCE_V2");
+    case DSP_DISASM_V2:
+      return ("DISASM_V2");
+    case DSP_IOACTIVITY:
+      return ("IOACTIVITY");
+    case DSP_OVERVIEW:
+      return ("OVERVIEW");
+    case DSP_SAMPLE:
+      return ("SAMPLE -- UNEXPECTED");
+    default:
+      snprintf (def_name, sizeof (def_name), "table number %d", flavor);
+      return (def_name);
+    }
+}
diff --git a/gprofng/src/ipcio.cc b/gprofng/src/ipcio.cc
new file mode 100644 (file)
index 0000000..57f2617
--- /dev/null
@@ -0,0 +1,1025 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <queue>
+#include "vec.h"
+#include "util.h"
+#include "ipcio.h"
+#include "DbeThread.h"
+#include "Experiment.h"
+
+#define ipc_trace               if (ipc_flags) ipc_default_log
+#define ipc_request_trace       if (ipc_flags) ipc_request_log
+#define ipc_response_trace      if (ipc_flags) ipc_response_log
+
+using namespace std;
+
+// IPC implementation
+static const int L_PROGRESS = 0;
+static const int L_INTEGER  = 1;
+static const int L_BOOLEAN  = 2;
+static const int L_LONG     = 3;
+static const int L_STRING   = 4;
+static const int L_DOUBLE   = 5;
+static const int L_ARRAY    = 6;
+static const int L_OBJECT   = 7;
+static const int L_CHAR     = 8;
+
+int currentRequestID;
+int currentChannelID;
+static long maxSize;
+
+extern int cancellableChannelID;
+extern int error_flag;
+extern int ipc_delay_microsec;
+extern FILE *responseLogFileP;
+
+IPCresponse *IPCresponseGlobal;
+
+BufferPool *responseBufferPool;
+
+IPCrequest::IPCrequest (int sz, int reqID, int chID)
+{
+  size = sz;
+  requestID = reqID;
+  channelID = chID;
+  status = INITIALIZED;
+  idx = 0;
+  buf = (char *) malloc (size);
+  cancelImmediate = false;
+}
+
+IPCrequest::~IPCrequest ()
+{
+  free (buf);
+}
+
+void
+IPCrequest::read (void)
+{
+  for (int i = 0; i < size; i++)
+    {
+      int c = getc (stdin);
+      ipc_request_trace (TRACE_LVL_4, "  IPCrequest:getc(stdin): %02x\n", c);
+      buf[i] = c;
+    }
+}
+
+IPCrequestStatus
+IPCrequest::getStatus (void)
+{
+  return status;
+}
+
+void
+IPCrequest::setStatus (IPCrequestStatus newStatus)
+{
+  status = newStatus;
+}
+
+static int
+readByte (IPCrequest* req)
+{
+  int c;
+  int val = 0;
+  for (int i = 0; i < 2; i++)
+    {
+      if (req == NULL)
+       {
+         c = getc (stdin);
+         ipc_request_trace (TRACE_LVL_4, "  readByte:getc(stdin): %02x\n", c);
+       }
+      else
+       c = req->rgetc ();
+      switch (c)
+       {
+       case '0': case '1': case '2': case '3':
+       case '4': case '5': case '6': case '7':
+       case '8': case '9':
+         val = val * 16 + c - '0';
+         break;
+       case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+         val = val * 16 + c - 'a' + 10;
+         break;
+       case EOF:
+         val = EOF;
+         break;
+       default:
+         fprintf (stderr, "readByte: Unknown byte: %d\n", c);
+         break;
+       }
+    }
+  return val;
+}
+
+static int
+readIVal (IPCrequest *req)
+{
+  int val = readByte (req);
+  for (int i = 0; i < 3; i++)
+    val = val * 256 + readByte (req);
+  ipc_trace ("  readIVal: %d\n", val);
+  return val;
+}
+
+static String
+readSVal (IPCrequest *req)
+{
+  int len = readIVal (req);
+  if (len == -1)
+    {
+      ipc_trace ("  readSVal: <NULL>\n");
+      return NULL;
+    }
+  char *str = (char *) malloc (len + 1);
+  char *s = str;
+  *s = (char) 0;
+  while (len--)
+    *s++ = req->rgetc ();
+  *s = (char) 0;
+  ipc_trace ("  readSVal: '%s'\n", str);
+  return str;
+}
+
+static long long
+readLVal (IPCrequest *req)
+{
+  long long val = readByte (req);
+  for (int i = 0; i < 7; i++)
+    val = val * 256 + readByte (req);
+  ipc_trace ("  readLVal: %lld\n", val);
+  return val;
+}
+
+static bool
+readBVal (IPCrequest *req)
+{
+  int val = readByte (req);
+  ipc_trace ("  readBVal: %s\n", val == 0 ? "true" : "false");
+  return val != 0;
+}
+
+static char
+readCVal (IPCrequest *req)
+{
+  int val = readByte (req);
+  ipc_trace ("  readCVal: %d\n", val);
+  return (char) val;
+}
+
+static double
+readDVal (IPCrequest *req)
+{
+  String s = readSVal (req);
+  double d = atof (s);
+  free (s);
+  return d;
+}
+
+static Object
+readAVal (IPCrequest *req)
+{
+  bool twoD = false;
+  int type = readByte (req);
+  if (type == L_ARRAY)
+    {
+      twoD = true;
+      type = readByte (req);
+    }
+  ipc_trace ("readAVal: twoD=%s type=%d\n", twoD ? "true" : "false", type);
+
+  int len = readIVal (req);
+  if (len == -1)
+    return NULL;
+  switch (type)
+    {
+    case L_INTEGER:
+      if (twoD)
+       {
+         Vector<Vector<int>*> *array = new Vector<Vector<int>*>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, (Vector<int>*)readAVal (req));
+         return array;
+       }
+      else
+       {
+         Vector<int> *array = new Vector<int>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, readIVal (req));
+         return array;
+       }
+      //break;
+    case L_LONG:
+      if (twoD)
+       {
+         Vector<Vector<long long>*> *array = new Vector<Vector<long long>*>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, (Vector<long long>*)readAVal (req));
+         return array;
+       }
+      else
+       {
+         Vector<long long> *array = new Vector<long long>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, readLVal (req));
+         return array;
+       }
+      //break;
+    case L_DOUBLE:
+      if (twoD)
+       {
+         Vector<Vector<double>*> *array = new Vector<Vector<double>*>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, (Vector<double>*)readAVal (req));
+         return array;
+       }
+      else
+       {
+         Vector<double> *array = new Vector<double>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, readDVal (req));
+         return array;
+       }
+      //break;
+    case L_BOOLEAN:
+      if (twoD)
+       {
+         Vector < Vector<bool>*> *array = new Vector < Vector<bool>*>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, (Vector<bool>*)readAVal (req));
+         return array;
+       }
+      else
+       {
+         Vector<bool> *array = new Vector<bool>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, readBVal (req));
+         return array;
+       }
+      //break;
+    case L_CHAR:
+      if (twoD)
+       {
+         Vector<Vector<char>*> *array = new Vector<Vector<char>*>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, (Vector<char>*)readAVal (req));
+         return array;
+       }
+      else
+       {
+         Vector<char> *array = new Vector<char>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, readCVal (req));
+         return array;
+       }
+      //break;
+    case L_STRING:
+      if (twoD)
+       {
+         Vector<Vector<String>*> *array = new Vector<Vector<String>*>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, (Vector<String>*)readAVal (req));
+         return array;
+       }
+      else
+       {
+         Vector<String> *array = new Vector<String>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, readSVal (req));
+         return array;
+       }
+      //break;
+    case L_OBJECT:
+      if (twoD)
+       {
+         Vector<Vector<Object>*> *array = new Vector<Vector<Object>*>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, (Vector<Object>*)readAVal (req));
+         return array;
+       }
+      else
+       {
+         Vector<Object> *array = new Vector<Object>(len);
+         for (int i = 0; i < len; i++)
+           array->store (i, readAVal (req));
+         return array;
+       }
+      //break;
+    default:
+      fprintf (stderr, "readAVal: Unknown code: %d\n", type);
+      break;
+    }
+  return NULL;
+}
+
+static int iVal;
+static bool bVal;
+static long long lVal;
+static String sVal;
+static double dVal;
+static Object aVal;
+
+static void
+readResult (int type, IPCrequest *req)
+{
+  int tVal = readByte (req);
+  switch (tVal)
+    {
+    case L_INTEGER:
+      iVal = readIVal (req);
+      break;
+    case L_LONG:
+      lVal = readLVal (req);
+      break;
+    case L_BOOLEAN:
+      bVal = readBVal (req);
+      break;
+    case L_DOUBLE:
+      dVal = readDVal (req);
+      break;
+    case L_STRING:
+      sVal = readSVal (req);
+      break;
+    case L_ARRAY:
+      aVal = readAVal (req);
+      break;
+    case EOF:
+      fprintf (stderr, "EOF read in readResult\n");
+      sVal = NULL;
+      return;
+    default:
+      fprintf (stderr, "Unknown code: %d\n", tVal);
+      abort ();
+    }
+  if (type != tVal)
+    {
+      fprintf (stderr, "Internal error: readResult: parameter mismatch: type=%d should be %d\n", tVal, type);
+      abort ();
+    }
+}
+
+int
+readInt (IPCrequest *req)
+{
+  readResult (L_INTEGER, req);
+  return iVal;
+}
+
+String
+readString (IPCrequest *req)
+{
+  readResult (L_STRING, req);
+  return sVal;
+}
+
+long long
+readLong (IPCrequest *req)
+{
+  readResult (L_LONG, req);
+  return lVal;
+}
+
+double
+readDouble (IPCrequest *req)
+{
+  readResult (L_DOUBLE, req);
+  return dVal;
+}
+
+bool
+readBoolean (IPCrequest *req)
+{
+  readResult (L_BOOLEAN, req);
+  return bVal;
+}
+
+DbeObj
+readObject (IPCrequest *req)
+{
+  readResult (L_LONG, req);
+  return (DbeObj) lVal;
+}
+
+Object
+readArray (IPCrequest *req)
+{
+  readResult (L_ARRAY, req);
+  return aVal;
+}
+
+// Write
+IPCresponse::IPCresponse (int sz)
+{
+  requestID = -1;
+  channelID = -1;
+  responseType = -1;
+  responseStatus = RESPONSE_STATUS_SUCCESS;
+  sb = new StringBuilder (sz);
+  next = NULL;
+}
+
+IPCresponse::~IPCresponse ()
+{
+  delete sb;
+}
+
+void
+IPCresponse::reset ()
+{
+  requestID = -1;
+  channelID = -1;
+  responseType = -1;
+  responseStatus = RESPONSE_STATUS_SUCCESS;
+  sb->setLength (0);
+}
+
+void
+IPCresponse::sendByte (int b)
+{
+  ipc_trace ("sendByte: %02x %d\n", b, b);
+  sb->appendf ("%02x", b);
+}
+
+void
+IPCresponse::sendIVal (int i)
+{
+  ipc_trace ("sendIVal: %08x %d\n", i, i);
+  sb->appendf ("%08x", i);
+}
+
+void
+IPCresponse::sendLVal (long long l)
+{
+  ipc_trace ("sendLVal: %016llx %lld\n", l, l);
+  sb->appendf ("%016llx", l);
+}
+
+void
+IPCresponse::sendSVal (const char *s)
+{
+  if (s == NULL)
+    {
+      sendIVal (-1);
+      return;
+    }
+  sendIVal ((int) strlen (s));
+  ipc_trace ("sendSVal: %s\n", s);
+  sb->appendf ("%s", s);
+}
+
+void
+IPCresponse::sendBVal (bool b)
+{
+  sendByte (b ? 1 : 0);
+}
+
+void
+IPCresponse::sendCVal (char c)
+{
+  sendByte (c);
+}
+
+void
+IPCresponse::sendDVal (double d)
+{
+  char str[32];
+  snprintf (str, sizeof (str), "%.12f", d);
+  sendSVal (str);
+}
+
+void
+IPCresponse::sendAVal (void *ptr)
+{
+  if (ptr == NULL)
+    {
+      sendByte (L_INTEGER);
+      sendIVal (-1);
+      return;
+    }
+
+  VecType type = ((Vector<void*>*)ptr)->type ();
+  switch (type)
+    {
+    case VEC_INTEGER:
+      {
+       sendByte (L_INTEGER);
+       Vector<int> *array = (Vector<int>*)ptr;
+       sendIVal (array->size ());
+       for (int i = 0; i < array->size (); i++)
+         sendIVal (array->fetch (i));
+       break;
+      }
+    case VEC_BOOL:
+      {
+       sendByte (L_BOOLEAN);
+       Vector<bool> *array = (Vector<bool>*)ptr;
+       sendIVal (array->size ());
+       for (int i = 0; i < array->size (); i++)
+         sendBVal (array->fetch (i));
+       break;
+      }
+    case VEC_CHAR:
+      {
+       sendByte (L_CHAR);
+       Vector<char> *array = (Vector<char>*)ptr;
+       sendIVal (array->size ());
+       for (int i = 0; i < array->size (); i++)
+         sendCVal (array->fetch (i));
+       break;
+      }
+    case VEC_LLONG:
+      {
+       sendByte (L_LONG);
+       Vector<long long> *array = (Vector<long long>*)ptr;
+       sendIVal (array->size ());
+       for (int i = 0; i < array->size (); i++)
+         sendLVal (array->fetch (i));
+       break;
+      }
+    case VEC_DOUBLE:
+      {
+       sendByte (L_DOUBLE);
+       Vector<double> *array = (Vector<double>*)ptr;
+       sendIVal (array->size ());
+       for (int i = 0; i < array->size (); i++)
+         sendDVal (array->fetch (i));
+       break;
+      }
+    case VEC_STRING:
+      {
+       sendByte (L_STRING);
+       Vector<String> *array = (Vector<String>*)ptr;
+       sendIVal (array->size ());
+       for (int i = 0; i < array->size (); i++)
+         sendSVal (array->fetch (i));
+       break;
+      }
+    case VEC_STRINGARR:
+      {
+       sendByte (L_ARRAY);
+       sendByte (L_STRING);
+       Vector<void*> *array = (Vector<void*>*)ptr;
+       sendIVal (array->size ());
+       for (int i = 0; i < array->size (); i++)
+         sendAVal (array->fetch (i));
+       break;
+      }
+    case VEC_INTARR:
+      {
+       sendByte (L_ARRAY);
+       sendByte (L_INTEGER);
+       Vector<void*> *array = (Vector<void*>*)ptr;
+       sendIVal (array->size ());
+       for (int i = 0; i < array->size (); i++)
+         sendAVal (array->fetch (i));
+       break;
+      }
+    case VEC_LLONGARR:
+      {
+       sendByte (L_ARRAY);
+       sendByte (L_LONG);
+       Vector<void*> *array = (Vector<void*>*)ptr;
+       sendIVal (array->size ());
+       for (int i = 0; i < array->size (); i++)
+         sendAVal (array->fetch (i));
+       break;
+      }
+    case VEC_VOIDARR:
+      {
+       sendByte (L_OBJECT);
+       Vector<void*> *array = (Vector<void*>*)ptr;
+       sendIVal (array->size ());
+       for (int i = 0; i < array->size (); i++)
+         sendAVal (array->fetch (i));
+       break;
+      }
+    default:
+      fprintf (stderr, "sendAVal: Unknown type: %d\n", type);
+      abort ();
+    }
+}
+
+static void
+writeResponseHeader (int requestID, int responseType, int responseStatus, int nBytes)
+{
+  if (responseType == RESPONSE_TYPE_HANDSHAKE)
+    nBytes = IPC_VERSION_NUMBER;
+  int use_write = 2;
+  ipc_response_trace (TRACE_LVL_1, "ResponseHeaderBegin----- %x ---- %x ----- %x -----%x -------\n", requestID, responseType, responseStatus, nBytes);
+  if (use_write)
+    {
+      char buf[23];
+      if (use_write == 1)
+       {
+         int i = 0;
+         snprintf (buf + i, 3, "%2x", HEADER_MARKER);
+         i += 2;
+         snprintf (buf + i, 9, "%8x", requestID);
+         i += 8;
+         snprintf (buf + i, 3, "%2x", responseType);
+         i += 2;
+         snprintf (buf + i, 3, "%2x", responseStatus);
+         i += 2;
+         snprintf (buf + i, 9, "%8x", nBytes);
+       }
+      else
+       snprintf (buf, 23, "%02x%08x%02x%02x%08x", HEADER_MARKER, requestID,
+                 responseType, responseStatus, nBytes);
+      buf[22] = 0;
+      write (1, buf, 22);
+    }
+  else
+    {
+      cout << setfill ('0') << setw (2) << hex << HEADER_MARKER;
+      cout << setfill ('0') << setw (8) << hex << requestID;
+      cout << setfill ('0') << setw (2) << hex << responseType;
+      cout << setfill ('0') << setw (2) << hex << responseStatus;
+      cout << setfill ('0') << setw (8) << hex << nBytes;
+      cout.flush ();
+    }
+  ipc_response_trace (TRACE_LVL_1, "----------------------------ResponseHeaderEnd\n");
+  if (nBytes > maxSize)
+    {
+      maxSize = nBytes;
+      ipc_trace ("New maxsize %ld\n", maxSize);
+    }
+}
+
+bool
+cancelNeeded (int chID)
+{
+  if (chID == cancellableChannelID && chID == cancelRequestedChannelID)
+    return true;
+  else
+    return false;
+}
+
+static void
+writeResponseWithHeader (int requestID, int channelID, int responseType,
+                        int responseStatus, IPCresponse* os)
+{
+  if (cancelNeeded (channelID))
+    {
+      responseStatus = RESPONSE_STATUS_CANCELLED;
+      ipc_trace ("CANCELLING %d %d\n", requestID, channelID);
+      // This is for gracefully cancelling regular ops like openExperiment - getFiles should never reach here
+    }
+  os->setRequestID (requestID);
+  os->setChannelID (channelID);
+  os->setResponseType (responseType);
+  os->setResponseStatus (responseStatus);
+  os->print ();
+  os->reset ();
+  responseBufferPool->recycle (os);
+}
+
+void
+writeAckFast (int requestID)
+{
+  writeResponseHeader (requestID, RESPONSE_TYPE_ACK, RESPONSE_STATUS_SUCCESS, 0);
+}
+
+void
+writeAck (int requestID, int channelID)
+{
+#if DEBUG
+  char *s = getenv (NTXT ("SP_NO_IPC_ACK"));
+#else /* ^DEBUG */
+  char *s = NULL;
+#endif /* ^DEBUG */
+  if (s)
+    {
+      int i = requestID;
+      int j = channelID;
+      ipc_request_trace (TRACE_LVL_4, "ACK skipped: requestID=%d channelID=%d\n", i, j);
+    }
+  else
+    {
+      IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_SMALL);
+      writeResponseWithHeader (requestID, channelID, RESPONSE_TYPE_ACK,
+                              RESPONSE_STATUS_SUCCESS, OUTS);
+    }
+}
+
+void
+writeHandshake (int requestID, int channelID)
+{
+  IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_SMALL);
+  writeResponseWithHeader (requestID, channelID, RESPONSE_TYPE_HANDSHAKE, RESPONSE_STATUS_SUCCESS, OUTS);
+  // writeResponseHeader(requestID, RESPONSE_TYPE_HANDSHAKE, RESPONSE_STATUS_SUCCESS, IPC_VERSION_NUMBER);
+}
+
+void
+writeResponseGeneric (int responseStatus, int requestID, int channelID)
+{
+  IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_SMALL);
+  writeResponseWithHeader (requestID, channelID, RESPONSE_TYPE_COMPLETE, responseStatus, OUTS);
+}
+
+BufferPool::BufferPool ()
+{
+  pthread_mutex_init (&p_mutex, NULL);
+  smallBuf = NULL;
+  largeBuf = NULL;
+}
+
+BufferPool::~BufferPool ()
+{
+  for (IPCresponse *p = smallBuf; p;)
+    {
+      IPCresponse *tmp = p;
+      p = tmp->next;
+      delete tmp;
+    }
+  for (IPCresponse *p = largeBuf; p;)
+    {
+      IPCresponse *tmp = p;
+      p = tmp->next;
+      delete tmp;
+    }
+}
+
+IPCresponse*
+BufferPool::getNewResponse (int size)
+{
+  pthread_mutex_lock (&p_mutex);
+  if (ipc_single_threaded_mode && size < BUFFER_SIZE_LARGE)
+    size = BUFFER_SIZE_LARGE;
+  IPCresponse *newResponse = NULL;
+  if (size >= BUFFER_SIZE_LARGE)
+    {
+      if (largeBuf)
+       {
+         newResponse = largeBuf;
+         largeBuf = largeBuf->next;
+       }
+    }
+  else if (smallBuf)
+    {
+      newResponse = smallBuf;
+      smallBuf = smallBuf->next;
+    }
+  if (newResponse)
+    newResponse->reset ();
+  else
+    {
+      newResponse = new IPCresponse (size);
+      ipc_trace ("GETNEWBUFFER %d\n", size);
+    }
+  pthread_mutex_unlock (&p_mutex);
+  return newResponse;
+}
+
+void
+BufferPool::recycle (IPCresponse *respB)
+{
+  pthread_mutex_lock (&p_mutex);
+  if (respB->getCurBufSize () >= BUFFER_SIZE_LARGE)
+    {
+      respB->next = largeBuf;
+      largeBuf = respB;
+    }
+  else
+    {
+      respB->next = smallBuf;
+      smallBuf = respB;
+    }
+  pthread_mutex_unlock (&p_mutex);
+}
+
+void
+writeArray (void *ptr, IPCrequest* req)
+{
+  if (req->getStatus () == CANCELLED_IMMEDIATE)
+    return;
+  IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_LARGE);
+  OUTS->sendByte (L_ARRAY);
+  OUTS->sendAVal (ptr);
+  writeResponseWithHeader (req->getRequestID (), req->getChannelID (),
+                          RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+void
+writeString (const char *s, IPCrequest* req)
+{
+  if (req->getStatus () == CANCELLED_IMMEDIATE)
+    return;
+  IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_LARGE);
+  OUTS->sendByte (L_STRING);
+  OUTS->sendSVal (s);
+  writeResponseWithHeader (req->getRequestID (), req->getChannelID (),
+                          RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+void
+writeObject (DbeObj obj, IPCrequest* req)
+{
+  writeLong ((long long) obj, req);
+}
+
+void
+writeBoolean (bool b, IPCrequest* req)
+{
+  if (req->getStatus () == CANCELLED_IMMEDIATE)
+    return;
+  IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
+  OUTS->sendByte (L_BOOLEAN);
+  OUTS->sendBVal (b);
+  writeResponseWithHeader (req->getRequestID (), req->getChannelID (),
+                          RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+void
+writeInt (int i, IPCrequest* req)
+{
+  if (req->getStatus () == CANCELLED_IMMEDIATE)
+    return;
+  IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
+  OUTS->sendByte (L_INTEGER);
+  OUTS->sendIVal (i);
+  writeResponseWithHeader (req->getRequestID (), req->getChannelID (), RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+void
+writeChar (char c, IPCrequest* req)
+{
+  if (req->getStatus () == CANCELLED_IMMEDIATE)
+    return;
+  IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
+  OUTS->sendByte (L_CHAR);
+  OUTS->sendCVal (c);
+  writeResponseWithHeader (req->getRequestID (), req->getChannelID (), RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+void
+writeLong (long long l, IPCrequest* req)
+{
+  if (req->getStatus () == CANCELLED_IMMEDIATE)
+    return;
+  IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
+  OUTS->sendByte (L_LONG);
+  OUTS->sendLVal (l);
+  writeResponseWithHeader (req->getRequestID (), req->getChannelID (), RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+void
+writeDouble (double d, IPCrequest* req)
+{
+  if (req->getStatus () == CANCELLED_IMMEDIATE) return;
+  IPCresponse *OUTS = responseBufferPool->getNewResponse (BUFFER_SIZE_MEDIUM);
+  OUTS->sendByte (L_DOUBLE);
+  OUTS->sendDVal (d);
+  writeResponseWithHeader (req->getRequestID (), req->getChannelID (), RESPONSE_TYPE_COMPLETE, RESPONSE_STATUS_SUCCESS, OUTS);
+}
+
+int
+setProgress (int percentage, const char *proc_str)
+{
+  if (cancelNeeded (currentChannelID))
+    {
+      // ExperimentLoadCancelException *e1 = new ExperimentLoadCancelException();
+      // throw (e1);
+      return 1;
+    }
+  if (NULL == proc_str)
+    return 1;
+  int size = strlen (proc_str) + 100; // 100 bytes for additional data
+  int bs = BUFFER_SIZE_MEDIUM;
+  if (size > BUFFER_SIZE_MEDIUM)
+    {
+      if (size > BUFFER_SIZE_LARGE) return 1; // This should never happen
+      bs = BUFFER_SIZE_LARGE;
+    }
+  IPCresponse *OUTS = responseBufferPool->getNewResponse (bs);
+  OUTS->sendByte (L_PROGRESS);
+  OUTS->sendIVal (percentage);
+  OUTS->sendSVal (proc_str);
+  writeResponseWithHeader (currentRequestID, currentChannelID, RESPONSE_TYPE_PROGRESS, RESPONSE_STATUS_SUCCESS, OUTS);
+  return 0;
+}
+
+void
+IPCresponse::print (void)
+{
+  if (ipc_delay_microsec)
+    usleep (ipc_delay_microsec);
+  int stringSize = sb->length ();
+  writeResponseHeader (requestID, responseType, responseStatus, stringSize);
+  if (stringSize > 0)
+    {
+      char *s = sb->toString ();
+      hrtime_t start_time = gethrtime ();
+      int use_write = 1;
+      if (use_write)
+       write (1, s, stringSize); // write(1, sb->toString(), stringSize);
+      else
+       {
+         cout << s;
+         cout.flush ();
+       }
+      hrtime_t end_time = gethrtime ();
+      unsigned long long time_stamp = end_time - start_time;
+      ipc_response_log (TRACE_LVL_3, "ReqID %x flush time %llu  nanosec \n", requestID, time_stamp);
+      free (s);
+    }
+}
+
+void
+setCancelRequestedCh (int chID)
+{
+  cancelRequestedChannelID = chID;
+}
+
+void
+readRequestHeader ()
+{
+  int marker = readByte (NULL);
+  if (marker != HEADER_MARKER)
+    {
+      fprintf (stderr, "Internal error: received request (%d) without header marker\n", marker);
+      error_flag = 1;
+      return;
+    }
+  else
+    ipc_request_trace (TRACE_LVL_1, "RequestHeaderBegin------------------------\n");
+  int requestID = readIVal (NULL);
+  int requestType = readByte (NULL);
+  int channelID = readIVal (NULL);
+  int nBytes = readIVal (NULL);
+  if (requestType == REQUEST_TYPE_HANDSHAKE)
+    {
+      // write the ack directly to the wire, not through the response queue
+      // writeAckFast(requestID);
+      writeAck (requestID, channelID);
+      maxSize = 0;
+      writeHandshake (requestID, channelID);
+      ipc_request_trace (TRACE_LVL_1, "RQ: HANDSHAKE --- %x ----- %x ---- %x --- %x -RequestHeaderEnd\n", requestID, requestType, channelID, nBytes);
+    }
+  else if (requestType == REQUEST_TYPE_CANCEL)
+    {
+      writeAck (requestID, channelID);
+      ipc_request_trace (TRACE_LVL_1, "RQ: CANCEL --- RQ: %x ----- %x --- CH:  %x --- %x -RequestHeaderEnd\n", requestID, requestType, channelID, nBytes);
+      if (channelID == cancellableChannelID)
+       {
+         // we have worked on at least one request belonging to this channel
+         writeResponseGeneric (RESPONSE_STATUS_SUCCESS, requestID, channelID);
+         setCancelRequestedCh (channelID);
+         ipc_trace ("CANCELLABLE %x %x\n", channelID, currentChannelID);
+         if (channelID == currentChannelID)
+           //  request for this channel is currently in progress
+           ipc_request_trace (TRACE_LVL_1, "IN PROGRESS REQUEST NEEDS CANCELLATION");
+           //              ssp_post_cond(waitingToFinish);
+       }
+      else
+       {
+         // FIXME:
+         // it is possible that a request for this channel is on the requestQ
+         // or has been submitted to the work group queue but is waiting for a thread to pick it up
+         writeResponseGeneric (RESPONSE_STATUS_FAILURE, requestID, channelID);
+         setCancelRequestedCh (channelID);
+         ipc_request_trace (TRACE_LVL_1, "RETURNING FAILURE TO CANCEL REQUEST channel %d\n", channelID);
+       }
+    }
+  else
+    {
+      writeAck (requestID, channelID);
+      ipc_request_trace (TRACE_LVL_1, "RQ: --- %x ----- %x ---- %x --- %x -RequestHeaderEnd\n", requestID, requestType, channelID, nBytes);
+      IPCrequest *nreq = new IPCrequest (nBytes, requestID, channelID);
+      nreq->read ();
+      ipc_request_trace (TRACE_LVL_1, "RQ: --- %x Read from stream \n", requestID);
+      if (cancelNeeded (channelID))
+       {
+         ipc_request_trace (TRACE_LVL_1, "CANCELLABLE REQ RECVD %x %x\n", channelID, requestID);
+         writeResponseGeneric (RESPONSE_STATUS_CANCELLED, requestID, channelID);
+         delete nreq;
+         return;
+       }
+      DbeQueue *q = new DbeQueue (ipc_doWork, nreq);
+      ipcThreadPool->put_queue (q);
+    }
+}
diff --git a/gprofng/src/ipcio.h b/gprofng/src/ipcio.h
new file mode 100644 (file)
index 0000000..94a635e
--- /dev/null
@@ -0,0 +1,176 @@
+/* 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.  */
+
+/* Defines the external interface between er_ipc and the routines */
+
+#ifndef _IPCIO_H
+#define _IPCIO_H
+#include <pthread.h>
+#include "gp-defs.h"
+#include "StringBuilder.h"
+
+class DbeThreadPool;
+typedef long long DbeObj;
+typedef void *Object;
+typedef char *String;
+
+#define BUFFER_SIZE_SMALL           512
+#define BUFFER_SIZE_MEDIUM          512
+#define BUFFER_SIZE_LARGE           1024*1024
+
+#define REQUEST_HAS_NO_BODY         0xFFFFFFFF
+#define RESPONSE_STATUS_DEFAULT     0
+#define RESPONSE_STATUS_SUCCESS     1
+#define RESPONSE_STATUS_FAILURE     2
+#define RESPONSE_STATUS_CANCELLED   3
+
+#define RESPONSE_TYPE_ACK           0
+#define RESPONSE_TYPE_PROGRESS      1
+#define RESPONSE_TYPE_COMPLETE      2
+#define RESPONSE_TYPE_HANDSHAKE     3
+#define HEADER_MARKER               0xff
+
+#define REQUEST_TYPE_DEFAULT        0
+#define REQUEST_TYPE_CANCEL         1
+#define REQUEST_TYPE_HANDSHAKE      2
+
+#define IPC_PROTOCOL_STR            "IPC_PROTOCOL_38"
+#define IPC_VERSION_NUMBER          38
+
+enum IPCrequestStatus
+{
+  INITIALIZED = 0,
+  IN_PROGRESS,
+  COMPLETED,
+  CANCELLED_DEFAULT,
+  CANCELLED_IMMEDIATE
+};
+
+enum IPCTraceLevel
+{
+  TRACE_LVL_0 = 0,
+  TRACE_LVL_1,
+  TRACE_LVL_2,
+  TRACE_LVL_3,
+  TRACE_LVL_4
+};
+
+class IPCrequest
+{
+  char *buf;
+  int size;
+  int idx;
+  int requestID;
+  int channelID;
+  IPCrequestStatus status;
+  bool cancelImmediate;
+public:
+  IPCrequest (int, int, int);
+  ~IPCrequest ();
+  IPCrequestStatus getStatus ();
+  void setStatus (IPCrequestStatus);
+  void read ();
+
+  int getRequestID ()               { return requestID; }
+  int getChannelID ()               { return channelID; }
+  bool isCancelImmediate ()         { return cancelImmediate; }
+  void setCancelImmediate ()        { cancelImmediate = true; }
+  char rgetc ()                     { return buf[idx++]; }
+};
+
+class IPCresponse
+{
+public:
+  IPCresponse (int sz);
+  ~IPCresponse ();
+
+  int getRequestID ()               { return requestID; }
+  int getChannelID ()               { return channelID; }
+  void setRequestID (int r)         { requestID = r; }
+  void setChannelID (int c)         { channelID = c; }
+  void setResponseType (int r)      { responseType = r; }
+  void setResponseStatus (int s)    { responseStatus = s; }
+  int getCurBufSize ()              { return sb->capacity (); }
+  void sendByte (int);
+  void sendIVal (int);
+  void sendLVal (long long);
+  void sendDVal (double);
+  void sendSVal (const char *);
+  void sendBVal (bool);
+  void sendCVal (char);
+  void sendAVal (void*);
+  void print (void);
+  void reset ();
+  IPCresponse *next;
+
+private:
+  int requestID;
+  int channelID;
+  int responseType;
+  int responseStatus;
+  StringBuilder *sb;
+};
+
+class BufferPool
+{
+public:
+  BufferPool ();
+  ~BufferPool ();
+  IPCresponse* getNewResponse (int);
+  void recycle (IPCresponse *);
+private:
+  pthread_mutex_t p_mutex;
+  IPCresponse *smallBuf;
+  IPCresponse *largeBuf;
+};
+
+// Read from the wire
+int readInt (IPCrequest*);
+bool readBoolean (IPCrequest*);
+long long readLong (IPCrequest*);
+DbeObj readObject (IPCrequest*);
+Object readArray (IPCrequest*);
+String readString (IPCrequest*);
+void readRequestHeader ();
+
+// write to the wire
+void writeString (const char *, IPCrequest*);
+void writeBoolean (bool, IPCrequest*);
+void writeInt (int, IPCrequest*);
+void writeChar (char, IPCrequest*);
+void writeLong (long long, IPCrequest*);
+void writeDouble (double, IPCrequest*);
+void writeArray (void *, IPCrequest*);
+void writeObject (DbeObj, IPCrequest*);
+void writeResponseGeneric (int, int, int);
+int setProgress (int, const char *);    // Update the progress bar
+int ipc_doWork (void *);                // The argument is an IPCrequest
+
+extern int ipc_flags;
+extern int ipc_single_threaded_mode;
+extern DbeThreadPool *responseThreadPool;
+extern DbeThreadPool *ipcThreadPool;
+extern int cancelRequestedChannelID;
+
+void ipc_default_log (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+void ipc_response_log (IPCTraceLevel, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+void ipc_request_log (IPCTraceLevel, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+#endif
diff --git a/gprofng/src/machinemodels/generic.ermm b/gprofng/src/machinemodels/generic.ermm
new file mode 100644 (file)
index 0000000..19fcc8e
--- /dev/null
@@ -0,0 +1,32 @@
+#  generic machinemodel file
+#
+#   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/>.
+
+mobj_define Memory_page_size       "(EA_PAGESIZE ? EA_PAGESIZE : -1)"
+mobj_define Memory_page            "(((VADDR>255) && EA_PAGESIZE) ? VADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Memory_64B_cacheline   "((VADDR>255)?(VADDR>>6<<6):-1)"
+mobj_define Memory_address         "((VADDR>255)?(VADDR):-1)"
+
+mobj_define Memory_in_home_lgrp    (EA_LGRP==LWP_LGRP_HOME)
+mobj_define Memory_lgrp            (EA_LGRP)
+
+mobj_define Physical_page          "((PADDR && EA_PAGESIZE) ? PADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Physical_64B_cacheline "(PADDR?(PADDR>>6<<6):-1)"
+mobj_define Physical_address       "(PADDR?(PADDR):-1)"
+
+#mobj_define Vpage_4K   "(((ea_pagesize==1<<12 || !ea_pagesize) && VADDR>255)?(VADDR>>12<<12):-1)"
+#mobj_define Ppage_4K   "((ea_pagesize==1<<12 && PADDR)?(PADDR>>12<<12):-1)"
diff --git a/gprofng/src/machinemodels/m5.ermm b/gprofng/src/machinemodels/m5.ermm
new file mode 100644 (file)
index 0000000..83f125d
--- /dev/null
@@ -0,0 +1,65 @@
+# Machinemodel file for M5 systems
+#
+#   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/>.
+
+indxobj_define M5_Chip ((CPUID>>3)/6)
+indxobj_define M5_Core (CPUID>>3)
+
+mobj_define Memory_page_size       "(EA_PAGESIZE ? EA_PAGESIZE : -1)"
+mobj_define Memory_page            "(((VADDR>255) && EA_PAGESIZE) ? VADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Memory_64B_cacheline   "((VADDR>255)?(VADDR>>6<<6):-1)"
+mobj_define Memory_32B_cacheline   "((VADDR>255)?(VADDR>>5<<5):-1)"
+mobj_define Memory_address         "((VADDR>255)?(VADDR):-1)"
+
+mobj_define Memory_in_home_lgrp    (EA_LGRP==LWP_LGRP_HOME)
+mobj_define Memory_lgrp            (EA_LGRP)
+
+mobj_define Physical_page          "((PADDR && EA_PAGESIZE) ? PADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Physical_64B_cacheline "(PADDR?(PADDR>>6<<6):-1)"
+mobj_define Physical_32B_cacheline "(PADDR?(PADDR>>5<<5):-1)"
+mobj_define Physical_address       "(PADDR?(PADDR):-1)"
+
+
+#mobj_define Vpage_8K   "((ea_pagesize==1<<13 && VADDR>255)?(VADDR>>13<<13):-1)"
+#mobj_define Vpage_64K  "((ea_pagesize==1<<16 && VADDR>255)?(VADDR>>16<<16):-1)"
+#mobj_define Vpage_4M   "((ea_pagesize==1<<22 && VADDR>255)?(VADDR>>22<<22):-1)"
+#mobj_define Vpage_256M "((ea_pagesize==1<<28 && VADDR>255)?(VADDR>>28<<28):-1)"
+#mobj_define Vpage_2G   "((ea_pagesize==1<<31 && VADDR>255)?(VADDR>>31<<31):-1)"
+
+#mobj_define Ppage_8K   "((ea_pagesize==1<<13 && PADDR)?(PADDR>>13<<13):-1)"
+#mobj_define Ppage_64K  "((ea_pagesize==1<<16 && PADDR)?(PADDR>>16<<16):-1)"
+#mobj_define Ppage_4M   "((ea_pagesize==1<<22 && PADDR)?(PADDR>>22<<22):-1)"
+#mobj_define Ppage_256M "((ea_pagesize==1<<28 && PADDR)?(PADDR>>28<<28):-1)"
+#mobj_define Ppage_2G   "((ea_pagesize==1<<31 && PADDR)?(PADDR>>31<<31):-1)"
+
+# comment out *CacheTag definitions since we don't have use cases to justify their complexity
+# comment out other *Cache* definitions since we don't have use cases to justify their complexity
+#       further, meminfo() tends not to give us physical addresses
+
+#mobj_define M5_L1ICacheSet "((PHYSPC>>5)&0x7F)"
+#mobj_define M5_L1ICacheTag "((PHYSPC>>12)&0x7FFFFFFFF)"
+#mobj_define M5_L1DCacheSet "(PADDR?((PADDR>>5)&0x7F):-1)"
+#mobj_define M5_L1DCacheTag "(PADDR?((PADDR>>12)&0x7FFFFFFFF):-1)"
+
+#mobj_define M5_L2ICacheSet "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>5)&0x1FF)"
+#mobj_define M5_L2ICacheTag "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>14)&0x1FFFFFFFF)"
+#mobj_define M5_L2DCacheSet "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>5)&0x1FF):-1)"
+#mobj_define M5_L2DCacheTag "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>14)&0x1FFFFFFFF):-1)"
+
+#mobj_define M5_L3DCacheSet "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0xFFFF):-1)"
+#mobj_define M5_L3DCacheTag "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>22)&0x3FFFFFF):-1)"
+#mobj_define M5_L3DBank "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0x3):-1)"
diff --git a/gprofng/src/machinemodels/m6.ermm b/gprofng/src/machinemodels/m6.ermm
new file mode 100644 (file)
index 0000000..1071e9e
--- /dev/null
@@ -0,0 +1,65 @@
+# Machinemodel file for M6 systems
+#
+#   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/>.
+
+indxobj_define M6_Chip ((CPUID>>3)/12)
+indxobj_define M6_Core (CPUID>>3)
+
+mobj_define Memory_page_size       "(EA_PAGESIZE ? EA_PAGESIZE : -1)"
+mobj_define Memory_page            "(((VADDR>255) && EA_PAGESIZE) ? VADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Memory_64B_cacheline   "((VADDR>255)?(VADDR>>6<<6):-1)"
+mobj_define Memory_32B_cacheline   "((VADDR>255)?(VADDR>>5<<5):-1)"
+mobj_define Memory_address         "((VADDR>255)?(VADDR):-1)"
+
+mobj_define Memory_in_home_lgrp    (EA_LGRP==LWP_LGRP_HOME)
+mobj_define Memory_lgrp            (EA_LGRP)
+
+mobj_define Physical_page          "((PADDR && EA_PAGESIZE) ? PADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Physical_64B_cacheline "(PADDR?(PADDR>>6<<6):-1)"
+mobj_define Physical_32B_cacheline "(PADDR?(PADDR>>5<<5):-1)"
+mobj_define Physical_address       "(PADDR?(PADDR):-1)"
+
+
+#mobj_define Vpage_8K   "((ea_pagesize==1<<13 && VADDR>255)?(VADDR>>13<<13):-1)"
+#mobj_define Vpage_64K  "((ea_pagesize==1<<16 && VADDR>255)?(VADDR>>16<<16):-1)"
+#mobj_define Vpage_4M   "((ea_pagesize==1<<22 && VADDR>255)?(VADDR>>22<<22):-1)"
+#mobj_define Vpage_256M "((ea_pagesize==1<<28 && VADDR>255)?(VADDR>>28<<28):-1)"
+#mobj_define Vpage_2G   "((ea_pagesize==1<<31 && VADDR>255)?(VADDR>>31<<31):-1)"
+
+#mobj_define Ppage_8K   "((ea_pagesize==1<<13 && PADDR)?(PADDR>>13<<13):-1)"
+#mobj_define Ppage_64K  "((ea_pagesize==1<<16 && PADDR)?(PADDR>>16<<16):-1)"
+#mobj_define Ppage_4M   "((ea_pagesize==1<<22 && PADDR)?(PADDR>>22<<22):-1)"
+#mobj_define Ppage_256M "((ea_pagesize==1<<28 && PADDR)?(PADDR>>28<<28):-1)"
+#mobj_define Ppage_2G   "((ea_pagesize==1<<31 && PADDR)?(PADDR>>31<<31):-1)"
+
+# comment out *CacheTag definitions since we don't have use cases to justify their complexity
+# comment out other *Cache* definitions since we don't have use cases to justify their complexity
+#       further, meminfo() tends not to give us physical addresses
+
+#mobj_define M6_L1ICacheSet "((PHYSPC>>5)&0x7F)"
+#mobj_define M6_L1ICacheTag "((PHYSPC>>12)&0x7FFFFFFFF)"
+#mobj_define M6_L1DCacheSet "(PADDR?((PADDR>>5)&0x7F):-1)"
+#mobj_define M6_L1DCacheTag "(PADDR?((PADDR>>12)&0x7FFFFFFFF):-1)"
+
+#mobj_define M6_L2ICacheSet "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>5)&0x1FF)"
+#mobj_define M6_L2ICacheTag "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>14)&0x1FFFFFFFF)"
+#mobj_define M6_L2DCacheSet "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>5)&0x1FF):-1)"
+#mobj_define M6_L2DCacheTag "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>14)&0x1FFFFFFFF):-1)"
+
+#mobj_define M6_L3DCacheSet "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0xFFFF):-1)"
+#mobj_define M6_L3DCacheTag "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>22)&0x3FFFFFF):-1)"
+#mobj_define M6_L3DBank "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0x3):-1)"
diff --git a/gprofng/src/machinemodels/m7.ermm b/gprofng/src/machinemodels/m7.ermm
new file mode 100644 (file)
index 0000000..29e3bef
--- /dev/null
@@ -0,0 +1,64 @@
+# Machinemodel file for M7/T7 systems
+#
+#   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/>.
+
+indxobj_define M7_Chip (CPUID>>8)
+indxobj_define M7_Core (CPUID>>3)
+
+mobj_define Memory_page_size       "(EA_PAGESIZE ? EA_PAGESIZE : -1)"
+mobj_define Memory_page            "(((VADDR>255) && EA_PAGESIZE) ? VADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Memory_64B_cacheline   "((VADDR>255)?(VADDR>>6<<6):-1)"
+mobj_define Memory_32B_cacheline   "((VADDR>255)?(VADDR>>5<<5):-1)"
+mobj_define Memory_address         "((VADDR>255)?(VADDR):-1)"
+
+mobj_define Memory_in_home_lgrp    (EA_LGRP==LWP_LGRP_HOME)
+mobj_define Memory_lgrp            (EA_LGRP)
+
+mobj_define Physical_page          "((PADDR && EA_PAGESIZE) ? PADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Physical_64B_cacheline "(PADDR?(PADDR>>6<<6):-1)"
+mobj_define Physical_32B_cacheline "(PADDR?(PADDR>>5<<5):-1)"
+mobj_define Physical_address       "(PADDR?(PADDR):-1)"
+
+
+#mobj_define Vpage_8K   "((ea_pagesize==1<<13 && VADDR>255)?(VADDR>>13<<13):-1)"
+#mobj_define Vpage_64K  "((ea_pagesize==1<<16 && VADDR>255)?(VADDR>>16<<16):-1)"
+#mobj_define Vpage_4M   "((ea_pagesize==1<<22 && VADDR>255)?(VADDR>>22<<22):-1)"
+#mobj_define Vpage_256M "((ea_pagesize==1<<28 && VADDR>255)?(VADDR>>28<<28):-1)"
+#mobj_define Vpage_2G   "((ea_pagesize==1<<31 && VADDR>255)?(VADDR>>31<<31):-1)"
+#mobj_define Vpage_16G  "((ea_pagesize==1<<34 && VADDR>255)?(VADDR>>34<<34):-1)"
+
+#mobj_define Ppage_8K   "((ea_pagesize==1<<13 && PADDR)?(PADDR>>13<<13):-1)"
+#mobj_define Ppage_64K  "((ea_pagesize==1<<16 && PADDR)?(PADDR>>16<<16):-1)"
+#mobj_define Ppage_4M   "((ea_pagesize==1<<22 && PADDR)?(PADDR>>22<<22):-1)"
+#mobj_define Ppage_256M "((ea_pagesize==1<<28 && PADDR)?(PADDR>>28<<28):-1)"
+#mobj_define Ppage_2G   "((ea_pagesize==1<<31 && PADDR)?(PADDR>>31<<31):-1)"
+#mobj_define Ppage_16G  "((ea_pagesize==1<<34 && PADDR)?(PADDR>>34<<34):-1)"
+
+# we dropped the *CacheTag definitions since:
+# - they're rarely used
+# - it's unclear if they are correct for S4
+# comment out other *Cache* definitions since we don't have use cases to justify their complexity
+#       further, meminfo() tends not to give us physical addresses
+
+#mobj_define M7_L1ICacheSet "((PHYSPC>>6)&0x3F)"
+#mobj_define M7_L1DCacheSet "(PADDR?((PADDR>>5)&0x7F):-1)"
+
+#mobj_define M7_L2ICacheSet "((((PHYSPC&0xFFFFFFFFFFF00FFF)|(((PHYSPC>>24)^(PHYSPC>>16)^(PHYSPC>>8)^PHYSPC)&0xFF000))>>6)&0x1FF)"
+#mobj_define M7_L2DCacheSet "(PADDR?((((PADDR&0x2000000000000)?PADDR:((PADDR&0xFFFFFFFFFFF00FFF)|(((PADDR>>24)^(PADDR>>16)^(PADDR>>8)^PADDR)&0xFF000)))>>6)&0x01FF):-1)"
+
+#mobj_define M7_L3DCacheSet "(PADDR?((((PADDR&0x2000000000000)?PADDR:((PADDR&0xFFFFFFFFFFF00FFF)|(((PADDR>>24)^(PADDR>>16)^(PADDR>>8)^PADDR)&0xFF000)))>>6)&0x3FFF):-1)"
+#mobj_define M7_L3DBank     "(PADDR?((((PADDR&0x2000000000000)?PADDR:((PADDR&0xFFFFFFFFFFF00FFF)|(((PADDR>>24)^(PADDR>>16)^(PADDR>>8)^PADDR)&0xFF000)))>>6)&0x0001):-1)"
diff --git a/gprofng/src/machinemodels/t4.ermm b/gprofng/src/machinemodels/t4.ermm
new file mode 100644 (file)
index 0000000..e27f3a4
--- /dev/null
@@ -0,0 +1,67 @@
+# Machinemodel file for T4 systems
+#
+#   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/>.
+
+indxobj_define T4_Chip (CPUID>>6)
+indxobj_define T4_Core (CPUID>>3)
+
+mobj_define Memory_page_size       "(EA_PAGESIZE ? EA_PAGESIZE : -1)"
+mobj_define Memory_page            "(((VADDR>255) && EA_PAGESIZE) ? VADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Memory_64B_cacheline   "((VADDR>255)?(VADDR>>6<<6):-1)"
+mobj_define Memory_32B_cacheline   "((VADDR>255)?(VADDR>>5<<5):-1)"
+mobj_define Memory_address         "((VADDR>255)?(VADDR):-1)"
+
+mobj_define Memory_in_home_lgrp    (EA_LGRP==LWP_LGRP_HOME)
+mobj_define Memory_lgrp            (EA_LGRP)
+
+mobj_define Physical_page          "((PADDR && EA_PAGESIZE) ? PADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Physical_64B_cacheline "(PADDR?(PADDR>>6<<6):-1)"
+mobj_define Physical_32B_cacheline "(PADDR?(PADDR>>5<<5):-1)"
+mobj_define Physical_address       "(PADDR?(PADDR):-1)"
+
+
+#mobj_define Vpage_8K   "((ea_pagesize==1<<13 && VADDR>255)?(VADDR>>13<<13):-1)"
+#mobj_define Vpage_64K  "((ea_pagesize==1<<16 && VADDR>255)?(VADDR>>16<<16):-1)"
+#mobj_define Vpage_512K "((ea_pagesize==1<<19 && VADDR>255)?(VADDR>>19<<19):-1)"
+#mobj_define Vpage_4M   "((ea_pagesize==1<<22 && VADDR>255)?(VADDR>>22<<22):-1)"
+#mobj_define Vpage_256M "((ea_pagesize==1<<28 && VADDR>255)?(VADDR>>28<<28):-1)"
+#mobj_define Vpage_2G   "((ea_pagesize==1<<31 && VADDR>255)?(VADDR>>31<<31):-1)"
+
+#mobj_define Ppage_8K   "((ea_pagesize==1<<13 && PADDR)?(PADDR>>13<<13):-1)"
+#mobj_define Ppage_64K  "((ea_pagesize==1<<16 && PADDR)?(PADDR>>16<<16):-1)"
+#mobj_define Ppage_512K "((ea_pagesize==1<<19 && PADDR)?(PADDR>>19<<19):-1)"
+#mobj_define Ppage_4M   "((ea_pagesize==1<<22 && PADDR)?(PADDR>>22<<22):-1)"
+#mobj_define Ppage_256M "((ea_pagesize==1<<28 && PADDR)?(PADDR>>28<<28):-1)"
+#mobj_define Ppage_2G   "((ea_pagesize==1<<31 && PADDR)?(PADDR>>31<<31):-1)"
+
+# comment out *CacheTag definitions since we don't have use cases to justify their complexity
+# comment out other *Cache* definitions since we don't have use cases to justify their complexity
+#       further, meminfo() tends not to give us physical addresses
+
+#mobj_define T4_L1ICacheSet "((PHYSPC>>5)&0x7F)"
+#mobj_define T4_L1ICacheTag "((PHYSPC>>12)&0x7FFFFFFFF)"
+#mobj_define T4_L1DCacheSet "(PADDR?((PADDR>>5)&0x7F):-1)"
+#mobj_define T4_L1DCacheTag "(PADDR?((PADDR>>12)&0x7FFFFFFFF):-1)"
+#mobj_define T4_L2ICacheSet "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>5)&0x1FF)"
+#mobj_define T4_L2ICacheTag "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>14)&0x1FFFFFFFF)"
+#mobj_define T4_L2DCacheSet "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>5)&0x1FF):-1)"
+#mobj_define T4_L2DCacheTag "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>14)&0x1FFFFFFFF):-1)"
+#mobj_define T4_L3DCacheSet "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0xFFF):-1)"
+#mobj_define T4_L3DCacheTag "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>18)&0x1FFFFFFF):-1)"
+#mobj_define T4_L3DBank "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0x7):-1)"
+#mobj_define T4_2_Socket "(PADDR?((PADDR>>33)&0x1):-1)"
+#mobj_define T4_4_Socket "(PADDR?((PADDR>>33)&0x3):-1)"
diff --git a/gprofng/src/machinemodels/t5.ermm b/gprofng/src/machinemodels/t5.ermm
new file mode 100644 (file)
index 0000000..6d666a9
--- /dev/null
@@ -0,0 +1,65 @@
+# Machinemodel file for T5 systems
+#
+#   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/>.
+
+indxobj_define T5_Chip (CPUID>>7)
+indxobj_define T5_Core (CPUID>>3)
+
+mobj_define Memory_page_size       "(EA_PAGESIZE ? EA_PAGESIZE : -1)"
+mobj_define Memory_page            "(((VADDR>255) && EA_PAGESIZE) ? VADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Memory_64B_cacheline   "((VADDR>255)?(VADDR>>6<<6):-1)"
+mobj_define Memory_32B_cacheline   "((VADDR>255)?(VADDR>>5<<5):-1)"
+mobj_define Memory_address         "((VADDR>255)?(VADDR):-1)"
+
+mobj_define Memory_in_home_lgrp    (EA_LGRP==LWP_LGRP_HOME)
+mobj_define Memory_lgrp            (EA_LGRP)
+
+mobj_define Physical_page          "((PADDR && EA_PAGESIZE) ? PADDR & (~(EA_PAGESIZE-1)) : -1)"
+mobj_define Physical_64B_cacheline "(PADDR?(PADDR>>6<<6):-1)"
+mobj_define Physical_32B_cacheline "(PADDR?(PADDR>>5<<5):-1)"
+mobj_define Physical_address       "(PADDR?(PADDR):-1)"
+
+
+#mobj_define Vpage_8K   "((ea_pagesize==1<<13 && VADDR>255)?(VADDR>>13<<13):-1)"
+#mobj_define Vpage_64K  "((ea_pagesize==1<<16 && VADDR>255)?(VADDR>>16<<16):-1)"
+#mobj_define Vpage_4M   "((ea_pagesize==1<<22 && VADDR>255)?(VADDR>>22<<22):-1)"
+#mobj_define Vpage_256M "((ea_pagesize==1<<28 && VADDR>255)?(VADDR>>28<<28):-1)"
+#mobj_define Vpage_2G   "((ea_pagesize==1<<31 && VADDR>255)?(VADDR>>31<<31):-1)"
+
+#mobj_define Ppage_8K   "((ea_pagesize==1<<13 && PADDR)?(PADDR>>13<<13):-1)"
+#mobj_define Ppage_64K  "((ea_pagesize==1<<16 && PADDR)?(PADDR>>16<<16):-1)"
+#mobj_define Ppage_4M   "((ea_pagesize==1<<22 && PADDR)?(PADDR>>22<<22):-1)"
+#mobj_define Ppage_256M "((ea_pagesize==1<<28 && PADDR)?(PADDR>>28<<28):-1)"
+#mobj_define Ppage_2G   "((ea_pagesize==1<<31 && PADDR)?(PADDR>>31<<31):-1)"
+
+# comment out *CacheTag definitions since we don't have use cases to justify their complexity
+# comment out other *Cache* definitions since we don't have use cases to justify their complexity
+#       further, meminfo() tends not to give us physical addresses
+
+#mobj_define T5_L1ICacheSet "((PHYSPC>>5)&0x7F)"
+#mobj_define T5_L1ICacheTag "((PHYSPC>>12)&0x7FFFFFFFF)"
+#mobj_define T5_L1DCacheSet "(PADDR?((PADDR>>5)&0x7F):-1)"
+#mobj_define T5_L1DCacheTag "(PADDR?((PADDR>>12)&0x7FFFFFFFF):-1)"
+
+#mobj_define T5_L2ICacheSet "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>5)&0x1FF)"
+#mobj_define T5_L2ICacheTag "((((PHYSPC&0xFFFFFFF80FFF)|(((PHYSPC>>19)^(PHYSPC>>16)^(PHYSPC>>10)^(PHYSPC>>4)^(PHYSPC>>1)^PHYSPC)&0x7F000))>>14)&0x1FFFFFFFF)"
+#mobj_define T5_L2DCacheSet "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>5)&0x1FF):-1)"
+#mobj_define T5_L2DCacheTag "(PADDR?((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>14)&0x1FFFFFFFF):-1)"
+
+#mobj_define T5_L3DCacheSet "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0x1FFF):-1)"
+#mobj_define T5_L3DCacheTag "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>19)&0x1FFFFFFF):-1)"
+#mobj_define T5_L3DBank "(PADDR?((((PADDR&0x800000000000)?((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))):((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))&0x7FFFFFFFFF3F)|(((((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000)))>>6)^((PADDR&0x800000000000)?PADDR:((PADDR&0xFFFFFFF80FFF)|(((PADDR>>19)^(PADDR>>16)^(PADDR>>10)^(PADDR>>4)^(PADDR>>1)^PADDR)&0x7F000))))&0xC0)))>>6)&0x7):-1)"
diff --git a/gprofng/src/parse.cc b/gprofng/src/parse.cc
new file mode 100644 (file)
index 0000000..ab22270
--- /dev/null
@@ -0,0 +1,927 @@
+/* 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/param.h>
+#include <sys/mman.h>
+
+#include "util.h"
+#include "DbeFile.h"
+#include "DbeSession.h"
+#include "Experiment.h"
+#include "Emsg.h"
+#include "Function.h"
+#include "LoadObject.h"
+#include "Module.h"
+#include "PRBTree.h"
+#include "Sample.h"
+#include "Elf.h"
+
+void
+Experiment::mrec_insert (MapRecord *mrec)
+{
+  int sz = mrecs->size ();
+  MapRecord *tmp = sz > 0 ? mrecs->fetch (sz - 1) : NULL;
+
+  // The following should work in most cases
+  if (tmp == NULL || tmp->ts <= mrec->ts)
+    {
+      mrecs->append (mrec);
+      return;
+    }
+
+  // If it didn't...
+  int lo = 0;
+  int hi = sz - 1;
+  while (lo <= hi)
+    {
+      int md = (lo + hi) / 2;
+      tmp = mrecs->fetch (md);
+      if (tmp->ts < mrec->ts)
+       lo = md + 1;
+      else
+       hi = md - 1;
+    }
+  mrecs->insert (lo, mrec);
+}
+
+int
+Experiment::process_arglist_cmd (char *, char *arglist)
+{
+  uarglist = arglist;
+
+  // find argv[0], and extract its basename
+  if (strcmp (uarglist, NTXT ("(fork)")) == 0)
+    return 0; // leaving target name NULL
+  char *p = uarglist;
+  char *pp = uarglist;
+  char *pl;
+  for (;;)
+    {
+      if (*p == '/')
+       pp = p + 1;
+      if (*p == ' ' || *p == 0)
+       {
+         pl = p;
+         break;
+       }
+      p++;
+    }
+  size_t len = pl - pp;
+  if (len > 0)
+    utargname = dbe_sprintf (NTXT ("%.*s"), (int) len, pp);
+  return 0;
+}
+
+int
+Experiment::process_desc_start_cmd (char *, hrtime_t ts, char *flavor,
+                                   char *nexp, int follow, char *txt)
+{
+  char *str;
+  Emsg *m;
+
+  if (follow == 1)
+    str = dbe_sprintf (GTXT ("Starting %s %ld.%09ld, exp %s.er, \"%s\""),
+                      flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC),
+                      nexp, txt);
+  else
+    str = dbe_sprintf (GTXT ("Starting %s %ld.%09ld, no experiment, \"%s\""),
+                      flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC),
+                      txt);
+  m = new Emsg (CMSG_COMMENT, str);
+  free (str);
+  runlogq->append (m);
+
+  free (flavor);
+  free (nexp);
+  free (txt);
+  return 0;
+}
+
+int
+Experiment::process_desc_started_cmd (char *, hrtime_t ts, char *flavor,
+                                     char *nexp, int follow, char *txt)
+{
+  char *str;
+  Emsg *m;
+
+  if (follow == 1)
+    str = dbe_sprintf (GTXT ("Started  %s %ld.%09ld, exp %s.er, \"%s\""),
+                      flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC),
+                      nexp, txt);
+  else
+    str = dbe_sprintf (GTXT ("Started  %s %ld.%09ld, no experiment, \"%s\""),
+                      flavor, (long) (ts / NANOSEC), (long) (ts % NANOSEC),
+                      txt);
+  m = new Emsg (CMSG_COMMENT, str);
+  free (str);
+  runlogq->append (m);
+  free (flavor);
+  free (nexp);
+  free (txt);
+  return 0;
+}
+
+LoadObject *
+Experiment::get_dynfunc_lo (const char *loName)
+{
+  LoadObject *lo = loadObjMap->get (loName);
+  if (lo == NULL)
+    {
+      lo = createLoadObject (loName, expIdx);// DYNFUNC_SEGMENT is always unique
+      lo->dbeFile->filetype |= DbeFile::F_FICTION;
+      lo->flags |= SEG_FLAG_DYNAMIC;
+      lo->type = LoadObject::SEG_TEXT;
+      lo->set_platform (platform, wsize);
+      append (lo);
+    }
+  return lo;
+}
+
+Function *
+Experiment::create_dynfunc (Module *mod, char *fname, int64_t vaddr,
+                           int64_t fsize)
+{
+  Function *f = dbeSession->createFunction ();
+  f->set_name (fname);
+  f->flags |= FUNC_FLAG_DYNAMIC;
+  f->size = fsize;
+  f->img_offset = vaddr;
+  f->module = mod;
+  mod->functions->append (f);
+  mod->loadobject->functions->append (f);
+  return f;
+}
+
+static int
+func_cmp (const void *a, const void *b)
+{
+  Function *fp1 = *((Function **) a);
+  Function *fp2 = *((Function **) b);
+  uint64_t i1 = fp1->img_offset;
+  uint64_t i2 = fp2->img_offset;
+  return i1 < i2 ? -1 : i1 == i2 ? 0 : 1;
+}
+
+int
+Experiment::process_fn_load_cmd (Module *mod, char *fname, Vaddr vaddr,
+                                int fsize, hrtime_t ts)
+{
+  Dprintf (DEBUG_MAPS,
+          "process_fn_load_cmd:%s (%s) vaddr=0x%llx msize=%lld ts=%lld\n",
+          STR (mod ? mod->get_name () : NULL), STR (fname),
+          (unsigned long long) vaddr, (long long) fsize, (long long) ts);
+  if (mod != NULL)
+    {
+      mod->functions->sort (func_cmp);
+      uint64_t lastVaddr = vaddr;
+      for (int i = 0, sz = mod->functions->size (); i < sz; i++)
+       {
+         Function *f = mod->functions->fetch (i);
+         if (lastVaddr < f->img_offset)
+           {
+             char *fnm = dbe_sprintf (GTXT ("<static>@0x%llx (%s)"),
+                                      (unsigned long long) lastVaddr, fname);
+             create_dynfunc (mod, fnm, lastVaddr, f->img_offset - lastVaddr);
+             free (fnm);
+           }
+         lastVaddr = f->img_offset + f->size;
+       }
+      if (lastVaddr < vaddr + fsize)
+       {
+         char *fnm = dbe_sprintf (GTXT ("<static>@0x%llx (%s)"),
+                                  (unsigned long long) lastVaddr, fname);
+         create_dynfunc (mod, fnm, lastVaddr, vaddr + fsize - lastVaddr);
+         free (fnm);
+       }
+      mod->functions->sort (func_cmp);
+      for (int i = 0, sz = mod->functions->size (); i < sz; i++)
+       {
+         Function *f = mod->functions->fetch (i);
+         MapRecord *mrec = new MapRecord;
+         mrec->kind = MapRecord::LOAD;
+         mrec->obj = f;
+         mrec->base = f->img_offset;
+         mrec->size = f->size;
+         mrec->ts = ts;
+         mrec->foff = 0;
+         mrec_insert (mrec);
+       }
+      return 0;
+    }
+
+  LoadObject *ds = get_dynfunc_lo (DYNFUNC_SEGMENT);
+  Function *dfunc = create_dynfunc (ds->noname, fname, vaddr, fsize);
+
+  // check for special functions, USER, IDLE, TRUNC to disable offsets in disassembly
+  // XXX -- check based on name now
+  // Optimization: use pre-initialized localized strings
+  static const char * localized_USER_MODE = NULL;
+  static const char * localized_IDLE = NULL;
+  static const char * localized_TRUNCATED_STACK = NULL;
+  if (localized_USER_MODE == NULL)
+    {
+      localized_USER_MODE = GTXT ("<USER_MODE>");
+      localized_IDLE = GTXT ("<IDLE>");
+      localized_TRUNCATED_STACK = GTXT ("<TRUNCATED_STACK>");
+    }
+  if (strcmp (fname, localized_USER_MODE) == 0
+      || strcmp (fname, localized_IDLE) == 0
+      || strcmp (fname, localized_TRUNCATED_STACK) == 0)
+    dfunc->flags |= FUNC_FLAG_NO_OFFSET;
+
+  MapRecord *mrec = new MapRecord;
+  mrec->kind = MapRecord::LOAD;
+  mrec->obj = dfunc;
+  mrec->base = vaddr;
+  mrec->size = fsize;
+  mrec->ts = ts;
+  mrec->foff = 0;
+  mrec_insert (mrec);
+  return 0;
+}
+
+int
+Experiment::process_fn_unload_cmd (char *, Vaddr vaddr, hrtime_t ts)
+{
+  MapRecord *mrec = new MapRecord;
+  mrec->kind = MapRecord::UNLOAD;
+  mrec->base = vaddr;
+  mrec->ts = ts;
+  mrec_insert (mrec);
+  return 0;
+}
+
+void
+Experiment::register_metric (Metric::Type type)
+{
+  BaseMetric *mtr = dbeSession->register_metric (type);
+  metrics->append (mtr);
+}
+
+void
+Experiment::register_metric (Hwcentry *ctr, const char* aux, const char* uname)
+{
+  BaseMetric *mtr = dbeSession->register_metric (ctr, aux, uname);
+  metrics->append (mtr);
+  if (mtr->get_dependent_bm ())
+    metrics->append (mtr->get_dependent_bm ());
+}
+
+int
+Experiment::process_hwcounter_cmd (char *, int cpuver, char *counter,
+                                  char * int_name, int interval, int tag,
+                                  int i_tpc, char *modstr)
+{
+  char *str;
+  Emsg *m;
+  Hwcentry *ctr;
+  ABST_type tpc = (ABST_type) i_tpc;
+
+  // Use previously ignored tag to associate counter packets.
+  if (tag < 0 || tag >= MAX_HWCOUNT)
+    {
+      // invalid tag specified, warn user
+      str = dbe_sprintf (GTXT ("*** Error: HW counter tag %d out of range [%d - %d]; ignored"),
+                        tag, 0, MAX_HWCOUNT - 1);
+      m = new Emsg (CMSG_ERROR, str);
+      free (str);
+      errorq->append (m);
+      free (counter);
+      return 0;
+    }
+  if (coll_params.hw_aux_name[tag])
+    {
+      // duplicate tag used, warn user
+      str = dbe_sprintf (GTXT ("*** Error: Duplicate HW counter tag %d specified; ignored"),
+                        tag);
+      m = new Emsg (CMSG_ERROR, str);
+      free (str);
+      errorq->append (m);
+      free (counter);
+      return 0;
+    }
+  hw_cpuver = cpuver;
+
+  // map it to a machinemodel string
+  if (hw_cpuver != CPUVER_UNDEFINED)
+    {
+      free (machinemodel);
+      if (hw_cpuver == 1104)
+       machinemodel = dbe_strdup (NTXT ("t4"));
+      else if (hw_cpuver == 1110)
+       machinemodel = dbe_strdup (NTXT ("t5"));
+      else if (hw_cpuver == 1204)
+       machinemodel = dbe_strdup (NTXT ("m4"));
+      else if (hw_cpuver == 1210)
+       machinemodel = dbe_strdup (NTXT ("m5"));
+      else if (hw_cpuver == 1220)
+       machinemodel = dbe_strdup (NTXT ("m6"));
+      else if (hw_cpuver == 1230)
+       machinemodel = dbe_strdup (NTXT ("m7"));
+      else
+       machinemodel = dbe_strdup (NTXT ("generic"));
+    }
+
+  // Find the entry in the machine table, and dup it
+  ctr = new Hwcentry;
+  dbeSession->append (ctr);
+  hwc_post_lookup (ctr, counter, int_name, cpuver);
+  ctr->sort_order = tag;
+  ctr->memop = tpc;
+
+  // Check if HWC name is to be modified
+  if (modstr != NULL)
+    {
+      char *s = ctr->name;
+      ctr->name = dbe_sprintf (NTXT ("%s%s"), modstr, s);
+      s = ctr->int_name;
+      ctr->int_name = dbe_sprintf (NTXT ("%s%s"), modstr, s);
+      s = ctr->metric;
+      if (s)
+       ctr->metric = dbe_sprintf (NTXT ("%s%s"), modstr, s);
+    }
+
+  char * cname = dbe_strdup (ctr->name);
+  char * uname = dbe_strdup (hwc_i18n_metric (ctr));
+  coll_params.hw_aux_name[tag] = cname;
+  coll_params.hw_username[tag] = uname;
+  coll_params.hw_interval[tag] = interval;
+  coll_params.hw_tpc[tag] = tpc;
+  coll_params.hw_cpu_ver[tag] = cpuver;
+
+  // set hw_mode and xhw_mode?
+  coll_params.hw_mode = 1;
+  if (ABST_MEMSPACE_ENABLED (tpc))
+    {
+      // yes, dataspace data available
+      coll_params.xhw_mode = 1;
+
+      // set dataspace available
+      dataspaceavail = true;
+    }
+  register_metric (ctr, cname, uname);
+  free (counter);
+  return 0;
+}
+
+// TBR:?
+
+int
+Experiment::process_hwsimctr_cmd (char *, int cpuver, char *nm, char *int_name,
+                                 char *metric, int reg,
+                                 int interval, int timecvt, int i_tpc, int tag)
+{
+  char *str;
+  Emsg *m;
+  Hwcentry *ctr;
+  ABST_type tpc = (ABST_type) i_tpc;
+
+  // Use previously ignored tag to associate counter packets.
+  if (tag < 0 || tag >= MAX_HWCOUNT)
+    {
+      // invalid tag specified, warn user
+      str = dbe_sprintf (GTXT ("*** Error: HW counter tag %d out of range [%d - %d]; ignored"),
+                        tag, 0, MAX_HWCOUNT - 1);
+      m = new Emsg (CMSG_ERROR, str);
+      free (str);
+      errorq->append (m);
+
+      free (nm);
+      free (int_name);
+      free (metric);
+      return 0;
+    }
+  if (coll_params.hw_aux_name[tag])
+    {
+      // duplicate tag used, warn user
+      str = dbe_sprintf (GTXT ("*** Error: Duplicate HW counter tag %d specified; ignored"),
+                        tag);
+      m = new Emsg (CMSG_ERROR, str);
+      free (str);
+      errorq->append (m);
+      free (nm);
+      free (int_name);
+      free (metric);
+      return 0;
+    }
+  hw_cpuver = cpuver;
+  ctr = new Hwcentry;
+  {
+    static Hwcentry empty;
+    *ctr = empty;
+  }
+  ctr->name = nm;
+  ctr->int_name = int_name;
+  ctr->metric = metric;
+  ctr->reg_num = reg;
+  ctr->val = interval;
+  ctr->timecvt = timecvt;
+  ctr->memop = tpc;
+  ctr->sort_order = tag;
+
+  char *cname = dbe_strdup (ctr->name);
+  char *uname = dbe_strdup (hwc_i18n_metric (ctr));
+
+  coll_params.hw_aux_name[tag] = cname;
+  coll_params.hw_username[tag] = uname;
+  coll_params.hw_interval[tag] = interval;
+  coll_params.hw_tpc[tag] = tpc;
+  coll_params.hw_cpu_ver[tag] = cpuver;
+
+  // set hw_mode and xhw_mode?
+  coll_params.hw_mode = 1;
+  if (ABST_MEMSPACE_ENABLED (tpc))
+    {
+      coll_params.xhw_mode = 1;
+      // set dataspace available
+      if (getenv ("ANALYZER_DATASPACE_COUNT") != 0)
+       dataspaceavail = true;
+    }
+
+  register_metric (ctr, cname, uname);
+  return 0;
+}
+
+int
+Experiment::process_jcm_load_cmd (char *, Vaddr mid, Vaddr vaddr,
+                                 int msize, hrtime_t ts)
+{
+  if (jmaps == NULL)
+    return 1;
+
+  JMethod *jfunc = (JMethod*) jmaps->locate_exact_match (mid, ts);
+  if (jfunc == NULL || jfunc->get_type () != Histable::FUNCTION)
+    return 1;
+
+  LoadObject *ds = get_dynfunc_lo (JAVA_COMPILED_METHODS);
+  Module *jmodule = jfunc->module;
+  Module *dmodule = ds->noname;
+  if (jmodule)
+    {
+      dmodule = dbeSession->createModule (ds, jmodule->get_name ());
+      dmodule->lang_code = Sp_lang_java;
+      dmodule->set_file_name (dbe_strdup (jmodule->file_name));
+    }
+
+  JMethod *dfunc = dbeSession->createJMethod ();
+  dfunc->flags |= FUNC_FLAG_DYNAMIC;
+  dfunc->size = msize;
+  dfunc->module = dmodule;
+  dfunc->usrfunc = jfunc;
+  dfunc->set_addr (vaddr);
+  dfunc->set_mid (mid);
+  dfunc->set_signature (jfunc->get_signature ());
+  dfunc->set_name (jfunc->get_mangled_name ());
+  ds->functions->append (dfunc);
+  dmodule->functions->append (dfunc);
+  MapRecord *mrec = new MapRecord;
+  mrec->kind = MapRecord::LOAD;
+  mrec->obj = dfunc;
+  mrec->base = vaddr;
+  mrec->size = msize;
+  mrec->ts = ts;
+  mrec->foff = 0;
+  mrec_insert (mrec);
+  return 0;
+}
+
+int
+Experiment::process_jcm_unload_cmd (char *, Vaddr /*mid*/, hrtime_t /*ts*/)
+{
+  if (jmaps == NULL)
+    return 1;
+
+  // We are ignoring this record because of the flaw in
+  // JVMPI desing that doesn't distinguish between two or more
+  // compiled instances of a method when an unload event is
+  // generated:
+  //     JVMPI_COMPILED_METHOD_LOAD( mid, addr1, ... )
+  //     JVMPI_COMPILED_METHOD_LOAD( mid, addr2, ... )
+  //     JVMPI_COMPILED_METHOD_UNLOAD( mid ) -- which one?
+  // We rely on the ability of the PRBTree algorithms to
+  // perform mapping appropriately based on timestamps.
+  return 0;
+}
+
+int
+Experiment::process_jthr_end_cmd (char *, uint64_t tid64, Vaddr jthr,
+                                 Vaddr jenv, hrtime_t ts)
+{
+  int lt = 0;
+  int rt = jthreads_idx->size () - 1;
+  uint32_t ttid = mapTagValue (PROP_THRID, tid64);
+  while (lt <= rt)
+    {
+      int md = (lt + rt) / 2;
+      JThread *jthread = jthreads_idx->fetch (md);
+      if (jthread->tid < ttid)
+       lt = md + 1;
+      else if (jthread->tid > ttid)
+       rt = md - 1;
+      else
+       {
+         for (; jthread; jthread = jthread->next)
+           {
+             if (jthread->jenv == jenv)
+               {
+                 jthread->end = ts;
+                 return 0;
+               }
+           }
+         return 0;
+       }
+    }
+  JThread *jthread = new JThread;
+  jthread->tid = mapTagValue (PROP_THRID, tid64);
+  jthread->jthr = jthr;
+  jthread->jenv = jenv;
+  jthread->jthr_id = jthreads->size ();
+  jthread->start = ZERO_TIME;
+  jthread->end = ts;
+  jthread->next = NULL;
+  jthreads->append (jthread);
+  if (lt == jthreads_idx->size ())
+    jthreads_idx->append (jthread);
+  else
+    jthreads_idx->insert (lt, jthread);
+  return 0;
+}
+
+int
+Experiment::process_jthr_start_cmd (char *, char *thread_name, char *group_name,
+                                   char *parent_name, uint64_t tid64,
+                                   Vaddr jthr, Vaddr jenv, hrtime_t ts)
+{
+  JThread *jthread = new JThread;
+  jthread->name = thread_name;
+  jthread->group_name = group_name;
+  jthread->parent_name = parent_name;
+  jthread->tid = mapTagValue (PROP_THRID, tid64);
+  jthread->jthr = jthr;
+  jthread->jenv = jenv;
+  jthread->jthr_id = jthreads->size ();
+  jthread->start = ts;
+  jthread->end = MAX_TIME;
+  jthread->next = NULL;
+
+  jthreads->append (jthread);
+
+  int lt = 0;
+  int rt = jthreads_idx->size () - 1;
+  while (lt <= rt)
+    {
+      int md = (lt + rt) / 2;
+      JThread *jtmp = jthreads_idx->fetch (md);
+      if (jtmp->tid < jthread->tid)
+       lt = md + 1;
+      else if (jtmp->tid > jthread->tid)
+       rt = md - 1;
+      else
+       {
+         jthread->next = jtmp;
+         jthreads_idx->store (md, jthread);
+         return 0;
+       }
+    }
+  if (lt == jthreads_idx->size ())
+    jthreads_idx->append (jthread);
+  else
+    jthreads_idx->insert (lt, jthread);
+  return 0;
+}
+
+int
+Experiment::process_gc_end_cmd (
+                               hrtime_t ts)
+{
+  if (gcevents->size () == 0)
+    {
+      GCEvent *gcevent = new GCEvent;
+      gcevent->start = ZERO_TIME;
+      gcevent->end = ts;
+      gcevent->id = gcevents->size () + 1;
+      gcevents->append (gcevent);
+      return 0;
+    }
+  GCEvent *gcevent = gcevents->fetch (gcevents->size () - 1);
+  if (gcevent->end == MAX_TIME)
+    gcevent->end = ts;
+  else
+    // Weird: gc_end followed by another gc_end
+    gcevent->end = ts; // extend the previous event
+  return 0;
+}
+
+int
+Experiment::process_gc_start_cmd (
+                                 hrtime_t ts)
+{
+  if (gcevents->size () != 0)
+    {
+      GCEvent *gcevent = gcevents->fetch (gcevents->size () - 1);
+      // Weird: gc_start followed by another gc_start
+      if (gcevent->end == MAX_TIME)
+       return 0; // ignore nested gc_starts
+    }
+  GCEvent *gcevent = new GCEvent;
+  gcevent->start = ts;
+  gcevent->end = MAX_TIME;
+  gcevent->id = gcevents->size () + 1;
+  gcevents->append (gcevent);
+  return 0;
+}
+
+int
+Experiment::process_sample_cmd (char */*cmd*/, hrtime_t /*log_xml_time*/,
+                               int sample_number, char *label)
+{
+  // sample 0 is not a sample but the starting point
+  if (sample_number == 0)
+    {
+      first_sample_label = label;
+      return 0;
+    }
+  Sample *prev_sample = samples->size () > 0 ?
+         samples->fetch (samples->size () - 1) : NULL;
+  char *start_lable = prev_sample ?
+         prev_sample->end_label : first_sample_label;
+  Sample *sample = new Sample (sample_number);
+  sample->start_label = dbe_strdup (start_lable);
+  sample->end_label = label;
+  samples->append (sample);
+  return 0;
+}
+
+int
+Experiment::process_sample_sig_cmd (char *, int sig)
+{
+  char *str;
+  Emsg *m;
+  str = dbe_sprintf (GTXT ("Sample signal %d"), sig);
+  m = new Emsg (CMSG_COMMENT, str);
+  free (str);
+  runlogq->append (m);
+  return 0;
+}
+
+int
+Experiment::process_seg_map_cmd (char */*cmd*/, hrtime_t ts, Vaddr vaddr,
+                                int mapsize, int /*pagesize*/, int64_t offset,
+                                int64_t modeflags, int64_t chk, char *nm)
+{
+  if (nm == NULL ||
+      strncmp (nm + 1, SP_MAP_UNRESOLVABLE, strlen (SP_MAP_UNRESOLVABLE)) == 0)
+    return 0;
+
+  LoadObject *lo = loadObjMap->get (nm);
+  if (lo == NULL)
+    {
+      if (chk == 0)
+       {
+         char *archName = checkFileInArchive (nm, false);
+         if (archName)
+           {
+             Elf *elf = new Elf (archName);
+             if (elf->status == Elf::ELF_ERR_NONE)
+               {
+                 chk = elf->elf_checksum ();
+               }
+             free (archName);
+             delete elf;
+           }
+       }
+      lo = dbeSession->find_lobj_by_name (nm, chk);
+      if (lo == NULL)
+       {
+         // Skip non-text segments
+         if (modeflags != (PROT_READ | PROT_EXEC))
+           return 0;
+         // A new segment
+         lo = createLoadObject (nm, chk);
+         if (strstr (nm, NTXT ("libjvm.so")))
+           {
+             lo->flags |= SEG_FLAG_JVM;
+             // Make sure <JVM-System> is created
+             (void) dbeSession->get_jvm_Function ();
+           }
+         else if (strstr (nm, NTXT ("libmtsk.so")))
+           {
+             lo->flags |= SEG_FLAG_OMP;
+             // Make sure all pseudo functions are created
+             for (int i = 0; i < OMP_LAST_STATE; i++)
+               (void) dbeSession->get_OMP_Function (i);
+           }
+         else if (dbe_strcmp (utargname, get_basename (nm)) == 0)
+           {
+             lo->flags |= SEG_FLAG_EXE;
+             (void) dbeSession->comp_lobjs->get ((char *) COMP_EXE_NAME, lo);
+           }
+         lo->checksum = chk;
+         //  This is the default segment type
+         lo->type = LoadObject::SEG_TEXT;
+         lo->flags = lo->flags | SEG_FLAG_REORDER;
+         lo->set_platform (platform, wsize);
+       }
+      if (lo->dbeFile->get_location (false) == NULL)
+       {
+         char *archName = checkFileInArchive (nm, false);
+         if (archName)
+           {
+             lo->dbeFile->set_location (archName);
+             lo->dbeFile->inArchive = true;
+             lo->dbeFile->check_access (archName); // init 'sbuf'
+             lo->dbeFile->sbuf.st_mtime = 0; // Don't check timestamps
+             free (archName);
+           }
+         else
+           {
+             archName = checkFileInArchive (nm, true);
+             if (archName)
+               {
+                 lo->set_archname (archName);
+                 lo->need_swap_endian = need_swap_endian;
+               }
+           }
+         if (!dbeSession->archive_mode)
+           lo->sync_read_stabs ();
+       }
+      append (lo);
+    }
+  if (lo->size == 0)
+    lo->size = mapsize;
+  MapRecord *mrec = new MapRecord;
+  mrec->kind = MapRecord::LOAD;
+  mrec->obj = lo;
+  mrec->base = vaddr;
+  mrec->size = mapsize;
+  mrec->ts = ts;
+  mrec->foff = offset;
+  mrec_insert (mrec);
+  return 0;
+}
+
+int
+Experiment::process_seg_unmap_cmd (char */*cmd*/, hrtime_t ts, Vaddr vaddr)
+{
+  MapRecord *mrec = new MapRecord;
+  mrec->kind = MapRecord::UNLOAD;
+  mrec->base = vaddr;
+  mrec->ts = ts;
+  mrec_insert (mrec);
+  return 0;
+}
+
+int
+Experiment::process_Linux_kernel_cmd (hrtime_t ts)
+{
+  LoadObject *lo = createLoadObject ("LinuxKernel");
+  lo->flags |= SEG_FLAG_EXE;
+  lo->type = LoadObject::SEG_TEXT;
+  lo->set_platform (platform, wsize);
+  append (lo);
+  long long unsigned lo_min = (long long unsigned) (-1);
+  long long unsigned lo_max = 0;
+  Module *mod = dbeSession->createModule (lo, "LinuxKernel");
+  /*
+   * XXX need to review mod initialization
+   * A specific issue is mod->file_name.  Options include:
+   *     *) NULL
+   *            This leads to seg faults in, e.g., Timeline view.
+   *     *) "/lib/modules/$(uname -r)/kernel/kernel/ctf/ctf.ko"
+   *            This leads to garbage in the Source view.
+   *     *) "/boot/vmlinuz-$(uname -r)"
+   *            This cannot be parsed for DWARF and is sometimes not found,
+   *            but the Analyzer seems to handle such problems.
+   *     *) "LinuxKernel"
+   *            This is not a proper file name,
+   *            but again Analyzer handles the case of not finding the file or not reading DWARF from it.
+   */
+  mod->set_file_name (dbe_strdup ("LinuxKernel"));
+  char last_mod_name[256];
+  last_mod_name[0] = '\0';
+  size_t line_n = 0;
+  char *line = NULL;
+  char kallmodsyms_copy[MAXPATHLEN];
+  snprintf (kallmodsyms_copy, sizeof (kallmodsyms_copy), "%s/kallmodsyms",
+           expt_name);
+  FILE *fd = fopen (kallmodsyms_copy, "r");
+  if (fd == NULL)
+    {
+      char *s = dbe_sprintf (GTXT ("*** Error: Cannot find kernel module symbols file %s; ignored"),
+                            kallmodsyms_copy);
+      Emsg *m = new Emsg (CMSG_ERROR, s);
+      free (s);
+      errorq->append (m);
+      lo_min = 0;
+    }
+  else
+    {
+      while (getline (&line, &line_n, fd) > 0)
+       {
+         long long unsigned sym_addr;
+         long long unsigned sym_size;
+         char sym_type;
+         int sym_text;
+         char sym_name[256];
+         char mod_name[256] = "vmlinux]"; /* note trailing ] */
+         sscanf (line, "%llx %llx %c %s [%s", &sym_addr, &sym_size, &sym_type,
+                 sym_name, mod_name);
+         if (line[0] == '\n' || line[0] == 0)
+           continue;
+         sym_text = (sym_type == 't' || sym_type == 'T');
+         mod_name[strlen (mod_name) - 1] = '\0'; /* chop trailing ] */
+         if (strcmp (mod_name, "ctf") == 0)
+           strcpy (mod_name, "shared_ctf");
+
+         char *mod_name_ptr;
+         int skip;
+#define strstarts(var, x) (strncmp(var, x, strlen (x)) == 0)
+         if (strcmp (sym_name, "__per_cpu_start") == 0
+             || strcmp (sym_name, "__per_cpu_end") == 0
+             || strstarts (sym_name, "__crc_")
+             || strstarts (sym_name, "__ksymtab_")
+             || strstarts (sym_name, "__kcrctab_")
+             || strstarts (sym_name, "__kstrtab_")
+             || strstarts (sym_name, "__param_")
+             || strstarts (sym_name, "__syscall_meta__")
+             || strstarts (sym_name, "__p_syscall_meta__")
+             || strstarts (sym_name, "__event_")
+             || strstarts (sym_name, "event_")
+             || strstarts (sym_name, "ftrace_event_")
+             || strstarts (sym_name, "types__")
+             || strstarts (sym_name, "args__")
+             || strstarts (sym_name, "__tracepoint_")
+             || strstarts (sym_name, "__tpstrtab_")
+             || strstarts (sym_name, "__tpstrtab__")
+             || strstarts (sym_name, "__initcall_")
+             || strstarts (sym_name, "__setup_")
+             || strstarts (sym_name, "__pci_fixup_")
+             || strstarts (sym_name, "__dta_")
+             || strstarts (sym_name, "__dtrace_probe_")
+             || (strstr (sym_name, ".") != NULL
+                 &&  strstr (sym_name, ".clone.") == NULL))
+           {
+             mod_name_ptr = last_mod_name;
+             skip = 1;
+           }
+         else
+           {
+             mod_name_ptr = mod_name;
+             skip = 0;
+           }
+#undef strstarts
+
+         if (sym_text && skip == 0)
+           {
+             char fname[128];
+             snprintf (fname, sizeof (fname), "%s`%s", mod_name_ptr, sym_name);
+             Function *func = dbeSession->createFunction ();
+             func->set_name (fname);
+             // func->flags |= FUNC_FLAG_???;  // XXX
+             func->size = sym_size;
+             func->img_offset = sym_addr;
+             func->module = mod;
+             lo->functions->append (func);
+             mod->functions->append (func);
+             if (lo_min > sym_addr)
+               lo_min = sym_addr;
+             if (lo_max < sym_addr + sym_size)
+               lo_max = sym_addr + sym_size;
+           }
+         sprintf (last_mod_name, mod_name_ptr);
+       }
+      fclose (fd);
+    }
+  free (line);
+  lo->size = lo_max;
+  lo->functions->sort (func_cmp);
+  mod->functions->sort (func_cmp);
+
+  MapRecord *mrec = new MapRecord;
+  mrec->kind = MapRecord::LOAD;
+  mrec->obj = lo;
+  mrec->base = lo_min;
+  mrec->size = lo_max - lo_min;
+  mrec->ts = ts;
+  mrec->foff = lo_min;
+  mrec_insert (mrec);
+  return 0;
+}
diff --git a/gprofng/src/stab.h b/gprofng/src/stab.h
new file mode 100644 (file)
index 0000000..4610105
--- /dev/null
@@ -0,0 +1,205 @@
+/* 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.  */
+
+/*
+ * This file gives definitions supplementing <a.out.h>
+ * for debugging symbol table entries.
+ * These entries must have one of the N_STAB bits on,
+ * and are subject to relocation according to the masks in <a.out.h>
+ * on 4.x (stabs not relocated on SVR4).
+ */
+
+#ifndef _STAB_H
+#define _STAB_H
+
+/* this file also contains fragments of a.out.h relevant to
+ * support of stab processing within ELF files
+ * (when a.out.h is not available)
+ */
+struct stab
+{
+  unsigned n_strx;      /* index into file string table */
+  unsigned char n_type; /* type flag (N_TEXT,..)  */
+  char n_other;         /* used by N_SLINE stab */
+  short n_desc;         /* see stabs documentation */
+  unsigned n_value;     /* value of symbol (or sdb offset) */
+};
+
+/* patchtypes for N_PATCH stab (n_desc field) */
+#define P_BITFIELD          0x1
+#define P_SPILL             0x2
+#define P_SCOPY             0x3
+
+/* markers for N_CODETAG stab (n_other field) */
+#define CODETAG_BITFIELD    0x1 /* load/store of a bit field */
+#define CODETAG_SPILL       0x2 /* spill of registers */
+#define CODETAG_SCOPY       0x3 /* structure copy load/store */
+#define CODETAG_FSTART      0x4 /* points to first inst of new frame (0==leaf)*/
+#define CODETAG_END_CTORS   0x5 /* end of calls to super-class constructors */
+/* UNUSED 0x6 DW_ATCF_SUN_branch_target in dwarf, not used in stabs */
+#define CODETAG_STACK_PROBE 0x7 /* marks insns which probe the stack memory */
+
+/*
+ * Simple values for n_type.
+ */
+#define N_UNDF      0x0     /* undefined */
+#define N_ABS       0x2     /* absolute */
+#define N_TEXT      0x4     /* text */
+#define N_DATA      0x6     /* data */
+#define N_BSS       0x8     /* bss */
+#define N_COMM      0x12    /* common (internal to ld) */
+#define N_FN        0x1f    /* file name symbol */
+#define N_EXT       01      /* external bit, or'ed in */
+#define N_TYPE      0x1e    /* mask for all the type bits */
+
+/*
+ * maximum length of stab string before using continuation stab.
+ *   (this is just a suggested limit), assembler has no limit.
+ */
+#define MAX_STAB_STR_LEN 250
+
+/*
+ * for symbolic debuggers:
+ */
+#define N_GSYM      0x20  /* global symbol: name,,0,type,0 */
+#define N_FNAME     0x22  /* procedure name (f77 kludge): name,,0 */
+#define N_FUN       0x24  /* procedure: name,,0,linenumber,0 */
+#define N_OUTL      0x25  /* outlined func: name,,0,linenumber,0 */
+#define N_STSYM     0x26  /* static symbol: name,,0,type,0 or section relative */
+#define N_TSTSYM    0x27  /* thread static symbol: Ttdata.data */
+#define N_LCSYM     0x28  /* .lcomm symbol: name,,0,type,0 or section relative */
+#define N_TLCSYM    0x29  /* thread local symbol: Ttbss.bss */
+#define N_MAIN      0x2a  /* name of main routine : name,,0,0,0 */
+#define N_ROSYM     0x2c  /* ro_data: name,,0,type,0 or section relative */
+#define N_FLSYM     0x2e  /* fragmented data: name,,0,type,0 */
+#define N_TFLSYM    0x2f  /* thread fragmented data: name,,0,type,0 */
+#define N_PC        0x30  /* global pascal symbol: name,,0,subtype,line */
+#define N_CMDLINE   0x34  /* command line info */
+#define N_OBJ       0x38  /* object file path or name */
+#define N_OPT       0x3c  /* compiler options */
+#define N_RSYM      0x40  /* register sym: name,,0,type,register */
+#define N_SLINE     0x44  /* src line: 0,,0,linenumber,function relative */
+#define N_XLINE     0x45  /* h.o. src line: 0,,0,linenumber>>16,0 */
+#define N_ILDPAD    0x4c  /* now used as ild pad stab value=strtab delta
+                          * was designed for "function start.end" */
+#define N_SSYM      0x60  /* structure elt: name,,0,type,struct_offset */
+#define N_ENDM      0x62  /* last stab emitted for object module */
+#define N_SO        0x64  /* source file name: name,,0,0,0 */
+#define N_MOD       0x66  /* f90 module: name,,0,0,0 */
+#define N_EMOD      0x68  /* end of f90 module: name,,0,0,0 */
+#define N_READ_MOD  0x6a  /* use of f90 module: name;locallist,,0,0,0 */
+#define N_ALIAS     0x6c  /* alias name: name,,0,0,0 */
+#define N_LSYM      0x80  /* local sym: name,,0,type,offset */
+#define N_BINCL     0x82  /* header file: name,,0,0,0 */
+#define N_SOL       0x84  /* #included file name: name,,0,0,0 */
+#define N_PSYM      0xa0  /* parameter: name,,0,type,offset */
+#define N_EINCL     0xa2  /* end of include file */
+#define N_ENTRY     0xa4  /* alternate entry: name,linenumber,0 */
+#define N_SINCL     0xa6  /* shared include file */
+#define N_LBRAC     0xc0  /* left bracket: 0,,0,nesting level,function relative */
+#define N_EXCL      0xc2  /* excluded include file */
+#define N_USING     0xc4  /* C++ using command */
+#define N_ISYM      0xc6  /* position independent type symbol, internal */
+#define N_ESYM      0xc8  /* position independent type symbol, external */
+#define N_PATCH     0xd0  /* Instruction to be ignored by run-time checking. */
+#define N_CONSTRUCT 0xd2  /* C++ constructor call. */
+#define N_DESTRUCT  0xd4  /* C++ destructor call. */
+#define N_CODETAG   0xd8  /* Generic code tag */
+#define N_FUN_CHILD 0xd9  /* Identifies a child function */
+#define N_RBRAC     0xe0  /* right bracket: 0,,0,nesting level,function relative */
+#define N_BCOMM     0xe2  /* begin common: name,, */
+#define N_TCOMM     0xe3  /* begin task common: name,, */
+#define N_ECOMM     0xe4  /* end task_common/common: name,, */
+#define N_XCOMM     0xe6  /* excluded common block */
+#define N_ECOML     0xe8  /* end common (local name): ,,address */
+#define N_WITH      0xea  /* pascal with statement: type,,0,0,offset */
+#define N_LENG      0xfe  /* second stab entry with length information */
+
+/*
+ * for analyzer (cache profile feedback support)
+ */
+#define N_CPROF     0xf0  /* annotation for cache profile feedback */
+
+/*
+ * n_descr values used in N_CPROF stabs.  The n_descr field of
+ * an N_CPROF stab identifies the type of table whose location
+ * is defined by the N_CPROF stab.
+ */
+typedef enum n_cprof_instr_type_t
+{
+  N_CPROF_INSTR_TYPE_LOAD = 0,  /* profiled load ops */
+  N_CPROF_INSTR_TYPE_STORE,     /* profiled store ops */
+  N_CPROF_INSTR_TYPE_PREFETCH,  /* profiled prefetch ops */
+  N_CPROF_INSTR_TYPE_BRTARGET,  /* branch target locations */
+  N_CPROF_INSTR_TYPE_NTYPES     /* number of types */
+} n_cprof_instr_type_t;
+
+/*
+ * for code browser only
+ */
+#define N_BROWS 0x48  /* path to associated .cb file */
+
+/*
+ * for functions -- n_other bits for N_FUN stab
+ */
+#define N_FUN_PURE              (1 << 0)
+#define N_FUN_ELEMENTAL         (1 << 1)
+#define N_FUN_RECURSIVE         (1 << 2)
+#define N_FUN_AMD64_PARMDUMP    (1 << 3)
+
+/*
+ * for variables -- n_other bits for N_LSYM, N_GSYM, N_LCSYM, N_STSYM, ...
+ */
+#define N_SYM_OMP_TLS       (1 << 3)
+
+/*
+ * Optional language designations for N_SO (n_desc field)
+ */
+#define N_SO_AS             1   /* Assembler  */
+#define N_SO_C              2   /* C          */
+#define N_SO_ANSI_C         3   /* ANSI C     */
+#define N_SO_CC             4   /* C++        */
+#define N_SO_FORTRAN        5   /* Fortran 77 */
+#define N_SO_FORTRAN77      5   /* Fortran 77 */
+#define N_SO_PASCAL         6   /* Pascal     */
+#define N_SO_FORTRAN90      7   /* Fortran 90 */
+#define N_SO_JAVA           8   /* Java       */
+#define N_SO_C99            9   /* C99        */
+
+/*
+ * Floating point type values (encoded in "R" type specification string)
+ */
+#define NF_NONE             0   /* Undefined type */
+#define NF_SINGLE           1   /* Float IEEE 32 bit floating point */
+#define NF_DOUBLE           2   /* Double IEEE 64 bit floating point */
+#define NF_COMPLEX          3   /* Complex (2 32bit floats) */
+#define NF_COMPLEX16        4   /* Complex (2 64bit doubles) */
+#define NF_COMPLEX32        5   /* Complex (2 128bit long doubles) */
+#define NF_LDOUBLE          6   /* Long double 128 bit floating point */
+#define NF_INTERARITH       7   /* Interval (2 32bit floats) */
+#define NF_DINTERARITH      8   /* Interval (2 64bit doubles) */
+#define NF_QINTERARITH      9   /* Interval (2 128bit long doubles) */
+#define NF_IMAGINARY        10  /* Imaginary (1 32bit floats) */
+#define NF_DIMAGINARY       11  /* Imaginary (1 64bit doubles) */
+#define NF_QIMAGINARY       12  /* Imaginary (1 128bit long doubles) */
+
+#endif
+
+
diff --git a/gprofng/src/util.cc b/gprofng/src/util.cc
new file mode 100644 (file)
index 0000000..b93deaf
--- /dev/null
@@ -0,0 +1,1582 @@
+/* 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/param.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <dirent.h>    // readdir()
+#include <sys/param.h> // MAXPATHLEN
+#include <pthread.h>   // mutex
+#include <libgen.h>    // dirname
+#include <sys/types.h> // open
+#include <sys/stat.h>  // open
+#include <errno.h>     // errno
+#include <fcntl.h>     // open
+
+#include "util.h"
+#include "dbe_structs.h"
+#include "StringBuilder.h"
+#include "StringMap.h"      // For directory names
+#include "Application.h"    // Only for get_prog_name
+#include "vec.h"
+
+void
+tsadd (timestruc_t *result, timestruc_t *time)
+{
+  // This routine will add "time" to "result".
+  result->tv_sec += time->tv_sec;
+  result->tv_nsec += time->tv_nsec;
+  if (result->tv_nsec >= NANOSEC)
+    {
+      result->tv_nsec -= NANOSEC;
+      result->tv_sec++;
+    }
+}
+
+void
+tssub (timestruc_t *result, timestruc_t *time1, timestruc_t *time2)
+{
+  // This routine will store "time1" - "time2" in "result".
+
+  if (time1->tv_nsec >= time2->tv_nsec)
+    {
+      result->tv_nsec = time1->tv_nsec - time2->tv_nsec;
+      if (time1->tv_sec >= time2->tv_sec)
+       result->tv_sec = time1->tv_sec - time2->tv_sec;
+      else
+       {
+         result->tv_sec = -1;
+         result->tv_nsec = 0;
+       }
+    }
+  else
+    {
+      result->tv_nsec = time1->tv_nsec + NANOSEC - time2->tv_nsec;
+      if (time1->tv_sec - 1 >= time2->tv_sec)
+       result->tv_sec = time1->tv_sec - 1 - time2->tv_sec;
+      else
+       {
+         result->tv_sec = -1;
+         result->tv_nsec = 0;
+       }
+    }
+}
+
+int
+tscmp (timestruc_t *time1, timestruc_t *time2)
+{
+  // This routine will return 1 if "time1" is greater than "time2"
+  // and 0 if "time1" is equal to "time2" and -1 otherwise.
+  if (time1->tv_sec == time2->tv_sec)
+    return time1->tv_nsec > time2->tv_nsec ? 1 :
+         time1->tv_nsec == time2->tv_nsec ? 0 : -1;
+  else
+    return time1->tv_sec > time2->tv_sec ? 1 : -1;
+}
+
+void
+int_max (int *maximum, int count)
+{
+  if (count > *maximum)
+    *maximum = count;
+}
+
+double
+TValue::to_double ()
+{
+  switch (tag)
+    {
+    case VT_DOUBLE:
+      return (double) d;
+    case VT_INT:
+      return (double) i;
+    case VT_ULLONG:
+      return (double) ull;
+    case VT_LLONG:
+    case VT_ADDRESS:
+      return (double) ll;
+    case VT_FLOAT:
+      return (double) f;
+    case VT_SHORT:
+      return (double) s;
+    default:
+      return 0.0;
+    }
+}
+
+int
+TValue::to_int ()
+{
+  switch (tag)
+    {
+    case VT_DOUBLE:
+      return (int) d;
+    case VT_INT:
+      return (int) i;
+    case VT_ULLONG:
+      return (int) ull;
+    case VT_LLONG:
+    case VT_ADDRESS:
+      return (int) ll;
+    case VT_FLOAT:
+      return (int) f;
+    case VT_SHORT:
+      return (int) s;
+    default:
+      return 0;
+    }
+}
+
+size_t
+TValue::get_len ()
+{
+  char buf[256];
+  return strlen (to_str (buf, sizeof (buf)));
+}
+
+char *
+TValue::to_str (char *str, size_t strsz)
+{
+  switch (tag)
+    {
+    case VT_DOUBLE:
+      if (d == 0.)
+       {
+         if (sign)
+           snprintf (str, strsz, NTXT ("+0.   "));
+         else
+           snprintf (str, strsz, NTXT ("0.   "));
+       }
+      else if (sign)
+       snprintf (str, strsz, NTXT ("%+.3lf"), d);
+      else
+       snprintf (str, strsz, NTXT ("%.3lf"), d);
+      break;
+    case VT_INT:
+      snprintf (str, strsz, NTXT ("%u"), i);
+      break;
+    case VT_LLONG:
+      if (sign)
+       snprintf (str, strsz, NTXT ("%+lld"), ll);
+      else
+       snprintf (str, strsz, NTXT ("%lld"), ll);
+      break;
+    case VT_ULLONG:
+      snprintf (str, strsz, NTXT ("%llu"), ll);
+      break;
+    case VT_ADDRESS:
+      snprintf (str, strsz, NTXT ("%u:0x%08x"), ADDRESS_SEG (ll), ADDRESS_OFF (ll));
+      break;
+    case VT_FLOAT:
+      snprintf (str, strsz, NTXT ("%.3f"), f);
+      break;
+    case VT_SHORT:
+      snprintf (str, strsz, NTXT ("%hu"), s);
+      break;
+    case VT_LABEL:
+      return l; // 'str' is not used !!!
+    default:
+      *str = '\0';
+      break;
+    }
+
+  return str;
+}
+
+void
+TValue::make_delta (TValue *v1, TValue *v2)
+{
+  assert (v1->tag == v2->tag);
+  tag = v1->tag;
+  sign = true;
+  switch (v1->tag)
+    {
+    case VT_INT:
+      i = v1->i - v2->i;
+      break;
+    case VT_LLONG:
+      ll = v1->ll - v2->ll;
+      break;
+    case VT_ULLONG:
+    case VT_ADDRESS:
+      tag = VT_LLONG;
+      ll = (long long) (v1->ull - v2->ull);
+      break;
+    case VT_FLOAT:
+      f = v1->f - v2->f;
+      break;
+    case VT_DOUBLE:
+      d = v1->d - v2->d;
+      break;
+    default:
+      assert (0);
+      break;
+    }
+}
+
+void
+TValue::make_ratio (TValue *v1, TValue *v2)
+{
+  assert (v1->tag == v2->tag);
+  double x1 = v1->to_double ();
+  double x2 = v2->to_double ();
+  sign = false;
+  if (x1 == 0.)
+    {
+      // if the numerator is 0, the ratio is 1. or 0. only
+      d = (x2 == 0.) ? 1. : 0.;
+      tag = VT_DOUBLE;
+    }
+  else
+    {
+      // EUGENE replace 99.999 with a variable that is known by both DBE and GUI
+      if (x1 > 99.999 * x2)
+       {
+         l = dbe_strdup (">99.999");
+         tag = VT_LABEL;
+       }
+      else if (x1 < -99.999 * x2)
+       {
+         l = dbe_strdup ("<-99.999");
+         tag = VT_LABEL;
+       }
+      else
+       {
+         d = x1 / x2;
+         tag = VT_DOUBLE;
+       }
+    }
+}
+
+int
+TValue::compare (TValue *v)
+{
+  if (tag != v->tag)
+    { // Only for comparison (Ratio)
+      if (tag == VT_LABEL)
+       {
+         if (v->tag == VT_LABEL)
+           return strcoll (l, v->l);
+         return 1;
+       }
+      if (v->tag == VT_LABEL)
+       return -1;
+      return ll < v->ll ? -1 : (ll == v->ll ? 0 : 1);
+    }
+  switch (tag)
+    {
+    case VT_SHORT:
+      return s < v->s ? -1 : (s == v->s ? 0 : 1);
+    case VT_INT:
+      return i < v->i ? -1 : (i == v->i ? 0 : 1);
+    case VT_FLOAT:
+      return f < v->f ? -1 : (f == v->f ? 0 : 1);
+    case VT_DOUBLE:
+      return d < v->d ? -1 : (d == v->d ? 0 : 1);
+    case VT_LABEL:
+      return strcoll (l, v->l);
+    case VT_LLONG:
+    case VT_ULLONG:
+    case VT_ADDRESS:
+    case VT_HRTIME:
+    default:
+      return (ll < v->ll) ? -1 : ((ll == v->ll) ? 0 : 1);
+    }
+}
+
+char *
+strstr_r (char *s1, const char *s2)
+{
+  char *str = NULL;
+  for (char *s = s1; s;)
+    {
+      s = strstr (s, s2);
+      if (s)
+       {
+         str = s;
+         s++;
+       }
+    }
+  return str;
+}
+
+// reversal order of strpbrk
+
+char *
+strrpbrk (const char *string, const char *brkset)
+{
+  const char *p;
+  const char *s;
+  for (s = string + strlen (string) - 1; s >= string; s--)
+    {
+      for (p = brkset; *p != '\0' && *p != *s; ++p)
+       ;
+      if (*p != '\0')
+       return ((char *) s);
+    }
+  return NULL;
+}
+
+char *
+read_line (FILE *fptr)
+{
+  // get an input line, no size limit
+  int line_sz = 128; // starting size
+  char *line = (char *) malloc (line_sz);
+
+  // read as much of the line as will fit in memory
+  line[0] = 0;
+  int len = 0;
+  for (;;)
+    {
+      while (fgets (line + len, line_sz - len, fptr) != NULL)
+       {
+         len = (int) strlen (line);
+         if (len == 0 || line[len - 1] == '\n')
+           break;
+         // increase the buffer
+         char *lineNew = (char *) malloc (2 * line_sz);
+         strncpy (lineNew, line, line_sz);
+         lineNew[line_sz] = '\0';
+         free (line);
+         line = lineNew;
+         line_sz *= 2;
+         if (line == NULL)
+           {
+             fprintf (stderr, GTXT ("   Line too long -- out of memory; exiting\n"));
+             exit (1);
+           }
+       }
+      if (len == 0)
+       {
+         free (line);
+         return NULL;
+       }
+      // see if there's a continuation line
+      if ((len >= 2) && (line[len - 1] == '\n') && (line[len - 2] == '\\'))
+       {
+         // remove the trailing \ and the \n, and keep going
+         line[len - 2] = 0;
+         len -= 2;
+       }
+      else
+       break;
+    }
+  return line; // expecting the caller to free it
+}
+
+Vector<char *> *
+split_str (char *str, char delimiter)
+{
+  Vector<char *> *v = new Vector<char *>;
+  for (char *s = str; s;)
+    {
+      if (*s == '"')
+       {
+         char *next_s = NULL;
+         char *tok = parse_qstring (s, &next_s);
+         if (tok && *tok != '\0')
+           v->append (tok);
+         if (*next_s)
+           s = next_s + 1;
+         else
+           s = NULL;
+       }
+      else
+       {
+         char *next_s = strchr (s, delimiter);
+         if (next_s)
+           {
+             if (next_s != s)
+               v->append (dbe_strndup (s, next_s - s));
+             s = next_s + 1;
+           }
+         else
+           {
+             if (*s != '\0')
+               v->append (dbe_strdup (s));
+             s = NULL;
+           }
+       }
+    }
+  return v;
+}
+
+// get quoted string
+char *
+parse_qstring (char *in_str, char **endptr)
+{
+  int i;
+  char c, c2;
+  char term;
+  char csnum[2 * MAXPATHLEN];
+
+  // Skip any leading blanks or tabs
+  while (*in_str == '\t' || *in_str == ' ')
+    in_str++;
+
+  int gtxt = 0;
+  if (*in_str == 'G' && *(in_str + 1) == 'T' && *(in_str + 2) == 'X'
+      && *(in_str + 3) == 'T' && *(in_str + 4) == '(')
+    {
+      gtxt = 1;
+      in_str += 5;
+    }
+  // non-quoted string
+  if (*in_str == '"')
+    term = '"';
+  else if (*in_str == '\'')
+    term = '\'';
+  else
+    return strtok_r (in_str, NTXT (" "), endptr);
+
+  StringBuilder sb;
+  while ((c = *(++in_str)) != '\0')
+    {
+      if (c == term) // the closing quote
+       break;
+      if (c == '\\')
+       { // handle any escaped characters
+         c2 = *(++in_str);
+         switch (c2)
+           {
+           case '\"':
+             sb.append ('\"');
+             break;
+           case '\'':
+             sb.append ('\'');
+             break;
+           case '\\':
+             sb.append ('\\');
+             break;
+           case 't':
+             sb.append ('\t');
+             break;
+           case 'r':
+             sb.append ('\r');
+             break;
+           case 'b':
+             sb.append ('\b');
+             break;
+           case 'f':
+             sb.append ('\f');
+             break;
+           case 'n':
+             sb.append ('\n');
+             break;
+           default:
+             if ((c2 >= '0') && (c2 <= '9'))
+               {
+                 for (i = 0; i < MAXPATHLEN; i++)
+                   {
+                     if (((c2 < '0') || (c2 > '9')) && (c2 != 'x') &&
+                         ((c2 < 'a') || (c2 > 'f')) &&
+                         ((c2 < 'A') || (c2 > 'F')))
+                       {
+                         csnum[i] = '\0';
+                         --in_str;
+                         break;
+                       }
+                     else
+                       {
+                         csnum[i] = c2;
+                         c2 = *(++in_str);
+                       }
+                   }
+                 sb.append ((char) strtoul (csnum, endptr, 0));
+               }
+             else
+               sb.append (c2);
+             break;
+           }
+       }
+      else
+       sb.append (c);
+    }
+  if (c == term && gtxt && *in_str == ')')
+    in_str++;
+  if (*in_str == '\0')
+    *endptr = in_str;
+  else
+    *endptr = in_str + 1;
+  return sb.toString ();
+}
+
+// parse a file name of the form name`name2`
+// returns name
+// stores the pointer to named in fcontext
+// returns NULL if the string is not properly formatted
+char *
+parse_fname (char *in_str, char **fcontext)
+{
+  *fcontext = NULL;
+  int ch = '`';
+  if (in_str == NULL)
+    return NULL;
+  char *copy = strdup (in_str);
+  char *p = strchr (copy, ch);
+  if (p != NULL)
+    {
+      // yes, there's an embedded file name
+      *p = '\0';
+      p++;
+      // now find the terminating single quote
+      char *p1 = strchr (p, ch);
+      if (p1 == NULL)
+       {
+         // if we don't have the closing `, the format is incorrect
+         free (copy);
+         return NULL;
+       }
+      //remove the closing quote
+      *p1 = '\0';
+      // see if there's anything following it
+      if (*(p1 + 1) != 0)
+       {
+         // error in format
+         free (copy);
+         return NULL;
+       }
+      free (*fcontext);
+      *fcontext = strdup (p);
+    }
+  return copy;
+}
+
+int
+get_paren (const char *name)
+{
+  char buf[8192];
+  char *ptr;
+  int temp_level1, temp_level2;
+
+  temp_level1 = temp_level2 = 0;
+  snprintf (buf, sizeof (buf), NTXT ("%s"), name);
+  while ((ptr = strrpbrk (buf, "><)(")) != NULL)
+    {
+      if (*ptr == '>')
+       temp_level1++;
+      else if (*ptr == '<')
+       temp_level1--;
+      else if (*ptr == ')')
+       temp_level2++;
+      else
+       {
+         temp_level2--;
+         if (temp_level1 <= 0 && temp_level2 <= 0)
+           return (int) (ptr - buf);
+       }
+      *ptr = '\0';
+    }
+  return -1;
+}
+
+// CRC-64 based on x^64 + x^11 + x^2 + x + 1 polynomial.
+// This algorithm doesn't perform well but is short and
+// readable. We currently use it for a small amount of
+// short strings. Should this change, another algorithm
+// with better performance is to be used instead.
+static uint64_t masks[256] = {
+  /*   0 */ 0x000000, 0x000807, 0x00100e, 0x001809, 0x00201c, 0x00281b,
+  /*   6 */ 0x003012, 0x003815, 0x004038, 0x00483f, 0x005036, 0x005831,
+  /*  12 */ 0x006024, 0x006823, 0x00702a, 0x00782d, 0x008070, 0x008877,
+  /*  18 */ 0x00907e, 0x009879, 0x00a06c, 0x00a86b, 0x00b062, 0x00b865,
+  /*  24 */ 0x00c048, 0x00c84f, 0x00d046, 0x00d841, 0x00e054, 0x00e853,
+  /*  30 */ 0x00f05a, 0x00f85d, 0x0100e0, 0x0108e7, 0x0110ee, 0x0118e9,
+  /*  36 */ 0x0120fc, 0x0128fb, 0x0130f2, 0x0138f5, 0x0140d8, 0x0148df,
+  /*  42 */ 0x0150d6, 0x0158d1, 0x0160c4, 0x0168c3, 0x0170ca, 0x0178cd,
+  /*  48 */ 0x018090, 0x018897, 0x01909e, 0x019899, 0x01a08c, 0x01a88b,
+  /*  54 */ 0x01b082, 0x01b885, 0x01c0a8, 0x01c8af, 0x01d0a6, 0x01d8a1,
+  /*  60 */ 0x01e0b4, 0x01e8b3, 0x01f0ba, 0x01f8bd, 0x0201c0, 0x0209c7,
+  /*  66 */ 0x0211ce, 0x0219c9, 0x0221dc, 0x0229db, 0x0231d2, 0x0239d5,
+  /*  72 */ 0x0241f8, 0x0249ff, 0x0251f6, 0x0259f1, 0x0261e4, 0x0269e3,
+  /*  78 */ 0x0271ea, 0x0279ed, 0x0281b0, 0x0289b7, 0x0291be, 0x0299b9,
+  /*  84 */ 0x02a1ac, 0x02a9ab, 0x02b1a2, 0x02b9a5, 0x02c188, 0x02c98f,
+  /*  90 */ 0x02d186, 0x02d981, 0x02e194, 0x02e993, 0x02f19a, 0x02f99d,
+  /*  96 */ 0x030120, 0x030927, 0x03112e, 0x031929, 0x03213c, 0x03293b,
+  /* 102 */ 0x033132, 0x033935, 0x034118, 0x03491f, 0x035116, 0x035911,
+  /* 108 */ 0x036104, 0x036903, 0x03710a, 0x03790d, 0x038150, 0x038957,
+  /* 114 */ 0x03915e, 0x039959, 0x03a14c, 0x03a94b, 0x03b142, 0x03b945,
+  /* 120 */ 0x03c168, 0x03c96f, 0x03d166, 0x03d961, 0x03e174, 0x03e973,
+  /* 126 */ 0x03f17a, 0x03f97d, 0x040380, 0x040b87, 0x04138e, 0x041b89,
+  /* 132 */ 0x04239c, 0x042b9b, 0x043392, 0x043b95, 0x0443b8, 0x044bbf,
+  /* 138 */ 0x0453b6, 0x045bb1, 0x0463a4, 0x046ba3, 0x0473aa, 0x047bad,
+  /* 144 */ 0x0483f0, 0x048bf7, 0x0493fe, 0x049bf9, 0x04a3ec, 0x04abeb,
+  /* 150 */ 0x04b3e2, 0x04bbe5, 0x04c3c8, 0x04cbcf, 0x04d3c6, 0x04dbc1,
+  /* 156 */ 0x04e3d4, 0x04ebd3, 0x04f3da, 0x04fbdd, 0x050360, 0x050b67,
+  /* 162 */ 0x05136e, 0x051b69, 0x05237c, 0x052b7b, 0x053372, 0x053b75,
+  /* 168 */ 0x054358, 0x054b5f, 0x055356, 0x055b51, 0x056344, 0x056b43,
+  /* 174 */ 0x05734a, 0x057b4d, 0x058310, 0x058b17, 0x05931e, 0x059b19,
+  /* 180 */ 0x05a30c, 0x05ab0b, 0x05b302, 0x05bb05, 0x05c328, 0x05cb2f,
+  /* 186 */ 0x05d326, 0x05db21, 0x05e334, 0x05eb33, 0x05f33a, 0x05fb3d,
+  /* 192 */ 0x060240, 0x060a47, 0x06124e, 0x061a49, 0x06225c, 0x062a5b,
+  /* 198 */ 0x063252, 0x063a55, 0x064278, 0x064a7f, 0x065276, 0x065a71,
+  /* 204 */ 0x066264, 0x066a63, 0x06726a, 0x067a6d, 0x068230, 0x068a37,
+  /* 210 */ 0x06923e, 0x069a39, 0x06a22c, 0x06aa2b, 0x06b222, 0x06ba25,
+  /* 216 */ 0x06c208, 0x06ca0f, 0x06d206, 0x06da01, 0x06e214, 0x06ea13,
+  /* 222 */ 0x06f21a, 0x06fa1d, 0x0702a0, 0x070aa7, 0x0712ae, 0x071aa9,
+  /* 228 */ 0x0722bc, 0x072abb, 0x0732b2, 0x073ab5, 0x074298, 0x074a9f,
+  /* 234 */ 0x075296, 0x075a91, 0x076284, 0x076a83, 0x07728a, 0x077a8d,
+  /* 240 */ 0x0782d0, 0x078ad7, 0x0792de, 0x079ad9, 0x07a2cc, 0x07aacb,
+  /* 246 */ 0x07b2c2, 0x07bac5, 0x07c2e8, 0x07caef, 0x07d2e6, 0x07dae1,
+  /* 252 */ 0x07e2f4, 0x07eaf3, 0x07f2fa, 0x07fafd
+};
+
+uint64_t
+crc64 (const char *str, size_t len)
+{
+  uint64_t res = 0LL;
+  for (size_t i = 0; i < len; i++)
+    {
+      unsigned char b = (unsigned char) ((res >> 56) ^ *str++);
+      res = res << 8;
+      res ^= masks [b];
+    }
+  return res;
+}
+
+/**
+ * Canonize path inside the string provided by the argument
+ * @param path
+ * @return path
+ */
+char *
+canonical_path (char *path)
+{
+  char *s1, *s2;
+  if (!path)
+    return path;
+  s1 = path;
+  s2 = path;
+  while (*s1)
+    {
+      if (*s1 == '.' && s1[1] == '/')
+       { // remove .///
+         for (s1++; *s1; s1++)
+           if (*s1 != '/')
+             break;
+       }
+      else if (*s1 == '/')
+       { // replace /// with /
+         *(s2++) = *s1;
+         for (s1++; *s1; s1++)
+           if (*s1 != '/')
+             break;
+       }
+      else
+       {
+         while (*s1)
+           { // copy file or directory name
+             if (*s1 == '/')
+               break;
+             *(s2++) = *(s1++);
+           }
+       }
+    }
+  *s2 = 0;
+  if (s2 != path && (s2 - 1) != path && s2[-1] == '/')  // remove last /
+    *(s2 - 1) = 0;
+  return path;
+}
+
+char *
+get_relative_path (char *name)
+{
+  if (*name == '/' && theApplication)
+    {
+      char *cwd = theApplication->get_cur_dir ();
+      if (cwd)
+       {
+         size_t len = strlen (cwd);
+         if (len > 0 && len < strlen (name) && name[len] == '/'
+             && strncmp (cwd, name, len) == 0)
+           {
+             for (name += len + 1; *name == '/'; name++)
+               ;
+             return name;
+           }
+       }
+    }
+  return name;
+}
+
+/**
+ * Generate a relative link name from path_from to path_to
+ * Example:
+ * path_from=a/b/c/d
+ * path_to=a/b/e/f/g
+ * lname=../../e/f/g
+ * @param path_to
+ * @param path_from
+ * @return lname - relative link
+ */
+char *
+get_relative_link (const char *path_from, const char *path_to)
+{
+  if (!path_to)
+    path_to = ".";
+  if (!path_from)
+    path_from = ".";
+  char *s1 = dbe_strdup (path_to);
+  s1 = canonical_path (s1);
+  char *s2 = dbe_strdup (path_from);
+  s2 = canonical_path (s2);
+  long l = dbe_sstrlen (s1);
+  // try to find common directories
+  int common_slashes = 0;
+  int last_common_slash = -1;
+  for (int i = 0; i < l; i++)
+    {
+      if (s1[i] != s2[i]) break;
+      if (s1[i] == 0) break;
+      if (s1[i] == '/')
+       {
+         common_slashes++;
+         last_common_slash = i;
+       }
+    }
+  // find slashes in remaining path_to
+  int slashes = 0;
+  for (int i = last_common_slash + 1; i < l; i++)
+    {
+      if (s1[i] == '/')
+       {
+         // Exclude "/./" case
+         if (i > last_common_slash + 2)
+           {
+             if (s1[i - 1] == '.' && s1[i - 2] == '/')
+               continue;
+           }
+         else if (i > 0 && s1[i - 1] == '.')
+           continue;
+         slashes++;
+       }
+    }
+  // generate relative path
+  StringBuilder sb;
+  for (int i = 0; i < slashes; i++)
+    sb.append ("../");
+  sb.append (s2 + last_common_slash + 1);
+  char *lname = sb.toString ();
+  free (s1);
+  free (s2);
+  return lname;
+}
+
+char *
+get_prog_name (int basename)
+{
+  char *nm = NULL;
+  if (theApplication)
+    {
+      nm = theApplication->get_name ();
+      if (nm && basename)
+       nm = get_basename (nm);
+    }
+  return nm;
+}
+
+char *
+dbe_strndup (const char *str, size_t len)
+{
+  if (str == NULL)
+    return NULL;
+  char *s = (char *) malloc (len + 1);
+  strncpy (s, str, len);
+  s[len] = '\0';
+  return s;
+}
+
+char *
+dbe_sprintf (const char *fmt, ...)
+{
+  char buffer[256];
+  int buf_size;
+  va_list vp;
+
+  va_start (vp, fmt);
+  buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
+  va_end (vp);
+  if (buf_size < (int) sizeof (buffer))
+    {
+      if (buf_size <= 1)
+       buffer[0] = 0;
+      return strdup (buffer);
+    }
+
+  va_start (vp, fmt);
+  char *buf = (char *) malloc (buf_size);
+  vsnprintf (buf, buf_size, fmt, vp);
+  va_end (vp);
+  return buf;
+}
+
+ssize_t
+dbe_write (int f, const char *fmt, ...)
+{
+  char buffer[256];
+  int buf_size;
+  va_list vp;
+
+  va_start (vp, fmt);
+  buf_size = vsnprintf (buffer, sizeof (buffer), fmt, vp) + 1;
+  va_end (vp);
+  if (buf_size < (int) sizeof (buffer))
+    {
+      if (buf_size <= 1)
+       buffer[0] = 0;
+      return write (f, buffer, strlen (buffer));
+    }
+
+  va_start (vp, fmt);
+  char *buf = (char *) malloc (buf_size);
+  vsnprintf (buf, buf_size, fmt, vp);
+  va_end (vp);
+  ssize_t val = write (f, buf, strlen (buf));
+  free (buf);
+  return val;
+}
+
+/* Worker Threads to avoid hanging on file servers */
+
+/*
+ * Thread states
+ */
+enum
+{
+  THREAD_START,
+  THREAD_STARTED,
+  THREAD_CANCEL,
+  THREAD_CANCELED,
+  THREAD_CREATE,
+  THREAD_NOT_CREATED,
+  THREAD_FINISHED
+};
+
+/*
+ * Communication structure
+ */
+struct worker_thread_info
+{
+  pthread_t thread_id;      /* ID returned by pthread_create() */
+  int thread_num;           /* Application-defined thread # */
+  volatile int control;     /* Thread state */
+  volatile int result;      /* Return status */
+  struct stat64 statbuf;    /* File info from stat64() */
+  const char *path;         /* File */
+};
+
+static pthread_mutex_t worker_thread_lock = PTHREAD_MUTEX_INITIALIZER;
+static int worker_thread_number = 0;
+/**
+ * Call stat64() on current worker thread
+ * Check if control is not THREAD_CANCEL
+ * If control is THREAD_CANCEL return (exit thread)
+ * @param *wt_info
+ */
+static void *
+dbe_stat_on_thread (void *arg)
+{
+  struct worker_thread_info *wt_info = (struct worker_thread_info *) arg;
+  pthread_mutex_lock (&worker_thread_lock);
+  {
+    if (wt_info->control != THREAD_START)
+      {
+       // Already too late
+       pthread_mutex_unlock (&worker_thread_lock);
+       return 0;
+      }
+    wt_info->control = THREAD_STARTED;
+  }
+  pthread_mutex_unlock (&worker_thread_lock);
+  const char * path = wt_info->path;
+  int st = stat64 (path, &(wt_info->statbuf));
+  pthread_mutex_lock (&worker_thread_lock);
+  {
+    if (wt_info->control == THREAD_CANCEL)
+      {
+       // Too late.
+       pthread_mutex_unlock (&worker_thread_lock);
+       free (wt_info);
+       return 0;
+      }
+    wt_info->result = st;
+    wt_info->control = THREAD_FINISHED;
+  }
+  pthread_mutex_unlock (&worker_thread_lock);
+  return 0;
+}
+
+/**
+ * Create a worker thread to call specified function
+ * Wait for its result, but not longer than 5 seconds
+ * If the timeout happens, tell the thread to cancel
+ * @param path
+ * @param wt_info
+ * @return thread state
+ */
+static int
+dbe_dispatch_on_thread (const char *path, struct worker_thread_info *wt_info)
+{
+  wt_info->result = 0;
+  wt_info->control = THREAD_START;
+  pthread_attr_t attr;
+  /* Initialize thread creation attributes */
+  int res = pthread_attr_init (&attr);
+  if (res != 0)
+    {
+      wt_info->control = THREAD_NOT_CREATED;
+      return THREAD_NOT_CREATED;
+    }
+  wt_info->thread_id = 0;
+  wt_info->path = path;
+  // Lock
+  pthread_mutex_lock (&worker_thread_lock);
+  worker_thread_number++;
+  wt_info->thread_num = worker_thread_number;
+  // Unlock
+  pthread_mutex_unlock (&worker_thread_lock);
+  // Create thread
+  res = pthread_create (&wt_info->thread_id, &attr, &dbe_stat_on_thread, wt_info);
+  if (res != 0)
+    {
+      wt_info->control = THREAD_NOT_CREATED;
+      pthread_attr_destroy (&attr);
+      return THREAD_NOT_CREATED;
+    }
+  // Wait for the thread to finish
+  res = 0;
+  useconds_t maxusec = 5000000; // 5 seconds
+  useconds_t deltausec = 1000; // 1 millisecond
+  int max = maxusec / deltausec;
+  for (int i = 0; i < max; i++)
+    {
+      if (THREAD_FINISHED == wt_info->control)
+       break; // We are done
+      usleep (deltausec);
+    }
+  // Lock
+  pthread_mutex_lock (&worker_thread_lock);
+  if (THREAD_FINISHED != wt_info->control)
+    {
+      // Cancel thread
+      wt_info->control = THREAD_CANCEL; // Cannot use wt_info after that!
+      res = THREAD_CANCEL;
+    }
+  // Unlock
+  pthread_mutex_unlock (&worker_thread_lock);
+  // Destroy the thread attributes object, since it is no longer needed
+  pthread_attr_destroy (&attr);
+  // Report that thread was canceled
+  if (THREAD_CANCEL == res)
+    return res; /* Cannot free memory allocated by thread */
+  // Free all thread resources
+  void *resources = 0;
+  res = pthread_join (wt_info->thread_id, &resources);
+  free (resources); /* Free memory allocated by thread */
+  return THREAD_FINISHED;
+}
+
+static pthread_mutex_t dirnames_lock = PTHREAD_MUTEX_INITIALIZER;
+static Map<const char*, int> *dirnamesMap = NULL;
+
+#define DIR_STATUS_EXISTS 0
+#define DIR_STATUS_UNKNOWN 2
+
+/**
+ * Check if this directory name is known
+ * Return:
+ * @param path
+ *  0 - known, exists
+ *  1 - known, does not exist
+ *  2 - not known
+ */
+static int
+check_dirname (const char *path)
+{
+  pthread_mutex_lock (&dirnames_lock);
+  if (NULL == dirnamesMap)
+    dirnamesMap = new StringMap<int>(128, 128);
+  pthread_mutex_unlock (&dirnames_lock);
+  int res = DIR_STATUS_UNKNOWN;
+  if (path && *path)
+    {
+      char *fn = dbe_strdup (path);
+      char *dn = dirname (fn);
+      if (dn && *dn)
+       res = dirnamesMap->get (dn);
+      free (fn);
+    }
+  return res;
+}
+
+/**
+ * Save directory name and its status
+ * @param path
+ * @param status
+ * @return
+ */
+static void
+extract_and_save_dirname (const char *path, int status)
+{
+  pthread_mutex_lock (&dirnames_lock);
+  if (NULL == dirnamesMap)
+    dirnamesMap = new StringMap<int>(128, 128);
+  pthread_mutex_unlock (&dirnames_lock);
+  char *fn = dbe_strdup (path);
+  if (fn && *fn != 0)
+    {
+      char *dn = dirname (fn);
+      if (dn && (*dn != 0))
+       {
+         int st = 0; // exists
+         if (0 != status)
+           st = 1; // does not exist
+         dirnamesMap->put (dn, st);
+       }
+    }
+  free (fn);
+}
+
+// get status for specified file
+static int
+dbe_stat_internal (const char *path, struct stat64 *sbuf, bool file_only)
+{
+  struct stat64 statbuf;
+  int dir_status = check_dirname (path);
+  if (dir_status == DIR_STATUS_UNKNOWN)
+    {
+      // Try to use a worker thread
+      if (theApplication->get_number_of_worker_threads () > 0)
+       {
+         struct worker_thread_info *wt_info;
+         wt_info = (worker_thread_info *) calloc (1, sizeof (worker_thread_info));
+         if (wt_info != NULL)
+           {
+             int res = dbe_dispatch_on_thread (path, wt_info);
+             if (THREAD_FINISHED == res)
+               {
+                 int st = wt_info->result;
+                 extract_and_save_dirname (path, st);
+                 if (st == 0 && file_only)
+                   if (S_ISREG ((wt_info->statbuf).st_mode) == 0)
+                     st = -1; // It is not a regular file
+                 if (sbuf != NULL)
+                   *sbuf = wt_info->statbuf;
+                 free (wt_info);
+                 return st;
+               }
+             else
+               {
+                 if (THREAD_CANCEL == res)
+                   {
+                     // Worker thread hung. Cannot free wt_info.
+                     // Allocated memory will be freed by worker thread.
+                     // save directory
+                     extract_and_save_dirname (path, 1);
+                     return 1; // stat64 failed
+                   }
+                 else  // THREAD_NOT_CREATED - continue on current thread
+                   free (wt_info);
+               }
+           }
+       }
+    }
+  else if (dir_status != DIR_STATUS_EXISTS)
+    return -1; // does not exist
+  if (sbuf == NULL)
+    sbuf = &statbuf;
+  int st = stat64 (path, sbuf);
+  Dprintf (DEBUG_DBE_FILE, NTXT ("dbe_stat %d '%s'\n"), st, path);
+  if (st == -1)
+    return -1;
+  else if (file_only && S_ISREG (sbuf->st_mode) == 0)
+    return -1; // It is not ordinary file
+  return st;
+}
+
+// get status for the regular file
+
+int
+dbe_stat_file (const char *path, struct stat64 *sbuf)
+{
+  int res = dbe_stat_internal (path, sbuf, true);
+  return res;
+}
+
+// get status for specified file
+
+int
+dbe_stat (const char *path, struct stat64 *sbuf)
+{
+  int res = dbe_stat_internal (path, sbuf, false);
+  return res;
+}
+
+/**
+ * Reads directory and prepares list of files according to the specified format
+ * Supported formats:
+ * "/bin/ls -a" - see 'man ls' for details
+ * "/bin/ls -aF" - see 'man ls' for details
+ * @param path
+ * @param format
+ * @return char * files
+ */
+char *
+dbe_read_dir (const char *path, const char *format)
+{
+  StringBuilder sb;
+  DIR *dir = opendir (path);
+  if (dir == NULL)
+    return sb.toString ();
+  int format_aF = 0;
+  if (!strcmp (format, NTXT ("/bin/ls -aF")))
+    format_aF = 1;
+  struct dirent *entry = NULL;
+  if (format != NULL)
+    {
+      while ((entry = readdir (dir)) != NULL)
+       {
+         sb.append (entry->d_name);
+         if (format_aF)
+           {
+             const char *attr = NTXT ("@"); // Link
+             struct stat64 sbuf;
+             sbuf.st_mode = 0;
+             char filename[MAXPATHLEN + 1];
+             snprintf (filename, sizeof (filename), NTXT ("%s/%s"), path, entry->d_name);
+             dbe_stat (filename, &sbuf);
+             if (S_IREAD & sbuf.st_mode)
+               { // Readable
+                 if (S_ISDIR (sbuf.st_mode) != 0)  // Directory
+                   attr = NTXT ("/");
+                 else if (S_ISREG (sbuf.st_mode) != 0) // Regular file
+                   attr = NTXT ("");
+               }
+             sb.append (attr);
+           }
+         sb.append (NTXT ("\n"));
+       }
+    }
+  closedir (dir);
+  return sb.toString ();
+}
+
+/**
+ * Gets list of processes according to the specified format
+ * Supported formats:
+ * "/bin/ps -ef" - see 'man ps' for details
+ * @param format
+ * @return char * processes
+ */
+char *
+dbe_get_processes (const char *format)
+{
+  StringBuilder sb;
+  if (!strcmp (format, NTXT ("/bin/ps -ef")))
+    {
+      char buf[BUFSIZ];
+      FILE *ptr = popen (format, "r");
+      if (ptr != NULL)
+       {
+         while (fgets (buf, BUFSIZ, ptr) != NULL)
+           sb.append (buf);
+         pclose (ptr);
+       }
+    }
+  return sb.toString ();
+}
+
+/**
+ * Creates the directory named by the specified path name, including any
+ * necessary but nonexistent parent directories.
+ * Uses system utility "/bin/mkdir -p"
+ * Temporary limitation: path name should not contain spaces.
+ * Returns message from "/bin/mkdir -p"
+ * @param pathname
+ * @return result
+ */
+char *
+dbe_create_directories (const char *pathname)
+{
+  StringBuilder sb;
+  char *makedir = dbe_sprintf (NTXT ("/bin/mkdir -p %s 2>&1"), pathname);
+  char out[BUFSIZ];
+  FILE *ptr = popen (makedir, "r");
+  if (ptr != NULL)
+    {
+      while (fgets (out, BUFSIZ, ptr) != NULL)
+       sb.append (out);
+      pclose (ptr);
+    }
+  free (makedir);
+  DIR *dir = opendir (pathname);
+  if (dir != NULL)
+    {
+      closedir (dir);
+      return NULL; // success
+    }
+  else
+    sb.append (NTXT ("\nError: Cannot open directory\n")); // DEBUG
+  return sb.toString (); // error
+}
+
+/**
+ * Deletes the file or the directory named by the specified path name.
+ * If this pathname denotes a directory, then the directory must be empty in order to be deleted.
+ * Uses system utility "/bin/rm" or "/bin/rmdir"
+ * Temporary limitation: path name should not contain spaces.
+ * Returns error message from system utility
+ * @param pathname
+ * @return result
+ */
+char *
+dbe_delete_file (const char *pathname)
+{
+  StringBuilder sb;
+  char *cmd = NULL;
+  struct stat64 sbuf;
+  sbuf.st_mode = 0;
+  int st = dbe_stat (pathname, &sbuf);
+  if (st == 0)
+    { // Exists
+      if (S_ISDIR (sbuf.st_mode) != 0)      // Directory
+       cmd = dbe_sprintf (NTXT ("/bin/rmdir %s 2>&1"), pathname);
+      else if (S_ISREG (sbuf.st_mode) != 0)     // Regular file
+       cmd = dbe_sprintf (NTXT ("/bin/rm %s 2>&1"), pathname);
+    }
+  else
+    return NULL; // Nothing to remove
+  if (cmd != NULL)
+    {
+      char out[BUFSIZ];
+      FILE *ptr = popen (cmd, "r");
+      if (ptr != NULL)
+       {
+         while (fgets (out, BUFSIZ, ptr) != NULL)
+           sb.append (out);
+         pclose (ptr);
+       }
+      free (cmd);
+    }
+  else
+    sb.sprintf (NTXT ("Error: cannot remove %s - not a regular file and not a directory\n"), pathname);
+  return sb.toString ();
+}
+
+char *
+dbe_xml2str (const char *s)
+{
+  if (s == NULL)
+    return NULL;
+  StringBuilder sb;
+  while (*s)
+    {
+      if (*s == '&')
+       {
+         if (strncmp (s, NTXT ("&nbsp;"), 6) == 0)
+           {
+             sb.append (' ');
+             s += 6;
+             continue;
+           }
+         else if (strncmp (s, NTXT ("&quot;"), 6) == 0)
+           {
+             sb.append ('"');
+             s += 6;
+             continue;
+           }
+         else if (strncmp (s, NTXT ("&amp;"), 5) == 0)
+           {
+             sb.append ('&');
+             s += 5;
+             continue;
+           }
+         else if (strncmp (s, NTXT ("&lt;"), 4) == 0)
+           {
+             sb.append ('<');
+             s += 4;
+             continue;
+           }
+         else if (strncmp (s, NTXT ("&gt;"), 4) == 0)
+           {
+             sb.append ('>');
+             s += 4;
+             continue;
+           }
+       }
+      sb.append (*s);
+      s++;
+    }
+  return sb.toString ();
+}
+
+void
+swapByteOrder (void *p, size_t sz)
+{
+  if (sz == 8)
+    {
+      uint64_t *pv = (uint64_t *) p;
+      uint64_t v = *pv;
+      v = ((v & 0x00000000FF000000) << 8) | ((v >> 8) & 0x00000000FF000000) |
+             ((v & 0x0000000000FF0000) << 24) | ((v >> 24) & 0x0000000000FF0000) |
+             ((v & 0x000000000000FF00) << 40) | ((v >> 40) & 0x000000000000FF00) |
+             (v >> 56) | (v << 56);
+      *pv = v;
+    }
+  else if (sz == 4)
+    {
+      uint32_t *pv = (uint32_t *) p;
+      uint32_t v = *pv;
+      v = (v >> 24) | (v << 24) | ((v & 0x0000FF00) << 8) | ((v >> 8) & 0x0000FF00);
+      *pv = v;
+    }
+  else if (sz == 2)
+    {
+      uint16_t *pv = (uint16_t *) p;
+      uint16_t v = *pv;
+      v = (v >> 8) | (v << 8);
+      *pv = v;
+    }
+}
+
+void
+destroy (void *vec)
+{
+  if (vec == NULL)
+    return;
+  Vector<void*> *array = (Vector<void*>*)vec;
+  switch (array->type ())
+    {
+    case VEC_STRING:
+      ((Vector<char *>*)array)->destroy ();
+      break;
+    case VEC_VOIDARR:
+    case VEC_STRINGARR:
+    case VEC_INTARR:
+    case VEC_BOOLARR:
+    case VEC_LLONGARR:
+    case VEC_DOUBLEARR:
+      for (long i = 0; i < array->size (); i++)
+       destroy (array->fetch (i));
+      break;
+    case VEC_INTEGER:
+    case VEC_CHAR:
+    case VEC_BOOL:
+    case VEC_DOUBLE:
+    case VEC_LLONG:
+    default:
+      break;
+    }
+  delete array;
+}
+
+int64_t
+read_from_file (int fd, void *buffer, int64_t nbyte)
+{
+  int64_t cnt = 0;
+  char *buf = (char *) buffer;
+  while (nbyte > 0)
+    { // Sometimes system cannot read 'nbyte'
+      ssize_t n = read (fd, (void *) (buf + cnt), (size_t) nbyte);
+      if (n <= 0)
+       break;
+      nbyte -= n;
+      cnt += n;
+    }
+  return cnt;
+}
+
+/**
+ * Create symbolic link to the path
+ * @param  path - path with spaces
+ * @param  dir  - directory where the link should be created
+ * @return symbolic link
+ */
+char *
+dbe_create_symlink_to_path (const char *path, const char *dir)
+{
+  char *symbolic_link = NULL;
+  if (NULL == path || NULL == dir)
+    return NULL;
+  int res = mkdir (dir, 0777);
+  if (res != 0 && dbe_stat (dir, NULL) != 0)
+    return NULL; // Cannot create directory
+  long len = dbe_sstrlen (path);
+  if (len <= 4)
+    return NULL; // Unknown situation
+  if (strcmp ((path + len - 4), "/bin") != 0)   // Unknown situation
+    return NULL;
+  int max = 99; // Just an arbitrary number
+  for (int i = 1; i <= max; i++)
+    {
+      // Try to create symbolic link
+      char *d = dbe_sprintf ("%s/%d", dir, i);
+      if (NULL == d)
+       return NULL;
+      res = mkdir (d, 0777);
+      symbolic_link = dbe_sprintf ("%s/%s", d, "bin");
+      free (d);
+      if (NULL == symbolic_link) // Not enough memory
+       return NULL;
+      res = symlink (path, symbolic_link);
+      if (res == 0)     // Link is created - use it.
+       break;
+      // Check if such link already exists
+      int e = errno;
+      char buf[MAXPATHLEN + 1];
+      memset (buf, 0, MAXPATHLEN + 1);
+      ssize_t n = readlink (symbolic_link, buf, MAXPATHLEN);
+      if (n == len && strcmp (path, buf) == 0) // Link is correct - use it.
+       break;
+      if (i == max)
+       { // report the error
+         fprintf (stderr, GTXT ("Error: symlink(%s, %s) returned error: %d\n"), path, symbolic_link, res);
+         fprintf (stderr, GTXT ("Error: errno=%d (%s)\n"), e, strerror (e));
+         fflush (stderr);
+       }
+      free (symbolic_link);
+      symbolic_link = NULL;
+    }
+  return symbolic_link;
+}
+
+// Compute checksum for specified file.
+// This code is from usr/src/cmd/cksum.c, adapted for us
+// crcposix -- compute posix.2 compatable 32 bit CRC
+//
+// The POSIX.2 (draft 10) CRC algorithm.
+// This is a 32 bit CRC with polynomial
+//      x**32 + x**26 + x**23 + x**22 + x**16 + x**12 + x**11 + x**10 +
+//      x**8  + x**7  + x**5  + x**4  + x**2  + x**1  + x**0
+//
+// layout is from the POSIX.2 Rationale
+
+static uint32_t crctab_posix[256] = {
+  0x00000000L,
+  0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L, 0x130476DCL, 0x17C56B6BL,
+  0x1A864DB2L, 0x1E475005L, 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L,
+  0x2B4BCB61L, 0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL,
+  0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L, 0x5F15ADACL,
+  0x5BD4B01BL, 0x569796C2L, 0x52568B75L, 0x6A1936C8L, 0x6ED82B7FL,
+  0x639B0DA6L, 0x675A1011L, 0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL,
+  0x745E66CDL, 0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L,
+  0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L, 0xBE2B5B58L,
+  0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L, 0xAD2F2D84L, 0xA9EE3033L,
+  0xA4AD16EAL, 0xA06C0B5DL, 0xD4326D90L, 0xD0F37027L, 0xDDB056FEL,
+  0xD9714B49L, 0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L,
+  0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L, 0xE13EF6F4L,
+  0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL, 0x34867077L, 0x30476DC0L,
+  0x3D044B19L, 0x39C556AEL, 0x278206ABL, 0x23431B1CL, 0x2E003DC5L,
+  0x2AC12072L, 0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L,
+  0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL, 0x7897AB07L,
+  0x7C56B6B0L, 0x71159069L, 0x75D48DDEL, 0x6B93DDDBL, 0x6F52C06CL,
+  0x6211E6B5L, 0x66D0FB02L, 0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L,
+  0x53DC6066L, 0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL,
+  0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL, 0xBFA1B04BL,
+  0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L, 0x8AAD2B2FL, 0x8E6C3698L,
+  0x832F1041L, 0x87EE0DF6L, 0x99A95DF3L, 0x9D684044L, 0x902B669DL,
+  0x94EA7B2AL, 0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL,
+  0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L, 0xC6BCF05FL,
+  0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L, 0xD5B88683L, 0xD1799B34L,
+  0xDC3ABDEDL, 0xD8FBA05AL, 0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L,
+  0x644FC637L, 0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL,
+  0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL, 0x5C007B8AL,
+  0x58C1663DL, 0x558240E4L, 0x51435D53L, 0x251D3B9EL, 0x21DC2629L,
+  0x2C9F00F0L, 0x285E1D47L, 0x36194D42L, 0x32D850F5L, 0x3F9B762CL,
+  0x3B5A6B9BL, 0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL,
+  0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L, 0xF12F560EL,
+  0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L, 0xE22B20D2L, 0xE6EA3D65L,
+  0xEBA91BBCL, 0xEF68060BL, 0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L,
+  0xDA649D6FL, 0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L,
+  0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L, 0xAE3AFBA2L,
+  0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL, 0x9B3660C6L, 0x9FF77D71L,
+  0x92B45BA8L, 0x9675461FL, 0x8832161AL, 0x8CF30BADL, 0x81B02D74L,
+  0x857130C3L, 0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L,
+  0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL, 0x7B827D21L,
+  0x7F436096L, 0x7200464FL, 0x76C15BF8L, 0x68860BFDL, 0x6C47164AL,
+  0x61043093L, 0x65C52D24L, 0x119B4BE9L, 0x155A565EL, 0x18197087L,
+  0x1CD86D30L, 0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL,
+  0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L, 0x2497D08DL,
+  0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L, 0xC5A92679L, 0xC1683BCEL,
+  0xCC2B1D17L, 0xC8EA00A0L, 0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL,
+  0xDBEE767CL, 0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L,
+  0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L, 0x89B8FD09L,
+  0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L, 0x9ABC8BD5L, 0x9E7D9662L,
+  0x933EB0BBL, 0x97FFAD0CL, 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL,
+  0xA2F33668L, 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L
+};
+
+static void
+m_crcposix (uint32_t *crcp, unsigned char *bp, uint32_t n)
+{
+  while (n-- > 0)
+    *crcp = (*crcp << 8) ^ crctab_posix[(unsigned char) ((*crcp >> 24)^*bp++)];
+}
+
+// Do CRC-POSIX function by calling a library entry point that has a
+// slightly different calling sequence.
+static uint32_t
+docrcposix (uint32_t crcval, unsigned char *bp, uint32_t n)
+{
+  m_crcposix (&crcval, bp, n);
+  return (crcval);
+}
+
+// Sum algorithms require various kinds of post-processing.
+// The 'S' and 'R' variables are from the POSIX.2 (Draft 8?) description
+// of the "sum" utility.
+static uint32_t
+postprocess (uint32_t S, long long n)
+{
+  // POSIX tacks on significant bytes of the length so that
+  // different length sequences of '\0' have different sums;
+  // then it complements sum.
+  unsigned char char_n[sizeof (n)];
+  uint32_t i;
+  for (i = 0; n != 0; n >>= 8, ++i)
+    char_n[i] = (unsigned char) (n & 0xFF);
+  return (~docrcposix (S, char_n, i));
+}
+
+uint32_t
+get_cksum (const char * pathname, char ** errmsg)
+{
+  int fd = open (pathname, O_RDONLY);
+  if (fd < 0)
+    {
+      if (errmsg)
+       *errmsg = dbe_sprintf (GTXT ("*** Warning: Error opening file for reading: %s"), pathname);
+      return 0; // error
+    }
+  uint32_t crcval = 0;
+  long long bytes = 0;
+  int64_t n;
+  unsigned char buf[4096];
+  while ((n = read_from_file (fd, (char *) buf, sizeof (buf))) > 0)
+    {
+      bytes += n;
+      crcval = docrcposix (crcval, buf, n);
+    }
+  close (fd);
+  crcval = postprocess (crcval, bytes);
+  return crcval;
+}
diff --git a/gprofng/src/util.h b/gprofng/src/util.h
new file mode 100644 (file)
index 0000000..0d1b8bc
--- /dev/null
@@ -0,0 +1,185 @@
+/* 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 _PERFAN_UTIL_H
+#define _PERFAN_UTIL_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <stdint.h>
+
+#include "gp-defs.h"
+#include "gp-time.h"
+#include "i18n.h"
+#include "debug.h"
+
+#define SWAP_ENDIAN(x)  swapByteOrder((void *) (&(x)), sizeof(x))
+#define AppendString(len, arr, ...) len += snprintf(arr + len, sizeof(arr) - len, __VA_ARGS__)
+#define ARR_SIZE(x)     (sizeof (x) / sizeof (*(x)))
+
+// Utility routines.
+
+//
+// Inline functions
+//
+// max(a, b) - Return the maximum of two values
+inline int
+max (int a, int b)
+{
+  return (a >= b) ? a : b;
+}
+
+// min(a, b) - Return the minimum of two values
+inline int
+min (int a, int b)
+{
+  return (a <= b) ? a : b;
+}
+
+// streq(s1, s2) - Returns 1 if strings are the same, 0 otherwise
+inline int
+streq (const char *s1, const char *s2)
+{
+  return strcmp (s1, s2) == 0;
+}
+
+// StrChr(str, ch) - Rerurn 'str' if 'ch' does not occur in 'str' or
+// a pointer to the next symbol after the first occurrence of 'ch' in 'str'
+inline char *
+StrChr (char *str, char ch)
+{
+  char *s = strchr (str, ch);
+  return s ? (s + 1) : str;
+}
+
+// StrRchr(str, ch) - Rerurn 'str' if 'ch' does not occur in 'str' or
+// a pointer to the next symbol after the last occurrence of 'ch' in 'str'
+inline char *
+StrRchr (char *str, char ch)
+{
+  char *s = strrchr (str, ch);
+  return s ? (s + 1) : str;
+}
+
+inline char*
+STR (const char *s)
+{
+  return s ? (char*) s : (char*) NTXT ("NULL");
+}
+
+inline char*
+get_str (const char *s, const char *s1)
+{
+  return s ? (char*) s : (char*) s1;
+}
+
+inline char *
+get_basename (const char* name)
+{
+  return StrRchr ((char*) name, '/');
+}
+
+inline char *
+dbe_strdup (const char *str)
+{
+  return str ? strdup (str) : NULL;
+}
+
+inline long
+dbe_sstrlen (const char *str)
+{
+  return str ? (long) strlen (str) : 0;
+}
+
+inline int
+dbe_strcmp (const char *s1, const char *s2)
+{
+  return s1 ? (s2 ? strcmp (s1, s2) : 1) : (s2 ? -1 : 0);
+}
+
+// tstodouble(t) - Return timestruc_t in (double) seconds
+inline double
+tstodouble (timestruc_t t)
+{
+  return (double) t.tv_sec + (double) (t.tv_nsec / 1000000000.0);
+}
+
+inline void
+hr2timestruc (timestruc_t *d, hrtime_t s)
+{
+  d->tv_sec = (long) (s / NANOSEC);
+  d->tv_nsec = (long) (s % NANOSEC);
+}
+
+inline hrtime_t
+timestruc2hr (timestruc_t *s)
+{
+  return (hrtime_t) s->tv_sec * NANOSEC + (hrtime_t) s->tv_nsec;
+}
+
+struct stat64;
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+  //
+  // Declaration of utility functions
+  //
+  void tsadd (timestruc_t *result, timestruc_t *time);
+  void tssub (timestruc_t *result, timestruc_t *time1, timestruc_t *time2);
+  int tscmp (timestruc_t *time1, timestruc_t *time2);
+  void int_max (int *maximum, int count);
+  char *strstr_r (char *s1, const char *s2);
+  char *strrpbrk (const char *string, const char *brkset);
+  char *read_line (FILE *);
+  char *parse_qstring (char *in_str, char **endptr);
+  char *parse_fname (char *in_str, char **fcontext);
+  int get_paren (const char *name);
+
+  uint64_t crc64 (const char *str, size_t len);
+  char *canonical_path (char *path);
+  char *get_relative_path (char *name);
+  char *get_relative_link (const char *path_to, const char *path_from);
+  char *get_prog_name (int basename);
+  char *dbe_strndup (const char *str, size_t len);
+  int dbe_stat (const char *path, struct stat64 *sbuf);
+  int dbe_stat_file (const char *path, struct stat64 *sbuf);
+  char *dbe_read_dir (const char *path, const char *format);
+  char *dbe_get_processes (const char *format);
+  char *dbe_create_directories (const char *pathname);
+  char *dbe_delete_file (const char *pathname);
+  char *dbe_xml2str (const char *s);
+  void swapByteOrder (void *p, size_t sz);
+  char *dbe_sprintf (const char *fmt, ...) __attribute__ ((format (printf, 1, 2)));
+  ssize_t dbe_write (int f, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+  char *dbe_create_symlink_to_path (const char *path, const char *dir);
+  int64_t read_from_file (int fd, void *buffer, int64_t nbyte);
+  uint32_t get_cksum (const char * pathname, char ** errmsg);
+
+#ifdef  __cplusplus
+}
+int catch_out_of_memory (int (*real_main)(int, char*[]), int argc, char *argv[]);
+#endif
+
+
+#endif /* _UTIL_H */
diff --git a/gprofng/src/vec.h b/gprofng/src/vec.h
new file mode 100644 (file)
index 0000000..28b1800
--- /dev/null
@@ -0,0 +1,524 @@
+/* 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 _PERFAN_VEC_H
+#define _PERFAN_VEC_H
+
+#include <assert.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+
+// This package implements a vector of items.
+
+#define Destroy(x)      if (x) { (x)->destroy(); delete (x); (x) = NULL; }
+#define VecSize(x)      ((x) ? (x)->size() : 0)
+
+void destroy (void *vec); // Free up the "two-dimension" Vectors
+
+typedef int (*CompareFunc)(const void*, const void*);
+typedef int (*ExtCompareFunc)(const void*, const void*, const void*);
+typedef int (*SearchFunc)(char*, char*);
+
+extern "C"
+{
+  typedef int (*StdCompareFunc)(const void*, const void*);
+}
+
+enum Search_type
+{
+  LINEAR,
+  BINARY,
+  HASH
+};
+
+enum Direction
+{
+  FORWARD,
+  REVERSE
+};
+
+enum VecType
+{
+  VEC_VOID = 0,
+  VEC_INTEGER,
+  VEC_CHAR,
+  VEC_BOOL,
+  VEC_DOUBLE,
+  VEC_LLONG,
+  VEC_VOIDARR,
+  VEC_STRING,
+  VEC_INTARR,
+  VEC_BOOLARR,
+  VEC_LLONGARR,
+  VEC_STRINGARR,
+  VEC_DOUBLEARR
+};
+
+template <class ITEM> void
+qsort (ITEM *, size_t, ExtCompareFunc, void *);
+
+template <typename ITEM> class Vector
+{
+public:
+
+  Vector ()
+  {
+    count = 0;
+    data = NULL;
+    limit = 0;
+    sorted = false;
+  };
+
+  Vector (long sz);
+
+  virtual
+  ~Vector ()
+  {
+    free (data);
+  }
+
+  void append (const ITEM item);
+  void addAll (Vector<ITEM> *vec);
+  Vector<ITEM> *copy ();        // Return a copy of "this".
+
+  ITEM
+  fetch (long index)
+  {
+    return data[index];
+  }
+
+  ITEM
+  get (long index)
+  {
+    return data[index];
+  }
+
+  // Return the first index in "this" that equals "item".
+  // Return -1 if "item" is not found.
+  long find (const ITEM item);
+  long find_r (const ITEM item);
+
+  // Insert "item" into "index"'th slot of "this",
+  // moving everything over by 1.
+  void insert (long index, const ITEM item);
+
+  // Insert "item" after locating its appropriate index
+  void incorporate (const ITEM item, CompareFunc func);
+
+  // Remove and return the "index"'th item from "this",
+  // moving everything over by 1.
+  ITEM remove (long index);
+
+  // Swap two items in "this",
+  void swap (long index1, long index2);
+
+  long
+  size ()
+  {
+    return count;
+  }
+
+  // Store "item" into the "index"'th slot of "this".
+  void store (long index, const ITEM item);
+
+  void
+  put (long index, const ITEM item)
+  {
+    store (index, item);
+  }
+
+  // Sort the vector according to compare
+  void
+  sort (CompareFunc compare, void *arg = NULL)
+  {
+    qsort (data, count, (ExtCompareFunc) compare, arg);
+    sorted = true;
+  }
+
+  // Binary search, vector must be sorted
+  long bisearch (long start, long end, void *key, CompareFunc func);
+  void destroy ();      // delete all vector elements (must be pointers!)
+
+  void
+  reset ()
+  {
+    count = 0;
+    sorted = false;
+  }
+
+  bool
+  is_sorted ()
+  {
+    return sorted;
+  }
+
+  virtual VecType
+  type ()
+  {
+    return VEC_VOID;
+  }
+
+  virtual void
+  dump (const char * /* msg */)
+  {
+    return;
+  }
+
+private:
+
+  void resize (long index);
+
+  ITEM *data;   // Pointer to data vector
+  long count;   // Number of items
+  long limit;   // Vector length (power of 2)
+  bool sorted;
+};
+
+template<> VecType Vector<int>::type ();
+template<> VecType Vector<unsigned>::type ();
+template<> VecType Vector<char>::type ();
+template<> VecType Vector<bool>::type ();
+template<> VecType Vector<double>::type ();
+template<> VecType Vector<long long>::type ();
+template<> VecType Vector<uint64_t>::type ();
+template<> VecType Vector<void*>::type ();
+template<> VecType Vector<char*>::type ();
+template<> VecType Vector<Vector<int>*>::type ();
+template<> VecType Vector<Vector<char*>*>::type ();
+template<> VecType Vector<Vector<long long>*>::type ();
+template<> void Vector<char *>::destroy ();
+
+#define KILOCHUNK   1024
+#define MEGACHUNK   1024*1024
+#define GIGACHUNK   1024*1024*1024
+
+// A standard looping construct:
+#define Vec_loop(ITEM, vec, index, item) \
+if (vec != NULL) \
+    for (index = 0, item = ((vec)->size() > 0) ? (vec)->fetch(0) : (ITEM)0; \
+        index < (vec)->size(); \
+        item = (++index < (vec)->size()) ? (vec)->fetch(index) : (ITEM)0)
+
+template <typename ITEM>
+Vector<ITEM>::Vector (long sz)
+{
+  count = 0;
+  limit = sz > 0 ? sz : KILOCHUNK; // was 0;
+  data = limit ? (ITEM *) malloc (sizeof (ITEM) * limit) : NULL;
+  sorted = false;
+}
+
+template <typename ITEM> void
+Vector<ITEM>
+::resize (long index)
+{
+  if (index < limit)
+    return;
+  if (limit < 16)
+    limit = 16;
+  while (index >= limit)
+    {
+      if (limit > GIGACHUNK)
+       limit += GIGACHUNK; // Deoptimization for large experiments
+      else
+       limit = limit * 2;
+    }
+  data = (ITEM *) realloc (data, limit * sizeof (ITEM));
+}
+
+template <typename ITEM> void
+Vector<ITEM>::append (const ITEM item)
+{
+  // This routine will append "item" to the end of "this".
+  if (count >= limit)
+    resize (count);
+  data[count++] = item;
+}
+
+template <typename ITEM> void
+Vector<ITEM>::addAll (Vector<ITEM> *vec)
+{
+  if (vec)
+    for (int i = 0, sz = vec->size (); i < sz; i++)
+      append (vec->fetch (i));
+}
+
+template <typename ITEM> Vector<ITEM> *
+Vector<ITEM>::copy ()
+{
+  // This routine will return a copy of "this".
+  Vector<ITEM> *vector;
+  vector = new Vector<ITEM>;
+  vector->count = count;
+  vector->limit = limit;
+  vector->data = (ITEM *) malloc (sizeof (ITEM) * limit);
+  (void) memcpy ((char *) vector->data, (char *) data, sizeof (ITEM) * count);
+  return vector;
+}
+
+template <typename ITEM> long
+Vector<ITEM>::find (const ITEM match_item)
+{
+  for (long i = 0; i < size (); i++)
+    if (match_item == get (i))
+      return i;
+  return -1;
+}
+
+template <typename ITEM> long
+Vector<ITEM>::find_r (const ITEM match_item)
+{
+  for (long i = size () - 1; i >= 0; i--)
+    if (match_item == get (i))
+      return i;
+  return -1;
+}
+
+template <typename ITEM> void
+Vector<ITEM>::insert (long index, const ITEM item)
+{
+  // This routine will insert "item" into the "index"'th slot of "this".
+  // An error occurs if "index" > size().
+  // "index" is allowed to be equal to "count" in the case that
+  // you are inserting past the last element of the vector.
+  // In that case, the bcopy below becomes a no-op.
+  assert (index >= 0);
+  assert (index <= count);
+  append (item);
+  (void) memmove (((char *) (&data[index + 1])), (char *) (&data[index]),
+                 (count - index - 1) * sizeof (ITEM));
+  data[index] = item;
+}
+
+template <typename ITEM> ITEM
+Vector<ITEM>::remove (long index)
+{
+  // This routine will remove the "index"'th item from "this" and
+  // return it.  An error occurs if "index" >= size();.
+  assert (index >= 0);
+  assert (index < count);
+  ITEM item = data[index];
+  for (long i = index + 1; i < count; i++)
+    data[i - 1] = data[i];
+  count--;
+  // Bad code that works good when ITEM is a pointer type
+  data[count] = item;
+  return data[count];
+}
+
+template <typename ITEM> void
+Vector<ITEM>::swap (long index1, long index2)
+{
+  ITEM item;
+  item = data[index1];
+  data[index1] = data[index2];
+  data[index2] = item;
+}
+
+template <typename ITEM> void
+Vector<ITEM>::store (long index, const ITEM item)
+{
+  if (index >= count)
+    {
+      resize (index);
+      memset (&data[count], 0, (index - count) * sizeof (ITEM));
+      count = index + 1;
+    }
+  data[index] = item;
+}
+
+// This routine performs a binary search across
+// the entire vector, with "start" being the low boundary.
+// It is assumed that the vector is SORTED in
+// ASCENDING ORDER by the same criteria as the
+// compare function.
+// If no match is found, -1 is returned.
+template <typename ITEM> long
+Vector<ITEM>::bisearch (long start, long end, void *key, CompareFunc compare)
+{
+  ITEM *itemp;
+  if (end == -1)
+    end = count;
+  if (start >= end)
+    return -1; // start exceeds limit
+  itemp = (ITEM *) bsearch ((char *) key, (char *) &data[start],
+                         end - start, sizeof (ITEM), (StdCompareFunc) compare);
+  if (itemp == (ITEM *) 0)
+    return -1; // not found
+  return (long) (itemp - data);
+}
+
+template <typename ITEM> void
+Vector<ITEM>::incorporate (const ITEM item, CompareFunc compare)
+{
+  long lt = 0;
+  long rt = count - 1;
+  while (lt <= rt)
+    {
+      long md = (lt + rt) / 2;
+      if (compare (data[md], item) < 0)
+       lt = md + 1;
+      else
+       rt = md - 1;
+    }
+  if (lt == count)
+    append (item);
+  else
+    insert (lt, item);
+}
+
+#define QSTHRESH 6
+
+template <typename ITEM> void
+qsort (ITEM *base, size_t nelem, ExtCompareFunc qcmp, void *arg)
+{
+  for (;;)
+    {
+      // For small arrays use insertion sort
+      if (nelem < QSTHRESH)
+       {
+         for (size_t i = 1; i < nelem; i++)
+           {
+             ITEM *p = base + i;
+             ITEM *q = p - 1;
+             if (qcmp (q, p, arg) > 0)
+               {
+                 ITEM t = *p;
+                 *p = *q;
+                 while (q > base && qcmp (q - 1, &t, arg) > 0)
+                   {
+                     *q = *(q - 1);
+                     --q;
+                   }
+                 *q = t;
+               }
+           }
+         return;
+       }
+
+      ITEM *last = base + nelem - 1;
+      ITEM *mid = base + nelem / 2;
+      // Sort the first, middle, and last elements
+      ITEM *a1 = base, *a2, *a3;
+      if (qcmp (base, mid, arg) > 0)
+       {
+         if (qcmp (mid, last, arg) > 0)
+           { // l-m-b
+             a2 = last;
+             a3 = last;
+           }
+         else if (qcmp (base, last, arg) > 0)
+           { // l-b-m
+             a2 = mid;
+             a3 = last;
+           }
+         else
+           { // m-b-l
+             a2 = mid;
+             a3 = mid;
+           }
+       }
+      else if (qcmp (mid, last, arg) > 0)
+       {
+         a1 = mid;
+         a3 = last;
+         if (qcmp (base, last, arg) > 0)  // m-l-b
+           a2 = base;
+         else  // b-l-m
+           a2 = a3;
+       }
+      else // b-m-l
+       a3 = a2 = a1;
+      if (a1 != a2)
+       {
+         ITEM t = *a1;
+         *a1 = *a2;
+         if (a2 != a3)
+           *a2 = *a3;
+         *a3 = t;
+       }
+
+      // Partition
+      ITEM *i = base + 1;
+      ITEM *j = last - 1;
+      for (;;)
+       {
+         while (i < mid && qcmp (i, mid, arg) <= 0)
+           i++;
+         while (j > mid && qcmp (mid, j, arg) <= 0)
+           j--;
+         if (i == j)
+           break;
+         ITEM t = *i;
+         *i = *j;
+         *j = t;
+         if (i == mid)
+           {
+             mid = j;
+             i++;
+           }
+         else if (j == mid)
+           {
+             mid = i;
+             j--;
+           }
+         else
+           {
+             i++;
+             j--;
+           }
+       }
+
+      // Compare two partitions. Do the smaller one by recursion
+      // and loop over the larger one.
+      size_t nleft = mid - base;
+      size_t nright = nelem - nleft - 1;
+      if (nleft <= nright)
+       {
+         qsort (base, nleft, qcmp, arg);
+         base = mid + 1;
+         nelem = nright;
+       }
+      else
+       {
+         qsort (mid + 1, nright, qcmp, arg);
+         nelem = nleft;
+       }
+    }
+}
+
+template<> inline void
+Vector<char*>::destroy ()
+{
+  for (long i = 0; i < count; i++)
+    free (data[i]);
+  count = 0;
+}
+
+template <typename ITEM> inline void
+Vector<ITEM>::destroy ()
+{
+  for (long i = 0; i < count; i++)
+    delete data[i];
+  count = 0;
+}
+
+#endif /* _VEC_H */
diff --git a/gprofng/testsuite/config/default.exp b/gprofng/testsuite/config/default.exp
new file mode 100644 (file)
index 0000000..6fde0a1
--- /dev/null
@@ -0,0 +1,38 @@
+# Basic expect script for gprofng tests
+#   Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+# The "make check" target in the Makefile passes in
+# "CC=$(CC_FOR_TARGET)".  But, if the user invokes runtest directly,
+# these flags may not be set.
+if {![info exists CC]} {
+    set CC [find_gcc]
+}
+if {![info exists CC_FOR_TARGET]} {
+    set CC_FOR_TARGET $CC
+}
+if {![info exists CFLAGS]} {
+    set CFLAGS "-g -O2"
+}
+
+# Make a temporary install dir to run gprofng from, and point at it
+remote_exec host "sh -c \"rm -rf tmpdir; mkdir -p tmpdir; $MAKE -C .. install-gprofng program_transform_name= DESTDIR=`pwd`/tmpdir/root\""
+
+load_lib display-lib.exp
diff --git a/gprofng/testsuite/gprofng.display/display.exp b/gprofng/testsuite/gprofng.display/display.exp
new file mode 100644 (file)
index 0000000..108144c
--- /dev/null
@@ -0,0 +1,86 @@
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is part of the 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 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; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+#
+
+if {[info exists env(LC_ALL)]} {
+    set old_lc_all $env(LC_ALL)
+}
+set env(LC_ALL) "C"
+
+set pltf [exec uname -i]
+switch $pltf {
+  x86_64 {
+    # Columns in the table represent:
+    #   dir      cflags         gprofflags       Others
+    set table {
+      {"jsynprog" "-g -Wall"        "-p on -j on"}
+      {"mttest"   ""                ""}
+      {"mttest"   "-g -Wall"        "-p on"}
+      {"mttest"   "-g -O0"          "-p on"}
+      {"mttest"   "-g -O"           "-p on"}
+      {"mttest"   "-g -O"           "-h on"}
+      {"mttest"   "-g -O"           "-h on"}
+      {"mttest"   "-g -O"           "-p on -h on"}
+      {"synprog"  ""                ""}
+      {"synprog"  "-g"              "-p on"}
+      {"synprog"  "-g -O0"          "-p on"}
+      {"synprog"  "-g -O"           "-p on"}
+      {"synprog"  "-g"              "-p on -h on"}
+      {"synprog"  "-g -O0"          "-p on -h on"}
+      {"synprog"  "-g -O"           "-p on -h on"}
+    }
+  }
+  aarch64 {
+    set table {
+      {"jsynprog" "-g -Wall"        "-p on -j on"}
+      {"mttest"   ""                ""}
+      {"mttest"   "-g -Wall"        "-p on"}
+      {"mttest"   "-g -O0"          "-p on"}
+      {"mttest"   "-g -O"           "-p on"}
+      {"synprog"  ""                ""}
+      {"synprog"  "-g"              "-p on"}
+      {"synprog"  "-g -O"           "-p on"}
+    }
+  }
+  default {
+    # Columns in the table represent:
+    #   dir      cflags         gprofflags       Others
+    set table {
+      {"mttest"   ""              ""}
+      {"synprog"  ""              ""}
+    }
+  }
+}
+
+foreach line $table {
+  set dir [lindex $line 0]
+  set cflags [lindex $line 1]
+  set gprofflags [lindex $line 2]
+
+  verbose [file rootname $line]
+  verbose running display test $line
+  run_display_test $dir $cflags $gprofflags
+}
+    
+
+if {[info exists old_lc_all]} {
+    set env(LC_ALL) $old_lc_all
+} else {
+    unset env(LC_ALL)
+}
diff --git a/gprofng/testsuite/gprofng.display/jsynprog/Intface.java b/gprofng/testsuite/gprofng.display/jsynprog/Intface.java
new file mode 100644 (file)
index 0000000..016e7b2
--- /dev/null
@@ -0,0 +1,6 @@
+//   Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+
+public interface Intface {
+   public int add_int (int scale);
+   public double add_double (int scale);
+}
diff --git a/gprofng/testsuite/gprofng.display/jsynprog/Launcher.java b/gprofng/testsuite/gprofng.display/jsynprog/Launcher.java
new file mode 100644 (file)
index 0000000..33ee06c
--- /dev/null
@@ -0,0 +1,90 @@
+// Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+// @(#)Launcher.java 1.3 10/03/24 SMI
+
+import java.lang.reflect.*;
+
+public class Launcher {
+// Byte array for dynamically loaded class:            //
+//public class DynLoadedClass {                        //
+//   public int DynamicFunction(int x) {               //
+//      float f = 0;                                   //
+//      for (int k=0 ; k<20000; k++) {                 //
+//         f =  ((float)k) / x;                        //
+//      }                                              //
+//      return (int)f;                                 //
+//   }                                                 //
+//                                                     //
+//    public static void main(String[] args){          //
+//        DynLoadedClass dcls = new DynLoadedClass();  //
+//        for (int k=0 ; k<10; k++) {                  //
+//            dcls.DynamicFunction(k);                 //
+//        }                                            //
+//    }                                                //
+//}                                                    //
+static final byte [] bClassGenerated = {
+        -54, -2, -70, -66, 0, 0, 0, 46, 0, 20, 10, 0, 5, 0, 16, 7, 0, 17, 10, 0, 2, 0, 16, 10, 0, 2, 
+        0, 18, 7, 0, 19, 1, 0, 6, 60, 105, 110, 105, 116, 62, 1, 0, 3, 40, 41, 86, 1, 0, 4, 67, 111, 
+        100, 101, 1, 0, 15, 76, 105, 110, 101, 78, 117, 109, 98, 101, 114, 84, 97, 98, 108, 101, 1, 0, 15, 68, 121, 
+        110, 97, 109, 105, 99, 70, 117, 110, 99, 116, 105, 111, 110, 1, 0, 4, 40, 73, 41, 73, 1, 0, 4, 109, 97, 
+        105, 110, 1, 0, 22, 40, 91, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 
+        41, 86, 1, 0, 10, 83, 111, 117, 114, 99, 101, 70, 105, 108, 101, 1, 0, 19, 68, 121, 110, 76, 111, 97, 100, 
+        101, 100, 67, 108, 97, 115, 115, 46, 106, 97, 118, 97, 12, 0, 6, 0, 7, 1, 0, 14, 68, 121, 110, 76, 111, 
+        97, 100, 101, 100, 67, 108, 97, 115, 115, 12, 0, 10, 0, 11, 1, 0, 16, 106, 97, 118, 97, 47, 108, 97, 110, 
+        103, 47, 79, 98, 106, 101, 99, 116, 0, 33, 0, 2, 0, 5, 0, 0, 0, 0, 0, 3, 0, 1, 0, 6, 0, 
+        7, 0, 1, 0, 8, 0, 0, 0, 29, 0, 1, 0, 1, 0, 0, 0, 5, 42, -73, 0, 1, -79, 0, 0, 0, 
+        1, 0, 9, 0, 0, 0, 6, 0, 1, 0, 0, 0, 1, 0, 1, 0, 10, 0, 11, 0, 1, 0, 8, 0, 0, 
+        0, 66, 0, 2, 0, 4, 0, 0, 0, 26, 11, 69, 3, 62, 29, 17, 78, 32, -94, 0, 15, 29, -122, 27, -122, 
+        110, 69, -124, 3, 1, -89, -1, -16, 36, -117, -84, 0, 0, 0, 1, 0, 9, 0, 0, 0, 22, 0, 5, 0, 0, 
+        0, 3, 0, 2, 0, 4, 0, 11, 0, 5, 0, 17, 0, 4, 0, 23, 0, 7, 0, 9, 0, 12, 0, 13, 0, 
+        1, 0, 8, 0, 0, 0, 69, 0, 2, 0, 3, 0, 0, 0, 29, -69, 0, 2, 89, -73, 0, 3, 76, 3, 61, 
+        28, 16, 10, -94, 0, 15, 43, 28, -74, 0, 4, 87, -124, 2, 1, -89, -1, -15, -79, 0, 0, 0, 1, 0, 9, 
+        0, 0, 0, 22, 0, 5, 0, 0, 0, 11, 0, 8, 0, 12, 0, 16, 0, 13, 0, 22, 0, 12, 0, 28, 0, 
+        15, 0, 1, 0, 14, 0, 0, 0, 2, 0, 15
+    };
+    
+    private static DynClassLoader persistentInstance;
+    
+    public static DynClassLoader getPersistentInstance()
+    {
+        if (persistentInstance == null)
+            persistentInstance = new DynClassLoader();
+        return persistentInstance;
+    }  
+
+    public static void main(String args []) {
+        if (args.length != 1) {
+           System.err.println("Usage: Launcher DynLoadedClass");
+           return;
+       }
+
+        String className = args[0]; // Dynamic class name
+
+        try {
+            Class    genClass  = getPersistentInstance().getClassFromByteArray(className, bClassGenerated);
+            Method[] methods_g = genClass.getDeclaredMethods();
+
+            for (int i = 0; i < methods_g.length; i++) {
+                Method m = methods_g[i];
+                String methodName = m.getName();
+               String progArgs[] = new String[1];
+               //System.out.println("Invoking method " + className + "." + methodName);
+               if (methodName.equals("main"))
+                   m.invoke( null, (Object[]) progArgs );
+            }
+        } catch (InvocationTargetException iex) {
+            System.err.println("InvocationTargetException");
+        } catch (IllegalAccessException aex) {
+            System.err.println("IllegalAccessException");
+        }
+    }
+
+    // Class loader to generate dynamic class on the fly from the byte array
+    private static class DynClassLoader extends ClassLoader {
+        public DynClassLoader() { }
+        public Class getClassFromByteArray(String name, byte[] b) {
+            return super.defineClass(name, b, 0, b.length);
+        }
+    }
+
+
+}
diff --git a/gprofng/testsuite/gprofng.display/jsynprog/Makefile b/gprofng/testsuite/gprofng.display/jsynprog/Makefile
new file mode 100644 (file)
index 0000000..e78b692
--- /dev/null
@@ -0,0 +1,56 @@
+#   Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+TARGETS     = libcloop.so jsynprog.class
+TARGET      = jsynprog
+ACCT_FILE   = jsynprog.acct
+
+srcdir = .
+include $(srcdir)/../../lib/Makefile.skel
+
+JAVACFLAGS  =
+
+SRCS = \
+       $(srcdir)/../mttest/gethrtime.c \
+       $(srcdir)/cloop.cc \
+       $(NULL)
+
+JAVA_SRCS = \
+       $(srcdir)/Intface.java \
+       $(srcdir)/Routine.java \
+       $(srcdir)/Sub_Routine.java \
+       $(srcdir)/jsynprog.java \
+       $(srcdir)/Launcher.java \
+       $(NULL)
+
+HDRS = jsynprog.h
+
+libcloop.so: $(SRCS) 
+       @echo " ---- Build: $@ -----"
+       $(CC) $(jdk_inc) $(CCOPTS) $(SHAREDOPT) -o $@ $(SRCS)
+
+jsynprog.class: $(JAVA_SRCS)
+       @echo " ---- Build: $@ -----"
+       $(JAVAC) $(JAVACFLAGS) -d . $(JAVA_SRCS)
+
+$(EXPERIMENT): $(TARGETS)
+       @echo " ---- Build: $@ -----"
+       rm -rf $@ 
+       $(COLLECT) $(COLLECT_FLAGS) -o $@ $(JAVA) $(JAVACFLAGS) jsynprog
+
diff --git a/gprofng/testsuite/gprofng.display/jsynprog/Routine.java b/gprofng/testsuite/gprofng.display/jsynprog/Routine.java
new file mode 100644 (file)
index 0000000..cfe45d2
--- /dev/null
@@ -0,0 +1,224 @@
+/**
+ *   Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+ * This class implements the Intface interface
+ * increments value of integer and floats
+ */
+
+import java.util.*;
+
+public class Routine implements Intface {
+
+   /* add integers */
+   public int add_int (int scale) {
+       int     x = 0;
+       int kmax = 100*scale;
+       double tEnd = jsynprog.Timer() + jsynprog.testtime;
+       do { x = 0;
+       for (int k=0; k<kmax;k++) {
+          for (int j=0; j<10000;j++) {
+               x = x + 1;
+          }
+       }
+       } while (jsynprog.Timer() < tEnd);
+       return x;
+   }
+
+  /* add double */
+  public double add_double (int scale) {
+       double  y = 0.0;
+       int kmax = 1*scale;
+       double tEnd = jsynprog.Timer() + jsynprog.testtime;
+       do { y = 0.0;
+       for (int k=0; k<kmax;k++) {
+          for (int j=0; j<10000;j++) {
+               y = y + 1.0;
+          }
+       }
+       } while (jsynprog.Timer() < tEnd);
+       return y;
+   }
+
+  /* Use inner class */
+  public Integer[] has_inner_class(int scale) {
+       class JInner {
+           Integer[] g_int = new Integer[3];
+     
+           public Integer[] buildlist(int scale) {
+               double tEnd = jsynprog.Timer() + jsynprog.testtime;
+               do {
+               for (int k=0; k<g_int.length; k++) {
+                   int         x = 0;
+                   int imax = 10*scale;
+                   for (int i=0; i<imax;i++) {
+                       for (int j=0; j<10000;j++) {
+                           x = x + 1;
+                       }
+                   }
+                   g_int[k]=new Integer (x); 
+                } 
+                } while (jsynprog.Timer() < tEnd);
+                return g_int;
+           }
+       }
+       return ((new JInner()).buildlist(scale));
+  }
+
+  public void memalloc (int nsize, int scale) {
+       class myobj {
+           int nitem;
+           String shape;
+           String color;
+
+           myobj() { 
+                 nitem = 4;
+                 shape = "square";
+                 color = "blue";
+           }
+       }
+       for (int j=0; j<60; j++) {
+          for (int i=0; i<20; i++) {
+               myobj[] blueobj = new myobj[1000000]; 
+          }
+       }
+  } 
+
+  /* routine to do recursion */
+  public void recurse(int i, int imax, int scale) {
+     if(i == imax) {
+       double tEnd = jsynprog.Timer() + jsynprog.testtime;
+       do {
+           double x;
+           int j, k;
+           x = 0.0;
+           for(k=0; k<scale; k++) {
+                  for(j=0; j<5000000; j++) {
+                         x = x + 1.0;
+                  }
+           }
+       } while (jsynprog.Timer() < tEnd);
+     } else {
+           recurse(i+1, imax, scale);
+     }
+  }
+
+  /* routine to do deep recursion */
+  public void recursedeep(int i, int imax, int scale) {
+     if(i == imax) {
+         double tEnd = jsynprog.Timer() + jsynprog.testtime;
+         do {
+           double x;
+           int j, k;
+           x = 0.0;
+           for(k=0; k<scale; k++) {
+                  for(j=0; j<5000000; j++) {
+                         x = x + 1.0;
+                  }
+           }
+         } while (jsynprog.Timer() < tEnd);
+     } else {
+           recursedeep(i+1, imax, scale);
+     }
+  }
+
+
+  /* bounce -- example of indirect recursion */
+  public void bounce(int i, int imax, int scale) {
+       if(i == imax) {
+         double tEnd = jsynprog.Timer() + jsynprog.testtime;
+         do {
+            double x;
+            int j, k;
+               x = 0.0;
+               for(k=0; k < scale; k++) {
+                   for(j=0; j<5000000; j++) {
+                          x = x + 1.0;
+                   }
+               }
+         } while (jsynprog.Timer() < tEnd);
+       } else {
+               bounce_b(i, imax, scale);
+       }
+  }
+
+  private void bounce_b(int i, int imax, int scale) {
+       bounce(i+1, imax, scale);
+       return;
+  }
+
+
+  /* large array */ 
+  public void array_op(int scale) {
+       int size = 50000;
+       int imax = 1*scale;
+       Integer[] y = allocate_array(3*size);
+       Integer[] z = allocate_array(size);
+       double tEnd = jsynprog.Timer() + jsynprog.testtime;
+       do {
+       for (int i=0; i<imax; i++) {
+           System.arraycopy(y, 2, z, 0, size);
+       }
+       } while (jsynprog.Timer() < tEnd);
+  }   
+  
+  /* define large array */ 
+  private Integer[] allocate_array(int num) {
+       Integer[] x = new Integer[num];
+       for (int i=0; i<num;i++) {
+           x[i] = new Integer(i);
+       }
+       return x;
+  }   
+
+
+  /* large vector */
+  public void vector_op(int scale) {
+       Vector v = allocate_vector(); 
+       int imax = 1*scale;
+       int jmax = 1*scale;
+       double tEnd = jsynprog.Timer() + jsynprog.testtime;
+       do {
+       for (int i=0; i<imax; i++) {
+           vrem_last(v);
+       }
+       for (int j=0; j<jmax; j++) {
+           vrem_first(v);
+       }
+       } while (jsynprog.Timer() < tEnd);
+  }   
+
+  /* define large Vector */ 
+  private Vector allocate_vector() {
+       Vector<Integer> v1 = new Vector<Integer> (200000);
+       for (int i=0; i<1000000;i++) {
+           v1.add(new Integer(i)); 
+       }
+       return v1;
+  }
+  /* remove last element of vector */ 
+  private void vrem_last(Vector v) {
+       v.remove(v.size()-1);
+  }
+
+  /* remove first element of vector */ 
+  private void vrem_first(Vector v) {
+       v.remove(0);
+  }
+
+
+  /* Spend time in system calls */
+  public void sys_op(int scale) {
+       long stime ;
+       int jmax = 1000000;
+       int imax = 4;
+       double tEnd = jsynprog.Timer() + jsynprog.testtime;
+       do {
+       for (int i = 0; i < imax; i++) {
+           for(int j=0; j<jmax; j++) {
+                 stime = System.currentTimeMillis();
+           }
+       }
+       } while (jsynprog.Timer() < tEnd);
+  }
+
+} //end of class
diff --git a/gprofng/testsuite/gprofng.display/jsynprog/Sub_Routine.java b/gprofng/testsuite/gprofng.display/jsynprog/Sub_Routine.java
new file mode 100644 (file)
index 0000000..11e045e
--- /dev/null
@@ -0,0 +1,54 @@
+/* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+** @(#)Sub_Routine.java 1.4 10/03/24 SMI
+** This is subclass of Routine , overrides one method
+*/
+
+public class Sub_Routine extends Routine {
+    private static native double cTimer();
+
+   /*
+    ** Calls another method c() many times, overridden methos
+    */
+   public int add_int(int scale) {
+       int w = 0;
+       int kmax = 100*scale;
+        if (scale == 1) {
+           kmax /= 100;
+        }
+       double tEnd = jsynprog.Timer() + jsynprog.testtime;
+       do { w = 0;
+       for (int k=0 ; k<kmax; k++) {
+           w = addcall(w) + 1;
+       }
+       } while (jsynprog.Timer() < tEnd);
+       return w;
+   }
+
+   private static int addcall(int x) {
+       int jmax = 100;
+        int imax = 10;
+       for (int j=0; j<jmax;j++) {
+            for (int i=0; i<imax; i++) {
+               x = (i%2==0)?x:(x + 1);
+            }
+       }
+       return x;
+   }
+
+   public int naptime(int k, int scale)
+   {
+       int i;
+       int imax = k * scale;
+
+       try {
+           for (i = 0; i < imax; i++) {
+               System.out.println(i + " sleeping");
+               Thread.currentThread().sleep(10);
+               i=i+1;  
+           }
+       } catch (InterruptedException e) {e.printStackTrace();}
+       System.out.println("In naptime");
+       return 0;
+   }
+
+}
diff --git a/gprofng/testsuite/gprofng.display/jsynprog/check_results.pl b/gprofng/testsuite/gprofng.display/jsynprog/check_results.pl
new file mode 100755 (executable)
index 0000000..eac58a2
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/sh -- # This comment tells perl not to loop!
+
+#   Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+eval 'exec ${PERL:=/usr/dist/exe/perl} -S $0 ${1+"$@"}'
+if 0;
+
+use strict;
+require "acct.pm";
+
+my(@checkTime) = (1, 2);
+acct::readAcct($ARGV[0], @checkTime);
+acct::read_er_print_out($ARGV[1], -1);
+acct::createDiff();
+exit acct::set_retVal(0);
+
diff --git a/gprofng/testsuite/gprofng.display/jsynprog/cloop.cc b/gprofng/testsuite/gprofng.display/jsynprog/cloop.cc
new file mode 100644 (file)
index 0000000..cf8b779
--- /dev/null
@@ -0,0 +1,114 @@
+/*  
+ *      Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+#include <jni.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include "jsynprog.h"
+
+typedef long long       hrtime_t;
+extern "C" {
+    hrtime_t gethrtime();
+    hrtime_t gethrvtime();
+}
+static jdouble testtime = 3.0 * 1e9;
+
+int cfunc(int);
+
+JNIEXPORT jdouble JNICALL
+Java_jsynprog_Timer (JNIEnv *env, jclass obj)
+{
+    jdouble      jd;
+    hrtime_t     start;
+
+    start = gethrtime();
+    jd = (double)(start);
+    return jd;
+}
+
+JNIEXPORT jdouble JNICALL
+Java_jsynprog_cTimer (JNIEnv *env, jclass obj)
+{
+    jdouble      jd;
+    hrtime_t     vstart;
+
+    vstart = gethrvtime();
+    jd = (double)(vstart);
+    return jd;
+}
+
+JNIEXPORT jdouble JNICALL
+Java_jsynprog_computeSet (JNIEnv *env, jclass obj)
+{
+    char *s;
+
+    testtime = 3.0;
+    s = getenv("SP_COLLECTOR_TEST_TIMER");
+    if( s ) {
+        testtime = atof(s);
+        if (testtime < 1.0)
+            testtime = 1.0;
+    }
+    testtime *= 1e9;
+    return testtime;
+}
+
+JNIEXPORT jint JNICALL
+Java_jsynprog_JavaJavaC (JNIEnv *env, jclass obj, jint n, int scale )
+{
+    // fprintf(stderr, "Entering Java_jsynprog_JavaJavaC, scale = %d\n", scale);
+    int imax = 100000;
+    n = 0;
+    for (int i =0; i<imax; i++) {
+        n=n+((i%2==0)?1:2);
+    }
+    return n;
+}
+
+JNIEXPORT void JNICALL
+Java_jsynprog_JavaCC (JNIEnv *env, jclass obj, int scale)
+{
+    fprintf(stderr, "Entering Java_jsynprog_JavaCC, scale = %d\n", scale);
+    int n =0;
+    if (scale == 1) {
+        scale *= 1000;
+    }
+    int imax = 4*scale;
+    double tEnd = gethrtime() + testtime;
+    do { n = 0;
+    for (int i =0; i<imax; i++) {
+       n = cfunc(n);
+    }
+    } while (gethrtime() < tEnd);
+}
+
+int cfunc (int n) {
+    for (int j =0; j<100000;j++) {
+       n=n+1;
+    }
+    return n;
+}
+
+JNIEXPORT void JNICALL
+Java_jsynprog_JavaCJava (JNIEnv *env, jclass obj, int scale)
+{
+    fprintf(stderr, "Entering Java_jsynprog_JavaCJava, scale = %d\n", scale);
+    int pnum = 0;
+    jmethodID mid = (env)->GetStaticMethodID(obj, "javafunc", "(I)I");
+    if (mid == 0) {
+       fprintf(stderr, "Can't get jmethodID for \"javafunc\", \"(I)I\"\n");
+       return;
+    }
+    fprintf(stderr, "Calling CallStaticIntMethod, scale = %d\n", scale);
+    pnum = (env)->CallStaticIntMethod(obj, mid, scale);
+}
+
+JNIEXPORT jint JNICALL
+Java_jsynprog_isJVMPI (JNIEnv *env, jclass obj)
+{
+    char *jvmpi = getenv("SP_COLLECTOR_USE_JVMPI");
+
+    return jvmpi ? 1 : 0;
+}
diff --git a/gprofng/testsuite/gprofng.display/jsynprog/jsynprog.h b/gprofng/testsuite/gprofng.display/jsynprog/jsynprog.h
new file mode 100644 (file)
index 0000000..34b4f6c
--- /dev/null
@@ -0,0 +1,74 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+/*  Copyright (c) 2006, 2011, Oracle and/or its affiliates. All Rights Reserved. */
+#include <jni.h>
+/* Header for class jsynprog */
+
+#ifndef _Included_jsynprog
+#define _Included_jsynprog
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* Inaccessible static: dir_home */
+/* Inaccessible static: log */
+/* Inaccessible static: pstart */
+/* Inaccessible static: cstart */
+/*
+ * Class:     jsynprog
+ * Method:    Timer
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL Java_jsynprog_Timer
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     jsynprog
+ * Method:    cTimer
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL Java_jsynprog_cTimer
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     jsynprog
+ * Method:    computeSet
+ * Signature: ()D
+ */
+JNIEXPORT jdouble JNICALL Java_jsynprog_computeSet
+  (JNIEnv *, jclass);
+
+/*
+ * Class:     jsynprog
+ * Method:    JavaJavaC
+ * Signature: (I, I)I
+ */
+JNIEXPORT jint JNICALL Java_jsynprog_JavaJavaC
+  (JNIEnv *, jclass, jint, int);
+
+/*
+ * Class:     jsynprog
+ * Method:    JavaCC
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_jsynprog_JavaCC
+  (JNIEnv *, jclass, int);
+
+/*
+ * Class:     jsynprog
+ * Method:    JavaCJava
+ * Signature: (I, I)V
+ */
+JNIEXPORT void JNICALL Java_jsynprog_JavaCJava
+  (JNIEnv *, jclass, int);
+
+/*
+ * Class:     jsynprog
+ * Method:    isJVMPI
+ * Signature: (I)V
+ */
+JNIEXPORT jint JNICALL Java_jsynprog_isJVMPI
+  (JNIEnv *, jclass);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/gprofng/testsuite/gprofng.display/jsynprog/jsynprog.java b/gprofng/testsuite/gprofng.display/jsynprog/jsynprog.java
new file mode 100644 (file)
index 0000000..eb98b5e
--- /dev/null
@@ -0,0 +1,229 @@
+// Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
+// @(#)jsynprog.java SMI
+
+import java.util.*;
+import java.io.*;
+import java.text.*;
+
+class jsynprog 
+{
+    private static String      dir_home;
+    private static PrintWriter log;
+    private static double      pstart, cstart;
+
+    /* JNI calls */
+    public  static native double Timer();
+    private static native double cTimer();
+    private static native double computeSet();
+    private static native int JavaJavaC(int np, int scale);
+    private static native void JavaCC(int scale);
+    private static native void JavaCJava(int scale);
+    private static native int isJVMPI();
+
+    public static double testtime = 3.0 * 1e9;
+
+    public static void main (String [] args)
+    {
+       jsynprog jsyn_obj = new jsynprog();
+       Integer ni;
+       int scale = 1000;
+
+       createAcct();
+       LoadJNILibrary(args);
+        testtime = computeSet();
+
+       /* check for invocation parameter */
+       if (args.length != 0) {
+           if (args[0].equals("fast")) {
+               scale = 10000;
+           } else if (args[0].equals("slow")) {
+               scale = 1;
+           } else {
+               System.err.println("fatal: unexpected argument: " + args[0] );
+               System.exit(1);
+           }
+       }
+
+       /* large memory allocations, trigger gc */
+       Routine rtn = new Routine();
+       Sub_Routine sbrt = new Sub_Routine();
+       recTime(); 
+       rtn.memalloc(10000, scale);
+       printValue("Routine.memalloc", false);
+
+       /* add integers */
+       recTime(); 
+       ni = new Integer (rtn.add_int(scale));
+       printValue("Routine.add_int", true);
+
+       /* add double */
+       recTime(); 
+       Double nd = new Double(rtn.add_double(scale)); 
+       printValue("Routine.add_double", true);
+
+       /* call method in derived class */ 
+       recTime(); 
+       ni = new Integer (sbrt.add_int(scale));
+       printValue("Sub_Routine.add_int", true);
+
+       /* call method that defines an inner class */ 
+       recTime(); 
+       Integer[] na = rtn.has_inner_class(scale);
+       printValue("Routine.has_inner_class", true);
+
+       /* recursion */ 
+       recTime(); 
+       rtn.recurse(0,80, scale);
+       printValue("Routine.recurse", true);
+
+       /* deep recursion */ 
+       recTime(); 
+       rtn.recursedeep(0,500, scale);
+       printValue("<Truncated-stack>", true);
+
+       /* indirect recursion */ 
+       recTime(); 
+       rtn.bounce(0,20, scale);
+       printValue("Routine.bounce", true);
+
+       /* array operations */ 
+       recTime(); 
+       rtn.array_op(scale);
+       printValue("Routine.array_op", false);
+
+       /* Vector operations */ 
+       recTime(); 
+       rtn.vector_op(scale);
+       printValue("Routine.vector_op", false);
+
+       /* spend time in system calls */ 
+       recTime(); 
+       rtn.sys_op(scale);
+       printValue("Routine.sys_op", false);
+
+       /* java->java->c */
+       recTime(); 
+       int np = 0;
+       jni_JavaJavaC(np, scale);
+       printValue("jsynprog.jni_JavaJavaC", true);
+
+       /* java->c->c */
+       recTime(); 
+       JavaCC(scale);
+       printValue("jsynprog.JavaCC", true);
+
+       /* java->c->java */
+       recTime(); 
+       JavaCJava(scale);
+       printValue("jsynprog.JavaCJava", true);
+     
+     
+       /* dynamically loaded classes */
+       String java_ver = System.getProperty("java.version");
+       Launcher lnch = new Launcher();
+       String[] params = new String[]{"DynLoadedClass"};
+       recTime();
+       lnch.main(params);
+       printValue("Launcher.main", true);
+
+       System.gc();
+   }
+
+   /* 
+    ** Create accounting file 
+    */
+   private static void createAcct() {
+       System.out.println ("Directing output to acct file...");
+       try {
+          log = new PrintWriter (new FileWriter("jsynprog.acct"), true);
+       } catch (IOException ioe) {
+          ioe.printStackTrace();
+          System.err.println("fatal: Cannot create accounting file ");
+          System.exit(1);
+       }
+
+       log.println("X\tLWPTime\tCPUTime\tFunction");
+   }
+
+   /* 
+    ** Print output in acct file 
+    */
+   private static void printValue (String fname, boolean noignore) {
+       double  p_end = Timer();         // Global.Timer();
+       double  c_end = cTimer();       // Global.cTimer();
+       double  prog_elapsed = p_end - pstart;
+       double  cpu_elapsed = c_end - cstart;
+       DecimalFormat     format_decimal = new DecimalFormat("0.000");
+
+       System.out.println("Running " + fname + "; T = " + format_decimal.format(prog_elapsed * 0.000000001)
+               +" UCPU = " + format_decimal.format(cpu_elapsed * 0.000000001));
+       log.print( (noignore == true?  "X" : "Y")
+               + "\t" + format_decimal.format(prog_elapsed * 0.000000001) + "\t"
+               + format_decimal.format(cpu_elapsed * 0.000000001) + "\t");
+       log.println(fname);
+   }
+
+   /*
+    ** Record intial times
+    */
+   private static void recTime() {
+       pstart = Timer();        // Global.Timer();
+       cstart = cTimer();      // Global.cTimer();
+   }
+
+   /*
+    ** Load dynamic shared library for JNI
+    */
+   private static void LoadJNILibrary(String[] args) {
+
+       try {
+          dir_home = (new File(".")).getCanonicalPath();
+       } catch (IOException e) {
+          dir_home = "..";
+       }
+       System.out.println("libpath:"+dir_home);
+
+       // Find which JVM was invoked
+       String jvm_format = System.getProperty("java.vm.name"); 
+       System.out.println("jvm "+ jvm_format);
+       try {
+           System.out.println("Loading library.... " + dir_home + "/libcloop.so");
+           System.load(dir_home + "/libcloop.so");
+       } catch (UnsatisfiedLinkError e) {
+          System.err.println("fatal: Cannot load shared library " + e);
+          System.exit(1);
+       }
+   }
+
+   /*
+    ** Makes a lot of JNI calls
+    */ 
+   private static void jni_JavaJavaC(int np, int scale) {
+       int ret = 0;
+       int jmax = 10000;
+       System.out.println("Entering jni_JavaJavaC, scale = " + scale);
+       double tEnd = Timer() + testtime;
+       do {
+       for (int j =0 ; j<jmax; j++) {
+           ret = JavaJavaC(np, scale);
+       }
+       } while (Timer() < tEnd);
+   }
+
+   public static int javafunc (int scale) {
+       int jmax = 200*scale;
+       int imax = 40;
+       int np = 0;
+       // System.out.println("Entering javafunc, scale = " + scale);
+       double tEnd = Timer() + testtime;
+       do { np = 0;
+       for (int j =0 ; j<jmax; j++) {
+           for (int i =0 ; i<imax; i++) {
+               np = (i%2==0)?np:(np + 1);
+           }
+       }
+       } while (Timer() < tEnd);
+       return np;
+   }
+}
diff --git a/gprofng/testsuite/gprofng.display/mttest/Makefile b/gprofng/testsuite/gprofng.display/mttest/Makefile
new file mode 100644 (file)
index 0000000..0613ffb
--- /dev/null
@@ -0,0 +1,41 @@
+#   Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# This Makefile builds the mttest demo code
+
+# Select a thread flag, BOUND or UNBOUND, and comment the other one
+#FLAG   = UNBOUND
+FLAG   = BOUND
+
+TARGETS            = ./mttest
+TARGET     = ./mttest
+ACCT_FILE   = mttest.acct
+
+srcdir     = .
+include $(srcdir)/../../lib/Makefile.skel
+
+SRCS       = $(srcdir)/gethrtime.c $(srcdir)/mttest.c
+
+$(TARGET): $(SRCS)
+       $(CC) $(CFLAGS) -D$(FLAG) -pthread -o $@ $(SRCS)
+
+$(EXPERIMENT): $(TARGETS)
+       rm -rf $@
+       $(COLLECT) $(COLLECT_FLAGS) -o $@ $(TARGET) $(TARGET_FLAGS)
+
diff --git a/gprofng/testsuite/gprofng.display/mttest/check_results.pl b/gprofng/testsuite/gprofng.display/mttest/check_results.pl
new file mode 100644 (file)
index 0000000..2d67e8b
--- /dev/null
@@ -0,0 +1,46 @@
+#!/bin/sh -- # This comment tells perl not to loop!
+
+#   Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+eval 'exec ${PERL:=/usr/bin/perl} -S $0 ${1+"$@"}'
+if 0;
+
+use strict;
+use File::Basename;
+require "acct.pm";
+
+# XXX This needs better documentation. Or any, really.
+# e.g. what does (1, 2, 3) signify?
+sub read_acct
+{
+  my ($fname) = @_;
+  my(@checkTime, $nlines);
+  @checkTime = (1, 2, 3);
+  acct::readAcct($fname, @checkTime);
+  if (exists $acct::Acct{"*"})
+    {
+      printf "Signal lost\n";
+      exit 1;
+    }
+}
+
+read_acct($ARGV[0]);
+acct::read_er_print_out($ARGV[1], -1);
+exit acct::createDiff();
diff --git a/gprofng/testsuite/gprofng.display/mttest/gethrtime.c b/gprofng/testsuite/gprofng.display/mttest/gethrtime.c
new file mode 100644 (file)
index 0000000..a985401
--- /dev/null
@@ -0,0 +1,265 @@
+/* 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 <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#include <limits.h>
+
+#if defined(sparc) || defined(__sparcv9)
+#define SPARC       1
+#elif defined(__aarch64__)
+#define Aarch64     1
+#else
+#define Intel       1
+#endif
+
+/* typedef and function prototypes for hi-resolution timers */
+typedef long long hrtime_t;
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+  hrtime_t gethrtime ();
+  hrtime_t gethrvtime ();
+  hrtime_t gethrustime ();
+  hrtime_t gethrpxtime ();
+  int get_clock_rate ();
+  int get_ncpus ();
+
+  /* prototype underscore-appended wrappers for Fortran usage */
+  hrtime_t gethrtime_ ();
+  hrtime_t gethrustime_ ();
+  hrtime_t gethrpxtime_ ();
+  hrtime_t gethrvtime_ ();
+  int get_clock_rate_ ();
+#if defined(__cplusplus)
+}
+#endif
+
+/* =============================================================== */
+/*
+ * Below this are the get_clock_rate() and get_ncpus() for all OSs and architectures
+ */
+/* prototypes */
+
+/* implementation */
+static int clock_rate = 0;
+static int ncpus = 0;
+static char msgbuf[1024];
+
+int
+get_clock_rate (void)
+{
+  /* Linux version -- read /proc/cpuinfo
+   *   Note the parsing is different on intel-Linux and sparc-Linux
+   */
+  FILE *fp = fopen ("/proc/cpuinfo", "r");
+  if (fp != NULL)
+    {
+      char temp[1024];
+      while (fgets (temp, sizeof (temp), fp) != NULL)
+        {
+#if defined(SPARC)
+          /* cpu count for SPARC linux -- read from /proc/cpuinfo */
+          if (strncmp (temp, "ncpus active", 12) == 0)
+            {
+              char *val = strchr (temp, ':');
+              ncpus = val ? atol (val + 1) : 0;
+            }
+#endif
+
+          if (clock_rate == 0)
+            {
+              /* pick the first line that gives a CPU clock rate */
+#if defined(SPARC)
+              long long clk;
+              if (strncmp (temp, "Cpu0ClkTck", 10) == 0)
+                {
+                  char *val = strchr (temp, ':');
+                  clk = val ? strtoll (val + 1, NULL, 16) : 0;
+                  clock_rate = (int) (clk / 1000000);
+                }
+#elif defined(Intel)
+              if (strncmp (temp, "cpu MHz", 7) == 0)
+                {
+                  char *val = strchr (temp, ':');
+                  clock_rate = val ? atoi (val + 1) : 0;
+                }
+#endif
+            }
+
+          /* did we get a clock rate? */
+          if (clock_rate != 0)
+            {
+#if defined(SPARC)
+              /* since we got a cpu count, we can break from the look */
+              break;
+#endif
+            }
+#if defined(Intel)
+          /* On intel-Linux, count cpus based on "cpu MHz" lines */
+          if (strncmp (temp, "cpu MHz", 7) == 0)
+            ncpus++;
+#endif
+        }
+      fclose (fp);
+    }
+
+  if (clock_rate != 0)
+    sprintf (msgbuf, "Clock rate = %d MHz (from reading /proc/cpuinfo) %d CPUs\n", clock_rate, ncpus);
+
+  /* did we get a clock rate? */
+  if (clock_rate == 0)
+    {
+      clock_rate = 1000;
+      sprintf (msgbuf, "Clock rate = %d MHz (set by default) %d CPUs\n",
+               clock_rate, ncpus);
+    }
+  return clock_rate;
+}
+
+int
+get_ncpus (void)
+{
+  if (clock_rate == 0)
+    (void) get_clock_rate ();
+  return ncpus;
+}
+
+
+/* gethrpxtime -- per-process user+system CPU time from POSIX times() */
+/*  does not include the child user and system CPU time */
+hrtime_t
+gethrpxtime (void)
+{
+  hrtime_t rc = 0;
+  static int initted = 0;
+  static hrtime_t ns_per_tick;
+  if (!initted)
+    {
+      static long ticks_per_sec;
+      ticks_per_sec = sysconf (_SC_CLK_TCK);
+      ns_per_tick = 1000000000 / ticks_per_sec;
+      initted = 1;
+    }
+  struct tms mytms = {0};
+
+  clock_t curtick = times (&mytms);
+  if (curtick == 0) return rc;
+  rc = (mytms.tms_utime + mytms.tms_stime) * ns_per_tick;
+  return rc;
+}
+
+/* gethrustime -- per-process user+system CPU time from getrusage() */
+hrtime_t
+gethrustime (void)
+{
+  struct rusage usage;
+  if (0 == getrusage (RUSAGE_SELF, &usage))
+    {
+      hrtime_t rc = usage.ru_utime.tv_sec /* seconds */
+              + usage.ru_stime.tv_sec;
+      rc = usage.ru_utime.tv_usec /* microseconds */
+              + usage.ru_stime.tv_usec + 1000000 * rc;
+      rc *= 1000; /* nanoseconds */
+      return rc;
+    }
+  else
+    return 0;
+}
+
+/*
+ * Below this are the Linux versions of gethrvtime and gethrtime
+ */
+hrtime_t
+gethrtcputime (void)
+{
+  struct timespec tp;
+  hrtime_t rc = 0;
+  int r = clock_gettime (CLOCK_THREAD_CPUTIME_ID, &tp);
+  if (r == 0)
+    rc = ((hrtime_t) tp.tv_sec) * 1000000000 + (hrtime_t) tp.tv_nsec;
+  return rc;
+}
+
+/* generic gethrvtime -- uses gethrtcputime */
+hrtime_t
+gethrvtime ()
+{
+  return gethrtcputime ();
+}
+
+/*
+ *  CLOCK_MONOTONIC
+ *  Clock that cannot be set and represents monotonic time since some
+ *           unspecified starting point.
+ */
+hrtime_t
+gethrtime (void)
+{
+  struct timespec tp;
+  hrtime_t rc = 0;
+  int r = clock_gettime (CLOCK_MONOTONIC, &tp);
+  if (r == 0)
+    rc = ((hrtime_t) tp.tv_sec) * 1000000000 + (hrtime_t) tp.tv_nsec;
+  return rc;
+}
+
+/*
+ * define underscore-appended wrappers for Fortran usage
+ */
+hrtime_t
+gethrtime_ ()
+{
+  return gethrtime ();
+}
+
+hrtime_t
+gethrustime_ ()
+{
+  return gethrustime ();
+}
+
+hrtime_t
+gethrpxtime_ ()
+{
+  return gethrpxtime ();
+}
+
+hrtime_t
+gethrvtime_ ()
+{
+  return gethrvtime ();
+}
+
+int
+get_clock_rate_ ()
+{
+  return get_clock_rate ();
+}
+
+void
+init_micro_acct () { }
diff --git a/gprofng/testsuite/gprofng.display/mttest/mttest.c b/gprofng/testsuite/gprofng.display/mttest/mttest.c
new file mode 100644 (file)
index 0000000..5d22af7
--- /dev/null
@@ -0,0 +1,1306 @@
+/* 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.  */
+
+/* mttest -- show threaded use of global and local locks */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/sysinfo.h>
+#include <sys/procfs.h>
+#include <sys/fcntl.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <math.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <errno.h>
+
+#ifdef CLONE
+#include <linux/sched.h>
+#include <signal.h>
+#include <sys/wait.h>    
+#include <sys/syscall.h>   
+#include <sys/mman.h>
+#include <linux/futex.h>
+#include <linux/unistd.h>
+static int CLONE_FLAGS[] = {
+  CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_SYSVSEM | SIGCHLD | CLONE_CHILD_CLEARTID | CLONE_PARENT_SETTID | CLONE_IO,
+  CLONE_VM | SIGCHLD | CLONE_CHILD_CLEARTID | CLONE_PARENT_SETTID,
+  CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD | CLONE_SYSVSEM | SIGCHLD | CLONE_CHILD_CLEARTID | CLONE_PARENT_SETTID | CLONE_IO,
+  CLONE_VM | CLONE_SIGHAND | CLONE_THREAD | SIGCHLD | CLONE_CHILD_CLEARTID | CLONE_PARENT_SETTID
+};
+
+#define CLONE_STACK_SIZE 8388608
+#define CLONE_TLS_SIZE   4096
+#define CLONE_RED_SIZE   4096
+
+#endif /* CLONE */
+
+typedef int processorid_t;
+typedef long long hrtime_t;
+typedef struct timespec timespec_t;
+extern hrtime_t gethrtime ();
+extern hrtime_t gethrvtime ();
+
+timespec_t * hrt_to_ts (hrtime_t hrt);
+static const pthread_mutex_t mutex_initializer = PTHREAD_MUTEX_INITIALIZER;
+#ifdef CLONE
+#define CLONE_IO                0x80000000      /* Clone io context */
+char *model = "Cloned threads";
+#else       
+#ifdef BOUND
+char *model = "Bound Posix threads";
+#else
+char *model = "Unbound Posix threads";
+#endif
+#endif
+
+char *prtime (time_t *);
+int get_clock_rate (void);
+int get_ncpus ();
+
+#ifdef SELFTEST
+void start_prof (void);
+void finish_prof (void);
+#endif
+
+#define _STRUCTURED_PROC    1
+#define TRUE                1 
+#define FALSE               0
+#define NUM_OF_THREADS      4
+#define NUM_OF_BLOCKS       4 
+#define NUM_OF_RESOURCES    3 
+#define MYTIMEOUT           1000000000
+#define MYDBLTIMEOUT        ((double) 1000000000.)
+
+int repeat_count = 1; /* number of times to repeat test */
+int job_index = -1; /* index of selected job, if just one */
+int uniprocessor = 0; /* non-zero if -u specified; causes single processor bind */
+processorid_t cpuid;
+processorid_t ocpuid;
+
+// not a typedef; simplifies analyzer data display output
+#define workCtr_t double
+
+typedef struct workStruct_t
+{
+  workCtr_t sum_ctr;
+} workStruct_t;
+
+struct Workblk;
+
+typedef struct Workblk
+{
+  int index;                /* index of this block */
+  int strategy;             /* specifies type of locking to do */
+  int proffail;             /* flag set if thread loses interrupts */
+#ifdef CLONE
+  pid_t tid;                /* Linux kernel thread id */
+#else
+  pthread_t tid;            /* thread processing buffer */
+#endif        
+  pthread_mutex_t lock;     /* lock for this buffer */
+  lwpid_t ilwpid;           /* lwp processing buffer (initially) */
+  lwpid_t lwpid;            /* lwp processing buffer (after sync) */
+
+  /* timers */
+  hrtime_t start;           /* buffer fetched, wall clock */
+  hrtime_t vstart;          /* buffer fetched, CPU timer */
+  hrtime_t ready;           /* lock acquired (if needed), wall clock */
+  hrtime_t vready;          /* lock acquired (if needed), CPU timer */
+  hrtime_t done;            /* work done, wall clock */
+  hrtime_t vdone;           /* work done, CPU timer */
+  hrtime_t compute_ready;   /* compute ready, wall clock */
+  hrtime_t compute_vready;  /* compute ready, CPU timer */
+  hrtime_t compute_done;    /* compute done, wall clock */
+  hrtime_t compute_vdone;   /* compute done, CPU timer */
+  struct Workblk *next;     /* for queue management */
+  workStruct_t list[100];
+} Workblk;
+
+/* lookup table for behavior scripts */
+struct scripttab
+{
+  char *test_name;
+  void (*test_func)(Workblk *, struct scripttab *);
+  char *called_name;
+  void (*called_func)(workStruct_t *);
+};
+
+int locktest ();
+void resolve_symbols ();
+void init_micro_acct ();
+void compute_set (volatile workStruct_t *x);
+void compute (workStruct_t *x);
+void computeA (workStruct_t *x);
+void computeB (workStruct_t *x);
+void computeC (workStruct_t *x);
+void computeD (workStruct_t *x);
+void computeE (workStruct_t *x);
+void computeF (workStruct_t *x);
+void computeG (workStruct_t *x);
+void computeH (workStruct_t *x);
+void computeI (workStruct_t *x);
+void computeJ (workStruct_t *x);
+void computeK (workStruct_t *x);
+void addone (workCtr_t *x);
+void init_arrays (int strat);
+void dump_arrays ();
+void *do_work (void *v);
+void thread_work ();
+void nothreads (Workblk *array, struct scripttab *k);
+void lock_none (Workblk *array, struct scripttab *k);
+void cache_trash (Workblk *array, struct scripttab *k);
+void lock_global (Workblk *array, struct scripttab *k);
+void trylock_global (Workblk *array, struct scripttab *k);
+void lock_local (Workblk *array, struct scripttab *k);
+void calladd (Workblk *array, struct scripttab *k);
+void cond_global (Workblk *array, struct scripttab *k);
+void cond_timeout_global (Workblk *array, struct scripttab *k);
+void sema_global (Workblk *array, struct scripttab *k);
+void read_write (Workblk *array, struct scripttab *k);
+void s5sem (Workblk *array, struct scripttab *k);
+FILE *open_output (char *filename);
+int close_file (FILE *f);
+void scale_init (int argcc, char **argvv);
+void
+Print_Usage (int);
+
+struct scripttab scripttab[] = {
+#ifdef CLONE
+  {"nothreads",           nothreads,           "compute",  compute},
+  {"lock_none",           lock_none,           "computeA", computeA},
+  {"cache_trash",         cache_trash,         "computeB", computeB},
+  {"calladd",             calladd,             "computeF", computeF},
+  {"sema_global",         sema_global,         "computeI", computeI},
+#else    
+  {"nothreads",           nothreads,           "compute",  compute},
+  {"cond_timeout_global", cond_timeout_global, "computeH", computeH},
+  {"lock_none",           lock_none,           "computeA", computeA},
+  {"cache_trash",         cache_trash,         "computeB", computeB},
+  {"lock_global",         lock_global,         "computeC", computeC},
+  {"trylock_global",      trylock_global,      "computeD", computeD},
+  {"lock_local",          lock_local,          "computeE", computeE},
+  {"calladd",             calladd,             "computeF", computeF},
+  {"sema_global",         sema_global,         "computeI", computeI},
+  {"cond_global",         cond_global,         "computeG", computeG},
+#endif
+  {NULL, NULL, NULL, NULL}
+};
+
+static pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t global_cond_lock = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t global_cond_lock2 = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t global_cond = PTHREAD_COND_INITIALIZER;
+static timespec_t time_out;
+static sem_t global_sema_lock;  /* dynamically initted */
+static int s5_sema_id;
+static int global_cond_flag = TRUE;
+static int count = NUM_OF_RESOURCES;
+
+/* an array of workStruct_ts that is contiguous */
+workStruct_t *element;
+
+typedef struct
+{
+  int size;
+  Workblk *arrays;
+} Head;
+
+int nthreads = NUM_OF_THREADS;
+int narrays = NUM_OF_BLOCKS;
+static Head head;
+char *name;
+FILE *fid;
+
+#ifdef CLONE
+static sem_t fetch_sema_lock;
+static pid_t *tid;
+static void *stack_space[NUM_OF_THREADS];
+static void *stack[NUM_OF_THREADS];
+int stack_size = CLONE_STACK_SIZE;
+#else        
+static pthread_t *tid;
+#endif        
+pthread_attr_t attr;
+
+int
+main (int argc, char **argv, char **envp)
+{
+  int i;
+  scale_init (argc, argv);
+
+#define ALIGNMENTOFFSET 2 /* adjust alignment */
+  i = sizeof (workStruct_t) * (narrays + ALIGNMENTOFFSET);
+  element = memalign (64, i);
+  if (element == NULL)
+    {
+      perror ("calloc( narrays, sizeof(workStruct_t) )");
+      exit (1);
+    }
+  compute_set (element);
+  memset (element, 0, i);
+  element += ALIGNMENTOFFSET;
+
+#ifdef SELFTEST
+  start_prof ();
+#endif
+  fid = open_output ("mttest.acct");
+  if (job_index == -1)
+    i = (sizeof (scripttab) / sizeof ( struct scripttab) - 1);
+  else
+    i = 1;
+  fprintf (fid, "Number of tests: %d  Repeat count: %d\n", i, repeat_count);
+  fprintf (fid, "MHz: %d\n", get_clock_rate ());
+  fprintf (fid, "X    Incl. Total   Incl. CPU   Incl. Sync. Wait   Name (%s)\n",
+           model);
+  fprintf (fid, "X   %7.3f        %7.3f       %7.3f         %s\n",
+           0.0, 0.0, 0.0, "<Unknown>");
+  fflush (fid);
+  name = strdup (argv[0]);
+  init_micro_acct ();
+  pthread_attr_init (&attr);
+
+#ifdef BOUND
+  pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM);
+#endif
+  sem_init (&global_sema_lock, 0, count);
+#ifdef CLONE
+  sem_init (&fetch_sema_lock, 0, 1);
+  for (i = 0; i < nthreads; i++)
+    {
+      stack_space[i] = mmap (NULL, stack_size, PROT_READ | PROT_WRITE
+              | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, -1, 0);
+      if ((void*) - 1 == stack_space[i])
+        {
+          fprintf (stderr, "Error: mmap returned -1\n");
+          exit (1);
+        }
+      mprotect (stack_space[i], CLONE_RED_SIZE, PROT_NONE);
+      stack[i] = (char*) (stack_space[i]) + stack_size - CLONE_TLS_SIZE; // stack grows back
+    }
+#endif 
+
+  resolve_symbols ();
+  i = locktest ();
+  close_file (fid);
+
+#ifdef SELFTEST
+  finish_prof ();
+#endif
+  return 0;
+}
+
+Workblk *in_queue = NULL;
+Workblk *in_queue_last = NULL;
+
+pthread_mutex_t queue_lock;
+
+void
+queue_work (Workblk * w)
+{
+  if (in_queue == NULL)
+    {
+      in_queue = w;
+      in_queue_last = w;
+    }
+  else
+    {
+      in_queue_last->next = w;
+      in_queue_last = w;
+    }
+}
+
+Workblk *
+fetch_work ()
+{
+  /* acquire the queue lock */
+#ifdef CLONE
+  sem_wait (&fetch_sema_lock);
+#else
+  pthread_mutex_lock (&queue_lock);
+#endif
+
+  /* get the next block */
+  Workblk *w = in_queue;
+  if (w != NULL)
+    {
+      in_queue = w->next;
+      w->next = NULL;
+      if (in_queue == NULL)
+        in_queue_last = NULL;
+    }
+#ifdef CLONE
+  sem_post (&fetch_sema_lock);
+#else        
+  pthread_mutex_unlock (&queue_lock);
+#endif
+
+  /* return the block */
+  return w;
+}
+
+int
+locktest ()
+{
+  int i;
+  Workblk *array;
+  struct scripttab *k;
+  hrtime_t start;
+  hrtime_t vstart;
+  hrtime_t end;
+  hrtime_t vend;
+  struct timeval ttime;
+  time_t secs;
+
+  head.size = narrays;
+  head.arrays = (Workblk *) calloc (narrays, sizeof (Workblk));
+
+  for (i = 0, array = head.arrays; i < narrays; i++, array++)
+    array->index = i;
+
+  printf ("%s: number of %s = %d, number of blocks = %d, repeat %d times %s\n",
+          name, model, nthreads, narrays, repeat_count,
+          (uniprocessor == 0 ? "" : "[single CPU]"));
+#ifdef  CLONE
+  tid = (pid_t *) calloc (nthreads*repeat_count, sizeof (pid_t));
+#else       
+  tid = (pthread_t *) calloc (nthreads*repeat_count, sizeof (pthread_t));
+#endif 
+  for (count = 0; count < repeat_count; count++)
+    {
+      (void) gettimeofday (&ttime, NULL);
+      secs = (time_t) ttime.tv_sec;
+      printf ("Iteration %d, starting %s\n", count + 1, prtime (&secs));
+      if (job_index == -1)
+        {
+          for (i = 0;; i++)
+            {
+              k = &scripttab[i];
+              if (k->test_name == NULL)
+                break;
+
+              printf ("begin thread_work, %s\n", k->test_name);
+              init_arrays (i);
+              start = gethrtime ();
+              vstart = gethrvtime ();
+
+              if (strcmp (k->test_name, "nothreads") == 0)
+                {
+                  /* the "nothreads" task is special-cased to run in the main thread */
+                  int one_thread = 1;
+                  do_work (&one_thread);
+                }
+              else if (nthreads == 1)
+                {
+                  int one_thread = 1;
+                  do_work (&one_thread);
+                }
+              else
+                thread_work ();
+              end = gethrtime ();
+              vend = gethrvtime ();
+              dump_arrays (end - start, vend - vstart, i);
+            }
+        }
+      else
+        {
+          k = &scripttab[job_index];
+          if (k->test_name == NULL)
+            break;
+
+          printf ("begin thread_work, %s\n", k->test_name);
+          init_arrays (job_index);
+          start = gethrtime ();
+          vstart = gethrvtime ();
+          if (strcmp (k->test_name, "nothreads") == 0)
+            {
+              /* first one is special-cased to run in 1 thread */
+              int one_thread = 1;
+              do_work (&one_thread);
+            }
+          else if (nthreads == 1)
+            do_work (NULL);
+          else
+            thread_work ();
+          end = gethrtime ();
+          vend = gethrvtime ();
+          dump_arrays (end - start, vend - vstart, job_index);
+        }
+    }
+
+  /* we're done, return */
+  return (0);
+}
+
+void
+init_arrays (int strat)
+{
+  int i;
+  Workblk *array;
+  for (i = 0, array = head.arrays; i < narrays; i++, array++)
+    {
+      bzero (array, sizeof (Workblk));
+      array->index = i;
+      array->strategy = strat;
+      queue_work (array);
+    }
+}
+
+void
+dump_arrays (hrtime_t real, hrtime_t cpu, int case_index)
+{
+  int i;
+  double t1, t2, t3, t4, t5, t6, t7, t8;
+  Workblk *array;
+  struct scripttab *k;
+  double sumtotal = 0.;
+  double sumCPU = 0.;
+  double sumlock = 0.;
+  double sumCompTotal = 0.;
+  double sumCompCPU = 0.;
+  int proffail = 0;
+  printf ("                                   real       real       real        CPU\n");
+  printf ("idx (t id)                        total       lock     crunch     crunch\n");
+  for (i = 0, array = head.arrays; i < narrays; i++, array++)
+    {
+      /* check to see if data lost for this block */
+      /* set flag to disable the comparison */
+      /* convert times to seconds */
+      t1 = ((double) array->done - array->start) / MYDBLTIMEOUT;
+      t2 = ((double) array->vdone - array->vstart) / MYDBLTIMEOUT;
+      t3 = ((double) array->ready - array->start) / MYDBLTIMEOUT;
+      t4 = ((double) array->vready - array->vstart) / MYDBLTIMEOUT;
+      t5 = ((double) array->done - array->ready) / MYDBLTIMEOUT;
+      t6 = ((double) array->vdone - array->vready) / MYDBLTIMEOUT;
+      t7 = ((double) array->compute_done - array->compute_ready) / MYDBLTIMEOUT;
+      t8 = ((double) array->compute_vdone - array->compute_vready)
+              / MYDBLTIMEOUT;
+
+      if (array->proffail != 0)
+        proffail = 1;
+      sumtotal = sumtotal + t1; /* incl. total time */
+      sumlock = sumlock + t3; /* incl. sync. wait time */
+#ifdef BOUND
+      /* NOTE:
+       *  for bound threads, sumCPU includes the synchronization
+       *  CPU time; for unbound it does not
+       */
+      sumCPU = sumCPU + t2; /* test incl. CPU time */
+#else
+      sumCPU = sumCPU + t6; /* test incl. CPU time */
+#endif
+      sumCompTotal = sumCompTotal + t7; /* compute incl. totaltime */
+      sumCompCPU = sumCompCPU + t8; /* compute incl. CPU time */
+      printf ("#%2d (t%3ld, il%3d, l%3d)      %10.6f %10.6f %10.6f %10.6f%s\n",
+              array->index, array->tid, array->ilwpid, array->lwpid, t1, t3,
+              t5, t6, array->proffail == 0 ? "" : " *");
+      if (t4 == 0) printf ("t4 == 0\n");
+      assert (array->lwpid > 0);
+#if defined(BOUND)
+      assert (array->lwpid == array->ilwpid);
+#endif
+    }
+
+  k = &scripttab[case_index];
+
+  printf ("%-25s    %10.6f %10.6f  %-9s %10.6f\n", k->test_name, sumtotal,
+          sumlock, k->called_name, sumCPU);
+  printf ("main                         %10.6f\n\n",
+          (double) real / MYDBLTIMEOUT);
+
+  /* write accounting record for task */
+  fprintf (fid, "X   %7.3f        %7.3f       %7.3f         %s%s\n",
+           sumtotal, sumCPU, sumlock, k->test_name,
+           (proffail == 0 ? "" : " *"));
+  /* write accounting record for task's compute function */
+  fprintf (fid, "X   %7.3f        %7.3f         0.            %s%s\n",
+           sumCompTotal, sumCompCPU, k->called_name,
+           (proffail == 0 ? "" : " *"));
+  fflush (fid);
+  fflush (stdout);
+
+}
+
+void
+thread_work ()
+{
+  int i;
+#ifdef CLONE
+  pid_t ctid[NUM_OF_THREADS];
+  for (i = 0; i < nthreads; i++)
+    ctid[i] = -1;
+#endif
+
+  /* create nthreads threads, having each start at do_work */
+  for (i = 0; i < nthreads; i++)
+    {
+      int retval;
+#ifdef BOUND
+      retval = pthread_create (&(tid[i]), &attr, do_work, 0);
+#endif
+#ifdef UNBOUND
+      retval = pthread_create (&(tid[i]), 0, do_work, 0);
+#endif
+#ifdef CLONE
+      tid[i] = retval = clone ((int (*)(void*))do_work, stack[i],
+                               CLONE_FLAGS[i % sizeof (CLONE_FLAGS)], NULL,
+                               &(ctid[i]), NULL, &(ctid[i]));
+      if (retval < 0)
+        {
+          perror ("Oops, clone failed");
+          exit (1);
+        }
+#else
+      if (retval != 0)
+        {
+          perror ("Oops, thr_create failed");
+          exit (1);
+        }
+#endif 
+    }
+
+  /* wait for all threads to complete their work and join */
+  for (i = 0; i < nthreads; i++)
+    {
+#ifdef CLONE
+      int counter = 0;
+      while (ctid[i] == -1)
+        counter++;
+      while (ctid[i] != 0)
+        syscall (__NR_futex, &(ctid[i]), FUTEX_WAIT, tid[i], NULL);
+#else
+      pthread_join (tid[i], 0);
+#endif
+    }
+#ifdef CLONE
+  for (i = 0; i < nthreads / 2; i++)
+    {
+      int status;
+      waitpid (tid[i], &status, __WALL);
+    }
+#endif
+}
+
+/* do_work: process array's data with locking, based on array->strategy */
+void *
+do_work (void *v)
+{
+  Workblk *array;
+  struct scripttab *k;
+  int i;
+  volatile double x;
+
+#ifdef CLONE
+  pid_t mytid = syscall (__NR_gettid);
+#else        
+  pthread_t mytid = pthread_self ();
+#endif
+
+  /* delay to ensure that a tick passes, so that the
+   * first profile packet doesn't show the thread startup time
+   * attributed to the accounting functions
+   */
+  x = 0;
+  for (i = 0; i < 2000000; i++)
+    x = x + 1.0;
+
+  for (;;)
+    {
+      /* fetch a workblk */
+      array = fetch_work ();
+      if (array == NULL)  /* we're done */
+        break;
+      array->lock = mutex_initializer;
+      array->proffail = 0;
+      array->tid = mytid;
+      array->ilwpid = getpid () /* pthread_self()*/;
+
+      array->lwpid = -1; /* initialize to inappropriate value */
+      array->start = gethrtime ();
+      array->vstart = gethrvtime ();
+
+      k = &scripttab[array->strategy];
+      (k->test_func)(array, k);
+
+      array->done = gethrtime ();
+      array->vdone = gethrvtime ();
+      array->lwpid = getpid () /* pthread_self()*/;
+
+#if defined(BOUND)
+      assert (array->lwpid == array->ilwpid);
+#endif
+    }
+
+#ifdef CLONE
+  if (v == NULL)
+    syscall (__NR_exit);
+#endif  
+  return NULL;
+}
+
+/* nothreads: process array's data with no locking; called without threads */
+void
+nothreads (Workblk *array, struct scripttab *k)
+{
+  array->ready = gethrtime ();
+  array->vready = gethrvtime ();
+  array->compute_ready = array->ready;
+  array->compute_vready = array->vready;
+
+  /* do some work on the current array */
+  (k->called_func)(&array->list[0]);
+
+  array->compute_done = gethrtime ();
+  array->compute_vdone = gethrvtime ();
+
+}
+
+/* lock_none: process array's data with no locking */
+void
+lock_none (Workblk *array, struct scripttab *k)
+{
+  array->ready = array->start;
+  array->vready = array->vstart;
+  array->compute_ready = array->ready;
+  array->compute_vready = array->vready;
+
+  /* do some work on the current array */
+  (k->called_func)(&array->list[0]);
+
+  array->compute_done = gethrtime ();
+  array->compute_vdone = gethrvtime ();
+
+}
+
+/* cache_trash_even:
+ *      called for even numbered l1 cache lines
+ */
+void
+cache_trash_even (Workblk *array, struct scripttab *k)
+{
+  /* use a datum that will share a cache line with others */
+  (k->called_func)(&element[array->index]);
+}
+
+/* cache_trash_odd: 
+ *      called for odd numbered l1 cache lines
+ */
+void
+cache_trash_odd (Workblk *array, struct scripttab *k)
+{
+  /* use a datum that will share a cache line with others */
+  (k->called_func)(&element[array->index]);
+}
+
+/* cache_trash: multiple threads refer to adjacent words,
+ *     causing false sharing of cache lines, and trashing
+ */
+void
+cache_trash (Workblk *array, struct scripttab *k)
+{
+  array->ready = array->start;
+  array->vready = array->vstart;
+  array->compute_ready = array->ready;
+  array->compute_vready = array->vready;
+
+  /* use a datum that will share a cache line with others */
+  if ((unsigned long) (&element[array->index]) / 32 & 1)
+    cache_trash_odd (array, k);
+  else
+    cache_trash_even (array, k);
+
+  array->compute_done = gethrtime ();
+  array->compute_vdone = gethrvtime ();
+}
+
+/* lock_global: use a global lock to process array's data */
+void
+lock_global (Workblk *array, struct scripttab *k)
+{
+  /* acquire the global lock */
+  pthread_mutex_lock (&global_lock);
+
+  array->ready = gethrtime ();
+  array->vready = gethrvtime ();
+  array->compute_ready = array->ready;
+  array->compute_vready = array->vready;
+
+  /* do some work on the current array */
+  (k->called_func)(&array->list[0]);
+
+  array->compute_done = gethrtime ();
+  array->compute_vdone = gethrvtime ();
+
+  /* free the global lock */
+  pthread_mutex_unlock (&global_lock);
+  /* make another call to preclude tail-call optimization on the unlock */
+  (void) gethrtime ();
+}
+
+/* trylock_global: busy-wait on a global lock to process array's data */
+void
+trylock_global (Workblk *array, struct scripttab *k)
+{
+  int ret;
+
+  /* set ready before starting, since this is a busy wait */
+  array->ready = gethrtime ();
+  array->vready = gethrvtime ();
+
+  /* busy wait to acquire the global lock */
+  do
+    {
+      ret = pthread_mutex_trylock (&global_lock);
+    }
+  while (ret == EBUSY);
+  array->compute_ready = gethrtime ();
+  array->compute_vready = gethrvtime ();
+
+  /* do some work on the current array */
+  (k->called_func)(&array->list[0]);
+
+  array->compute_done = gethrtime ();
+  array->compute_vdone = gethrvtime ();
+
+  /* free the global lock */
+  pthread_mutex_unlock (&global_lock);
+  /* make another call to preclude tail-call optimization on the unlock */
+  (void) gethrtime ();
+}
+
+/* lock_local: use a local lock to process array's data */
+void
+lock_local (Workblk *array, struct scripttab *k)
+{
+  /* acquire the local lock */
+  pthread_mutex_lock (&(array->lock));
+  array->ready = gethrtime ();
+  array->vready = gethrvtime ();
+  array->compute_ready = array->ready;
+  array->compute_vready = array->vready;
+
+  /* do some work on the current array */
+  (k->called_func)(&array->list[0]);
+
+  array->compute_done = gethrtime ();
+  array->compute_vdone = gethrvtime ();
+
+  /* free the local lock */
+  pthread_mutex_unlock (&array->lock);
+  /* make another call to preclude tail-call optimization on the unlock */
+  (void) gethrtime ();
+}
+
+/* cond_global: use a global condition variable to process array's data */
+void
+cond_global (Workblk *array, struct scripttab *k)
+{
+  /* acquire the global condition lock */
+  pthread_mutex_lock (&global_cond_lock);
+
+  /* check to see if the condition flag is true, If not then wait
+  for that condition flag to become true. */
+  while (global_cond_flag != TRUE)
+    pthread_cond_wait (&global_cond, &global_cond_lock);
+  /* Now, condition is true, and we have the global_cond_lock */
+
+  /* set the condition flag to be FALSE, so when a new thread
+   * is created, it should wait till this one is done.
+   */
+  global_cond_flag = FALSE;
+
+  /* free the global_cond_lock and acquire the global lock */
+  pthread_mutex_unlock (&global_cond_lock);
+  pthread_mutex_lock (&global_lock);
+
+  array->ready = gethrtime ();
+  array->vready = gethrvtime ();
+
+  array->compute_ready = array->ready;
+  array->compute_vready = array->vready;
+
+  /* do some work on the current array */
+  (k->called_func)(&array->list[0]);
+
+  array->compute_done = gethrtime ();
+  array->compute_vdone = gethrvtime ();
+
+  /* free the global lock */
+  pthread_mutex_unlock (&global_lock);
+
+  /* now set the condition, and signal any other threads */
+  pthread_mutex_lock (&global_cond_lock);
+
+  global_cond_flag = TRUE;
+  pthread_cond_signal (&global_cond);
+  pthread_mutex_unlock (&global_cond_lock);
+  /* make another call to preclude tail-call optimization on the unlock */
+  (void) gethrtime ();
+}
+
+/* cond_timeout_global: use a global condition time wait variable to 
+   process array's data */
+void
+cond_timeout_global (Workblk *array, struct scripttab *k)
+{
+  int err;
+  struct timeval current_time;
+
+  /* acquire the global condition lock */
+  pthread_mutex_lock (&global_cond_lock);
+  gettimeofday (&current_time, NULL);
+  time_out.tv_sec = current_time.tv_sec;
+  time_out.tv_nsec = current_time.tv_usec * 1000;
+
+  /* check to see if the condition flag is true, If not then wait
+   * for that condition flag to become true
+   */
+
+  while (global_cond_flag != TRUE)
+    {
+      /* add MYTIMEOUT to current time for timeout */
+      time_out.tv_nsec += MYTIMEOUT;
+      while (time_out.tv_nsec > 1000000000)
+        {
+          time_out.tv_nsec -= 1000000000;
+          time_out.tv_sec++;
+        }
+      err = pthread_cond_timedwait (&global_cond, &global_cond_lock, &time_out);
+      if (err == 0)
+        break;
+    }
+  /* Now, condition is true, and we have the global_cond_lock */
+
+  pthread_mutex_unlock (&global_cond_lock);
+
+  pthread_mutex_lock (&global_cond_lock2);
+  global_cond_flag = FALSE;
+  pthread_mutex_unlock (&global_cond_lock2);
+
+  /* acquire the global lock */
+  pthread_mutex_lock (&global_lock);
+
+  array->ready = gethrtime ();
+  array->vready = gethrvtime ();
+
+  array->compute_ready = array->ready;
+  array->compute_vready = array->vready;
+
+  /* do some work on the current array */
+  (k->called_func)(&array->list[0]);
+  array->compute_done = gethrtime ();
+  array->compute_vdone = gethrvtime ();
+
+  /* free the global lock */
+  pthread_mutex_unlock (&global_lock);
+
+  /* now set the condition, and signal any other threads */
+  pthread_mutex_lock (&global_cond_lock2);
+
+  global_cond_flag = TRUE;
+  pthread_cond_signal (&global_cond);
+  pthread_mutex_unlock (&global_cond_lock2);
+
+  /* make another call to preclude tail-call optimization on the unlock */
+  (void) gethrtime ();
+}
+
+/* read_write: use a global Reader/Writer lock to process array's data */
+void
+read_write (Workblk *array, struct scripttab *k)
+{
+  /* make another call to preclude tail-call optimization on the unlock */
+  (void) gethrtime ();
+}
+
+/* sema_global: use a global semaphore to process array's data */
+void
+sema_global (Workblk *array, struct scripttab *k)
+{
+  sem_wait (&global_sema_lock);
+  array->ready = gethrtime ();
+  array->vready = gethrvtime ();
+  array->compute_ready = array->ready;
+  array->compute_vready = array->vready;
+
+  /* do some work on the current array */
+  (k->called_func)(&array->list[0]);
+
+  array->compute_done = gethrtime ();
+  array->compute_vdone = gethrvtime ();
+  sem_post (&global_sema_lock);
+
+  /* make another call to preclude tail-call optimization on the unlock */
+  (void) gethrtime ();
+}
+
+/* s5sema: use a global UNIX System V semaphore to process array's data */
+void
+s5sem (Workblk *array, struct scripttab *k)
+{
+  static struct sembuf op_wait[] = {
+    { 0, -1, IPC_NOWAIT}
+  };
+  static struct sembuf op_post[] = {
+    { 0, 1, 0}
+  };
+  int sema_val;
+
+  /* set ready before starting, since this is a busy wait */
+  array->ready = gethrtime ();
+  array->vready = gethrvtime ();
+  do
+    {
+      sema_val = semop (s5_sema_id, op_wait, 1);
+    }
+  while (sema_val == -1);
+
+  array->compute_ready = gethrtime ();
+  array->compute_vready = gethrvtime ();
+
+  /* do some work on the current array */
+  (k->called_func)(&array->list[0]);
+
+  array->compute_done = gethrtime ();
+  array->compute_vdone = gethrvtime ();
+
+  if (semop (s5_sema_id, op_post, 1) == -1)
+    perror ("semop: post");
+  /* make another call to preclude tail-call optimization on the unlock */
+  (void) gethrtime ();
+}
+
+/* lock_local: use a local lock to process array's data */
+void
+calladd (Workblk *array, struct scripttab *k)
+{
+  array->ready = array->start;
+  array->vready = array->vstart;
+  array->compute_ready = array->ready;
+  array->compute_vready = array->vready;
+  (k->called_func)(&array->list[0]);
+  array->compute_done = gethrtime ();
+  array->compute_vdone = gethrvtime ();
+}
+
+/* compute*: several copies, each burns cpu time, incrementing a workStruct_t */
+static long long loop_count = 80000000;
+
+void
+compute_set (volatile workStruct_t *x)
+{
+  double testtime = 3.0;
+  char *s = getenv ("SP_COLLECTOR_TEST_TIMER");
+  if (s)
+    {
+      testtime = atof (s);
+      if (testtime < 1.0)
+        testtime = 1.0;
+    }
+  hrtime_t t = gethrtime ();
+  x->sum_ctr = 0;
+  loop_count = 10000;
+  for (long long i = 0; i < loop_count; i++)
+    x->sum_ctr = x->sum_ctr + 1.0;
+  t = gethrtime () - t;
+  loop_count *= testtime * 1e9 / t;
+  printf ("compute_set: loop_count=%lld\n", loop_count);
+}
+
+void
+compute (workStruct_t *x)
+{
+  x->sum_ctr = 0;
+  for (long long i = 0; i < loop_count; i++)
+    x->sum_ctr = x->sum_ctr + 1.0;
+}
+
+void
+computeA (workStruct_t *x)
+{
+  x->sum_ctr = 0;
+  for (long long i = 0; i < loop_count; i++)
+    x->sum_ctr = x->sum_ctr + 1.0;
+}
+
+void
+computeB (workStruct_t *x)
+{
+  x->sum_ctr = 0;
+  for (long long i = 0; i < loop_count; i++)
+    x->sum_ctr = x->sum_ctr + 1.0;
+}
+
+void
+computeC (workStruct_t *x)
+{
+  x->sum_ctr = 0;
+  for (long long i = 0; i < loop_count; i++)
+    x->sum_ctr = x->sum_ctr + 1.0;
+}
+
+void
+computeD (workStruct_t *x)
+{
+  x->sum_ctr = 0;
+  for (long long i = 0; i < loop_count; i++)
+    x->sum_ctr = x->sum_ctr + 1.0;
+}
+
+void
+computeE (workStruct_t *x)
+{
+  x->sum_ctr = 0;
+  for (long long i = 0; i < loop_count; i++)
+    x->sum_ctr = x->sum_ctr + 1.0;
+}
+
+/* note that this one is different from the others, in that it calls
+ *     a function to do the add
+ */
+void
+computeF (workStruct_t *x)
+{
+  x->sum_ctr = 0;
+  for (long long i = 0; i < loop_count; i++)
+    addone (&x->sum_ctr);
+}
+
+void
+computeG (workStruct_t *x)
+{
+  x->sum_ctr = 0;
+  for (long long i = 0; i < loop_count; i++)
+    x->sum_ctr = x->sum_ctr + 1.0;
+}
+
+void
+computeH (workStruct_t *x)
+{
+  x->sum_ctr = 0;
+  for (long long i = 0; i < loop_count; i++)
+    x->sum_ctr = x->sum_ctr + 1.0;
+}
+
+void
+computeI (workStruct_t *x)
+{
+  x->sum_ctr = 0;
+  for (long long i = 0; i < loop_count; i++)
+    x->sum_ctr = x->sum_ctr + 1.0;
+}
+
+void
+computeJ (workStruct_t *x)
+{
+  x->sum_ctr = 0;
+  for (long long i = 0; i < loop_count; i++)
+    x->sum_ctr = x->sum_ctr + 1.0;
+}
+
+void
+computeK (workStruct_t *x)
+{
+  x->sum_ctr = 0;
+  for (long long i = 0; i < loop_count; i++)
+    x->sum_ctr = x->sum_ctr + 1.0;
+}
+
+void
+addone (workCtr_t *x)
+{
+  *x = *x + 1.0;
+}
+
+FILE *
+open_output (char *filename)
+{
+  errno = 0;
+  FILE *f = fopen (filename, "w");
+  if (f == NULL)
+    fprintf (stderr, "Open of %s for output failed: %s\n",
+             filename, strerror (errno));
+  return f;
+}
+
+int
+close_file (FILE *f)
+{
+  if (f == NULL)
+    return 0;
+  errno = 0;
+  int s = fclose (f);
+  if (s == EOF)
+    perror ("Close failed");
+  return s;
+}
+
+void
+scale_init (int argcc, char **argvv)
+{
+  int num;
+  int ii;
+  char *p;
+  struct scripttab *kk;
+
+  if (argcc >= 2) /* run mttest with options */
+    {
+      for (int i = 1; i < argcc; i++)
+        {
+          int j = i;
+          if (argvv[i][0] != '-')
+            Print_Usage (1);
+          if (argvv[i][1] == 'h' || argvv[i][1] == 'H')
+            Print_Usage (0);
+          if (argvv[i][1] == 'u')
+            {
+              uniprocessor++;
+              continue;
+            }
+          if (strlen (argvv[i]) == 2)
+            {
+              /* argument has blank separating key and number */
+              j++;
+              if (argcc > j)
+                {
+                  p = argvv[j];
+                  num = atoi (p);
+                }
+              else
+                Print_Usage (1);
+            }
+          else
+            {
+              /* argument has no blank separating key and number */
+              p = argvv[i] + 2;
+              num = atoi (p);
+            }
+
+          switch (argvv[i][1])
+            {
+            case 't':
+            case 'T':
+              nthreads = num;
+              break;
+            case 'b':
+            case 'B':
+              narrays = num;
+              break;
+            case 'r':
+            case 'R':
+              repeat_count = num;
+              break;
+            case 'j':
+            case 'J':
+              /* argument is a job name; p points to string */
+              for (ii = 0;; ii++)
+                {
+                  kk = &scripttab[ii];
+                  if (kk->test_name == NULL) /* Oops, name not found */
+                    Print_Usage (2);
+                  if (strcmp (kk->test_name, p) == 0)  /* found it */
+                    break;
+                }
+              job_index = ii;
+              break;
+            default:
+              Print_Usage (1);
+            }
+          i = j;
+        }
+    }
+}
+
+void
+Print_Usage (int error)
+{
+  if (error == 1)
+    printf ("\nError: Incorrect option\n");
+  else if (error == 2)
+    printf ("\nError: job name not found\n");
+  printf ("Usage: mttest [-t num_of_threads] [-b num_of_blocks] "
+          "[-R repeat_count] [-u] [-j job_name]\n");
+  printf ("    -u implies binding all LWPs to one CPU with processor_bind\n");
+  printf ("    job_name is one of:\n");
+  for (int ii = 0;; ii++)
+    {
+      struct scripttab *kk = &scripttab[ii];
+      if (kk->test_name == NULL)
+        break;
+      printf ("\t%s\n", kk->test_name);
+    }
+  printf ("    if job_name is omitted, each will be run in turn\n");
+  exit (-1);
+}
+
+void
+resolve_symbols ()
+{
+  global_cond_flag = TRUE;
+  pthread_mutex_lock (&queue_lock);
+  pthread_mutex_trylock (&queue_lock);
+  pthread_mutex_unlock (&queue_lock);
+  sem_post (&global_sema_lock);
+  sem_wait (&global_sema_lock);
+#ifdef CLONE
+  sem_post (&fetch_sema_lock);
+  sem_wait (&fetch_sema_lock);
+#endif
+}
+
+/*  prtime (ttime)
+ *      returns a pointer to a static string in the form:
+ *      Thu  01 Jan 00  00:00:00\0
+ *      01234567890122345678901234
+ *  ttime is a pointer to a UNIX time in seconds since epoch
+ *      library routine localtime() is used
+ */
+char *
+prtime (time_t *ttime)
+{
+  static char *days[] = {
+    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+  };
+  static char *months[] = {
+    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+  };
+
+  static char cvbuf[26];
+
+  /* get the date and time */
+  struct tm *tp = localtime (ttime);
+
+  /* convert to string */
+  sprintf (cvbuf, "%3s  %02d %s %02d  %02d:%02d:%02d",
+           days[tp->tm_wday], tp->tm_mday, months[tp->tm_mon],
+           tp->tm_year % 100, tp->tm_hour, tp->tm_min, tp->tm_sec);
+  return cvbuf;
+}
diff --git a/gprofng/testsuite/gprofng.display/synprog/Makefile b/gprofng/testsuite/gprofng.display/synprog/Makefile
new file mode 100644 (file)
index 0000000..7c50ea2
--- /dev/null
@@ -0,0 +1,66 @@
+#   Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+TARGETS     = synprog so_syn.so so_syx.so
+TARGET      = ./synprog
+ACCT_FILE   = synprog.acct
+
+srcdir = .
+include $(srcdir)/../../lib/Makefile.skel
+
+SRCS = \
+       $(srcdir)/../mttest/gethrtime.c \
+       $(srcdir)/synprog.c \
+       $(srcdir)/callso.c \
+       $(srcdir)/callsx.c \
+       $(srcdir)/endcases.c \
+       $(srcdir)/fitos.c \
+       $(srcdir)/iosyn.c \
+       $(srcdir)/pagethrash.c \
+       $(srcdir)/stopwatch.c \
+       $(NULL)
+
+HDRS= \
+       $(srcdir)/inc_body.h \
+       $(srcdir)/inc_brace.h \
+       $(srcdir)/inc_entry.h \
+       $(srcdir)/inc_exit.h \
+       $(srcdir)/inc_func.h \
+       $(srcdir)/inc_inline.h \
+       $(srcdir)/inc_macro.h \
+       $(srcdir)/stopwatch.h \
+       $(NULL)
+
+
+$(TARGET): $(SRCS) $(HDRS) so_syx.so so_syn.so
+       @echo " ---- Build: $@ -----"
+       $(CC) $(CFLAGS) -o $@ $(SRCS) -ldl -lc -lrt
+
+so_syx.so: $(srcdir)/so_syx.c
+       @echo " ---- Build: $@ -----"
+       $(CC) $(CFLAGS) $(SHAREDOPT) -o $@ $(srcdir)/so_syx.c -lc
+
+so_syn.so: $(srcdir)/so_syn.c
+       @echo " ---- Build: $@ -----"
+       $(CC) $(CFLAGS) $(SHAREDOPT) -o $@ $(srcdir)/so_syn.c -lc
+
+$(EXPERIMENT): $(TARGETS)
+       rm -rf $@
+       $(COLLECT) $(COLLECT_FLAGS) -o $@ $(TARGET) $(TARGET_FLAGS)
+
diff --git a/gprofng/testsuite/gprofng.display/synprog/callso.c b/gprofng/testsuite/gprofng.display/synprog/callso.c
new file mode 100644 (file)
index 0000000..6ff5c99
--- /dev/null
@@ -0,0 +1,152 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+#include "stopwatch.h"
+
+
+#define DYNSOROUTINE    "so_cputime"
+#define DYNSONAME       "./so_syn.so"
+
+/* callso -- dynamically link a shared object, and call a routine in it */
+
+#ifndef NONSHARED
+
+static void *so_object = NULL;
+static void closeso (void);
+
+int
+callso (int k)
+{
+  int i;
+  char buf[1024];
+  char *p;
+  char *q = DYNSONAME;
+  int errnum;
+
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = gethrvtime ();
+
+  /* Log the event */
+  wlog ("start of callso", NULL);
+
+  /* see if already linked */
+  if (so_object != NULL)
+    {
+      fprintf (stderr, "Execution error -- callso: so_object already linked\n");
+      return 0;
+    }
+
+  /* open the dynamic shared object */
+  so_object = NULL;
+  while (so_object == NULL)
+    {
+      so_object = dlopen (DYNSONAME, RTLD_NOW);
+      if (so_object != NULL)
+        break;
+      p = dlerror ();
+      if (q == NULL)
+        q = "DYNSONAME";
+      if (p == NULL)
+        p = "dlerror() returns NULL";
+      errnum = errno;
+      if (errnum == EINTR)
+        continue;   /* retry */
+      else
+        {
+          fprintf (stderr, "Execution error -- callso: dlopen of %s failed--%s, errno=%d (%s)\n",
+                   q, p, errnum, strerror (errnum));
+          return (0);
+        }
+    }
+
+  /* look up the routine name in it */
+  int (*so_routine)() = (int (*)())dlsym (so_object, DYNSOROUTINE);
+  if (so_routine == NULL)
+    {
+      fprintf (stderr, "Execution error -- callso: dlsym %s not found\n",
+               DYNSOROUTINE);
+      return (0);
+    }
+
+  /* invoke the routine */
+  long long count = 0;
+  do
+    {
+      i = (*so_routine)();
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  closeso ();
+  sprintf (buf, "end of callso, %s returned %d", DYNSOROUTINE, i);
+  wlog (buf, NULL);
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog ((gethrtime () - start), (gethrvtime () - vstart), "callso", NULL);
+  return 0;
+}
+
+/* closeso -- close a DSO */
+void
+closeso (void)
+{
+  /* Log the event */
+  wlog ("start of closeso", NULL);
+
+  /* ensure already linked */
+  if (so_object == NULL)
+    {
+      fprintf (stderr, "Execution error -- closeso: so_object not linked\n");
+      return;
+    }
+
+  /* close the dynamic shared object */
+  int rc = dlclose (so_object);
+  if (rc != 0)
+    {
+      fprintf (stderr, "Execution error -- closeso: dlclose() failed--%s\n",
+               dlerror ());
+      return;
+    }
+
+  /* clear the pointer */
+  so_object = NULL;
+  wlog ("end of closeso", NULL);
+  return;
+}
+
+#else /* NONSHARED */
+
+int
+callso (int i)
+{
+  return 0;
+}
+
+void
+closeso (void)
+{
+  return;
+}
+#endif /* NONSHARED */
diff --git a/gprofng/testsuite/gprofng.display/synprog/callsx.c b/gprofng/testsuite/gprofng.display/synprog/callsx.c
new file mode 100644 (file)
index 0000000..5adcf90
--- /dev/null
@@ -0,0 +1,152 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+#include "stopwatch.h"
+
+
+#define DYNSOROUTINE "sx_cputime"
+#define DYNSONAME "./so_syx.so"
+
+/* callsx -- dynamically link a shared object, and call a routine in it */
+
+#ifndef NONSHARED
+
+static void *sx_object = NULL;
+static void closesx (void);
+
+int
+callsx (int k)
+{
+  int i;
+  char buf[1024];
+  char *p;
+  char *q = DYNSONAME;
+  int errnum;
+
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = gethrvtime ();
+
+  /* Log the event */
+  wlog ("start of callsx", NULL);
+
+  /* see if already linked */
+  if (sx_object != NULL)
+    {
+      fprintf (stderr, "Execution error -- callsx: sx_object already linked\n");
+      return 0;
+    }
+
+  /* open the dynamic shared object */
+  /* open the dynamic shared object */
+  sx_object = NULL;
+  while (sx_object == NULL)
+    {
+      sx_object = dlopen (DYNSONAME, RTLD_NOW);
+      if (sx_object != NULL)
+        break;
+      p = dlerror ();
+      if (q == NULL) q = "DYNSONAME";
+      if (p == NULL) p = "dlerror() returns NULL";
+      errnum = errno;
+      if (errnum == EINTR)
+        continue;  /* retry */
+      else
+        {
+          fprintf (stderr, "Execution error -- callso: dlopen of %s failed--%s, errno=%d (%s)\n",
+                   q, p, errnum, strerror (errnum));
+          return (0);
+        }
+    }
+
+  /* look up the routine name in it */
+  int (*sx_routine)() = (int (*)())dlsym (sx_object, DYNSOROUTINE);
+  if (sx_routine == NULL)
+    {
+      fprintf (stderr, "Execution error -- callsx: dlsym %s not found\n",
+               DYNSOROUTINE);
+      return (0);
+    }
+
+  /* invoke the routine */
+  long long count = 0;
+  do
+    {
+      i = (*sx_routine)();
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  closesx ();
+  sprintf (buf, "end of callsx, %s returned %d", DYNSOROUTINE, i);
+  wlog (buf, NULL);
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog ((gethrtime () - start), (gethrvtime () - vstart), "callsx", NULL);
+  return 0;
+}
+
+/* closesx -- close a DSO */
+void
+closesx (void)
+{
+  /* Log the event */
+  wlog ("start of closesx", NULL);
+
+  /* ensure already linked */
+  if (sx_object == NULL)
+    {
+      fprintf (stderr, "Execution error -- closesx: sx_object not linked\n");
+      return;
+    }
+
+#if 0
+  /* close the dynamic shared object */
+  rc = dlclose (sx_object);
+  if (rc != 0)
+    {
+      fprintf (stderr, "Execution error -- closesx: dlclose() failed--%s\n",
+               dlerror ());
+      return;
+    }
+  /* clear the pointer */
+  sx_object = NULL;
+#endif
+  wlog ("end of closesx", NULL);
+  return;
+}
+
+#else /* NONSHARED */
+
+int
+callsx (int i)
+{
+  return 0;
+}
+
+void
+closesx (void)
+{
+  return;
+}
+#endif /* NONSHARED */
diff --git a/gprofng/testsuite/gprofng.display/synprog/check_results.pl b/gprofng/testsuite/gprofng.display/synprog/check_results.pl
new file mode 100755 (executable)
index 0000000..e77d074
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/sh -- # This comment tells perl not to loop!
+
+#   Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+eval 'exec ${PERL:=/usr/dist/exe/perl} -S $0 ${1+"$@"}'
+if 0;
+
+use strict;
+require "acct.pm";
+
+my(@checkTime);
+
+if ("$ENV{DA_io}" eq "on") {
+    @checkTime = ();
+    acct::readAcct("synprog.acct2", @checkTime);
+} else {
+    @checkTime = (1, 2);
+    acct::readAcct("synprog.acct", @checkTime);
+}
+
+acct::read_er_print_out($ARGV[1], -1);
+acct::createDiff();
+exit acct::set_retVal(0);
diff --git a/gprofng/testsuite/gprofng.display/synprog/endcases.c b/gprofng/testsuite/gprofng.display/synprog/endcases.c
new file mode 100644 (file)
index 0000000..5f9fb43
--- /dev/null
@@ -0,0 +1,208 @@
+/* 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 <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "stopwatch.h"
+
+/* endcases - examine some wierd endcases of programming style
+ *  test cases for inlined code, macros, #included code, ...
+ */
+void inc_func (int);
+void inc_brace (int);
+void inc_body (int);
+void inc_entry (int);
+void inc_middle (int);
+void inc_exit (int);
+void macro_code (int);
+void ext_macro_code (int);
+void xinline_code (int);
+static void s_inline_code (int);
+void ext_inline_code (int);
+
+#ifndef NO_INLINE
+void xinline_code () __attribute__ ((always_inline));
+void s_inline_code () __attribute__ ((always_inline));
+#endif
+
+#include "inc_inline.h"
+
+int n;
+int x1M = 1000000;
+int x2M = 2000000;
+int x8M = 8000000;
+
+/* define a macro that burns CPU time */
+#define burncpu(nn) \ 
+        x = 0; \
+        for (j = 0; j < (nn * x8M); j++) { \
+                 x = x + 1; \
+        }
+
+int
+endcases (int n)
+{
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = gethrvtime ();
+
+  /* Log the event */
+  wlog ("start of endcases", NULL);
+
+  if (n == 0)
+    n = 4;
+
+  long long count = 0;
+  do
+    {
+      /* test inlines */
+      xinline_code (n);
+      s_inline_code (n);
+      ext_inline_code (n);
+
+      /* test macros */
+      macro_code (n);
+      ext_macro_code (n);
+
+      /* test various cases of #include'd code */
+      inc_func (n);
+      inc_brace (n);
+      inc_body (n);
+      inc_entry (n);
+      inc_middle (n);
+      inc_exit (n);
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, gethrvtime () - vstart, "endcases", NULL);
+  return 0;
+}
+
+/* spend time in a inline locally-defined */
+void
+xinline_code (int n)
+{
+  int jmax = n * x8M;
+  volatile long x = 0;
+  for (int j = 0; j < jmax; j++)
+    x = x + 1;
+  if (x < 0.0)
+    printf ("ERROR: inline_code(): x < 0 (x=%ld)\n", x);
+}
+
+/* spend time in a static inline locally-defined */
+static void
+s_inline_code (int n)
+{
+  int jmax = n * x8M;
+  volatile long x = 0;
+  for (int j = 0; j < jmax; j++)
+    x = x + 1;
+  if (x < 0.0)
+    printf ("ERROR: s_inline_code(): x < 0 (x=%ld)\n", x);
+}
+
+/* spend time in a macro locally-defined */
+void
+macro_code (int n)
+{
+  int j;
+  volatile long x = 0;
+  burncpu (n);
+  if (x < 0.0)
+    printf ("ERROR: macro_code(): x < 0 (x=%ld)\n", x);
+}
+
+/* spend time in a macro externally-defined */
+#include "inc_macro.h"
+
+void
+ext_macro_code (int n)
+{
+  volatile long x = 0;
+  int j;
+  extburncpu (n);
+  if (x < 0.0)
+    printf ("ERROR: ext_macro_code(): x < 0 (x=%ld)\n", x);
+}
+
+#include "inc_func.h"
+
+void
+inc_brace (int n)
+#include "inc_brace.h"
+
+void
+inc_body (int n) {
+#include "inc_body.h"
+}
+
+void
+inc_entry (int n)
+#include "inc_entry.h"
+{
+  int jmax = n * x8M;
+  volatile float x = 0.0;
+  for (int j = 0; j < jmax; j++)
+    x = x + 1.0;
+  if (x < 0.0)
+    printf ("ERROR: inc_entry(): x < 0 (x=%f)\n", x);
+}
+}
+
+void
+inc_middle (int n)
+{
+  {
+    int jmax = n * x8M;
+    volatile float x = 0.0;
+    for (int j = 0; j < jmax; j++)
+      x = x + 1.0;
+    if (x < 0.0)
+      printf ("ERROR: inc_middle(): loop 1: x < 0 (x=%f)\n", x);
+  }
+#include "inc_body.h"
+  {
+    int jmax = n * x8M;
+    volatile float x = 0.0;
+    for (int j = 0; j < jmax; j++)
+      x = x + 1.0;
+    if (x < 0.0)
+      printf ("ERROR: inc_middle(): loop 2: x < 0 (x=%f)\n", x);
+  }
+}
+
+void
+inc_exit (int n)
+{
+  {
+    int jmax = n * x8M;
+    volatile float x = 0.0;
+    for (int j = 0; j < jmax; j++)
+      x = x + 1.0;
+    if (x < 0.0)
+      printf ("ERROR: inc_exit(): x < 0 (x=%f)\n", x);
+  }
+
+#include "inc_exit.h"
+
diff --git a/gprofng/testsuite/gprofng.display/synprog/fitos.c b/gprofng/testsuite/gprofng.display/synprog/fitos.c
new file mode 100644 (file)
index 0000000..f343876
--- /dev/null
@@ -0,0 +1,78 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include "stopwatch.h"
+
+/* The random number generator below is adapted from Kernighan and Ritchie,
+ *  "C Programming Language", Second Edition, p. 46.
+ */
+
+#define IA 1103515245u
+#define IC 12345u
+#define IM 2147483648u
+
+static unsigned int current_random = 1;
+
+static int
+my_irand (int imax)
+{
+  /* Create a random integer between 0 and imax, inclusive.  i.e. [0..imax] */
+
+  /* Use overflow to wrap */
+  current_random = current_random * IA + IC;
+  int ival = current_random & (IM - 1); /* Modulus */
+  ival = (int) ((float) ival * (float) (imax + 0.999) / (float) IM);
+  return ival;
+}
+
+#define N 6000000
+
+int
+fitos (int n)
+{
+  int i, k, retv;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = gethrvtime ();
+
+  /* Log the event */
+  wlog ("start of fitos", NULL);
+
+  if (n <= 0)
+    n = 1;
+  int max = N * n;
+
+  long long count = 0;
+  do
+    {
+      for (current_random = 1, i = retv = k = 0; i < max; i++)
+        {
+          retv += my_irand (100);
+          k += (current_random & (IM - 1)) >= (1 << 22);
+        }
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+  fprintf (stderr, "\t\t%d out of a total of %d >= 2^22 (%d)\n", k, max, retv);
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog ((gethrtime () - start), (gethrvtime () - vstart), "fitos", NULL);
+  return 0;
+}
diff --git a/gprofng/testsuite/gprofng.display/synprog/inc_body.h b/gprofng/testsuite/gprofng.display/synprog/inc_body.h
new file mode 100644 (file)
index 0000000..2126ea3
--- /dev/null
@@ -0,0 +1,26 @@
+/* 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.  */
+
+{
+  volatile float x = 0.0;
+  int jmax = n * 2000000;
+  for (int j = 0; j < jmax; j++)
+    x = x + 1.0;
+}
diff --git a/gprofng/testsuite/gprofng.display/synprog/inc_brace.h b/gprofng/testsuite/gprofng.display/synprog/inc_brace.h
new file mode 100644 (file)
index 0000000..2126ea3
--- /dev/null
@@ -0,0 +1,26 @@
+/* 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.  */
+
+{
+  volatile float x = 0.0;
+  int jmax = n * 2000000;
+  for (int j = 0; j < jmax; j++)
+    x = x + 1.0;
+}
diff --git a/gprofng/testsuite/gprofng.display/synprog/inc_entry.h b/gprofng/testsuite/gprofng.display/synprog/inc_entry.h
new file mode 100644 (file)
index 0000000..fdf9eed
--- /dev/null
@@ -0,0 +1,24 @@
+/* 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.  */
+
+/*  opening brace of function, second-level include */
+{
+#include "inc_body.h"
diff --git a/gprofng/testsuite/gprofng.display/synprog/inc_exit.h b/gprofng/testsuite/gprofng.display/synprog/inc_exit.h
new file mode 100644 (file)
index 0000000..4ada146
--- /dev/null
@@ -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.  */
+
+/*  closing brace of function, second-level include */
+
+#include "inc_body.h"
+
+}
diff --git a/gprofng/testsuite/gprofng.display/synprog/inc_func.h b/gprofng/testsuite/gprofng.display/synprog/inc_func.h
new file mode 100644 (file)
index 0000000..7b14359
--- /dev/null
@@ -0,0 +1,28 @@
+/* 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.  */
+
+void
+inc_func (int n)
+{
+  volatile float x = 0.0;
+  int jmax = n * 2000000;
+  for (int j = 0; j < jmax; j++)
+    x = x + 1.0;
+}
diff --git a/gprofng/testsuite/gprofng.display/synprog/inc_inline.h b/gprofng/testsuite/gprofng.display/synprog/inc_inline.h
new file mode 100644 (file)
index 0000000..219aee0
--- /dev/null
@@ -0,0 +1,32 @@
+/* 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 NO_INLINE
+void ext_inline_code() __attribute__ ((always_inline));
+#endif
+
+void
+ext_inline_code (int n)
+{
+  volatile long x = 0;
+  int jmax = n * 2000000;
+  for (int j = 0; j < jmax; j++)
+    x = x + 1;
+}
diff --git a/gprofng/testsuite/gprofng.display/synprog/inc_macro.h b/gprofng/testsuite/gprofng.display/synprog/inc_macro.h
new file mode 100644 (file)
index 0000000..c2093da
--- /dev/null
@@ -0,0 +1,26 @@
+/* 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.  */
+
+/* define a macro that burns CPU time */
+#define extburncpu(n) \
+        x = 0.0; \
+        for(j=0; j<n*1000000; j++) { \
+                 x = x + 1.0; \
+        }
diff --git a/gprofng/testsuite/gprofng.display/synprog/iosyn.c b/gprofng/testsuite/gprofng.display/synprog/iosyn.c
new file mode 100644 (file)
index 0000000..278ceea
--- /dev/null
@@ -0,0 +1,614 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+
+#include "stopwatch.h"
+
+/* parameters defining various tasks */
+#define BUFSIZE  16384
+#define NBLKS  1024
+
+#define SIZE ((int)(16*1024*1024))
+unsigned buffer[SIZE];
+extern FILE *fid2;
+
+/*     ioerror - do some erroneous file IO operations */
+int
+ioerror ()
+{
+  FILE *fp; /* FILE pointer for stdio */
+  char *fname = NULL;
+  char *ptr = NULL;
+  int fd; /* file descriptor for raw IO */
+  int fd2; /* file descriptor for raw IO */
+  int stat;
+  char buf[BUFSIZE];
+  unsigned long size = 0;
+  char sfn[23] = "";
+
+  /* Log the regular read */
+  wlog ("start of ioerror", NULL);
+
+  /* fname is set to NULL.
+     Use various calls to create
+     a file.
+   */
+
+  fd = creat (fname, 0666);
+  fd = open (fname, 0666);
+  fd2 = 0;
+  fd = openat (fd2, fname, 0666);
+  fp = fopen (fname, "w");
+  fp = fopen ("/iotest", "w");
+  fp = NULL;
+  stat = fflush (fp);
+  stat = chmod (fname, 755);
+  stat = access (fname, 755);
+  fname = "/tmp/synprogXXXXXX";
+  strncpy (sfn, fname, sizeof (sfn));
+  fd = mkstemp (sfn);
+  stat = unlink (sfn);
+  stat = rename (fname, NULL);
+  unlink (fname);
+  fp = fopen (fname, "w");
+  stat = fclose (fp);
+  stat = fread (buf, 100, 2, fp);
+  stat = fwrite (buf, 100, 2, fp);
+  ptr = fgets (buf, size, fp);
+  read (10000, buf, 100);
+  write (10000, buf, 100);
+  stat = unlink (fname);
+  fname = NULL;
+  stat = mkdir (fname, 755);
+  stat = unlink (fname);
+  /* 
+    These functions cannot be executed
+    if the File Pointer (fp) is set
+    to NULL. They generate segv failure
+    in actual call not inside of 
+    the wrapper.
+
+    stat = fread(buf, size, 2, fp);
+    stat = fwrite(buf, size, 2, fp);
+    ptr = fgets(buf, size, fp);
+    stat = fputs(buf, fp);
+    stat = fprintf(fp, "%d\n", size);
+    stat = fseek(fp, size, size);
+    rewind(fp);
+    ftell(fp);
+    fpos_t pos;
+    stat = fsetpos(fp, &pos);
+    stat = fgetpos(fp, &pos);
+   */
+  return 0;
+}
+
+/*=======================================================*/
+
+/* iofile - do some file io operations */
+int
+iofile ()
+{
+  FILE *fp; /* FILE pointer for stdio */
+  int k; /* temp value for loop */
+  int i;
+  char *buf;
+  hrtime_t start;
+  hrtime_t vstart;
+  char sfn[23] = "";
+  char *fname = "/tmp/synprogXXXXXX";
+  int ret;
+  int readCnt = 0;
+  int bRead = 0;
+  int writeCnt = 0;
+  int bWritten = 0;
+  int otherIOCnt = 0;
+  int bytes = 0;
+
+  start = gethrtime ();
+  vstart = gethrvtime ();
+
+  /* Log the event */
+  bytes = wlog ("start of iofile -- stdio", NULL);
+  bWritten += bytes;
+  writeCnt++;
+
+  strncpy (sfn, fname, sizeof (sfn));
+  ret = mkstemp (sfn);
+  otherIOCnt++;
+  if (ret == -1)
+    {
+      fprintf (stderr, "Unable to make a temporary name\n");
+      exit (1);
+    }
+  bytes = fprintf (stderr, "\tUsing %s as scratch file\n", sfn);
+  bWritten += bytes;
+  writeCnt++;
+
+  /* allocate a buffer for the reading */
+  /* note that this buffer is leaked! */
+  buf = (char *) malloc (BUFSIZE);
+
+  /* open the file */
+  fp = fdopen (ret, "w");
+  otherIOCnt++;
+  if (fp == NULL)
+    {
+      fprintf (stderr, "++ERROR opening %s, error %d\n", sfn, errno);
+      exit (1);
+    }
+
+  /* loop, writing the buffer to the file... */
+  for (i = 0; i < NBLKS; i++)
+    {
+      k = fwrite (buf, sizeof (char), BUFSIZE, fp);
+      writeCnt++;
+      if (k != BUFSIZE)
+        {
+          fprintf (stderr, "++ERROR writing %s, error %d\n", sfn, errno);
+          exit (1);
+        }
+      bWritten += k;
+    }
+
+  fclose (fp);
+  fp = NULL;
+  otherIOCnt++;
+
+  sprintf (buf, "fwrite: %d blocks of %d", i, BUFSIZE);
+  bytes = whrvlog (gethrtime () - start, gethrvtime () - vstart, buf, NULL);
+  bWritten += bytes;
+  writeCnt++;
+
+
+  /* now reopen the file, and read it */
+  start = gethrtime ();
+  vstart = gethrvtime ();
+
+  fp = fopen (sfn, "r");
+  otherIOCnt++;
+  if (fp == NULL)
+    {
+      fprintf (stderr, "++ERROR opening %s, error %d\n", sfn, errno);
+      exit (1);
+    }
+  i = 0;
+  for (;;)
+    {
+      k = fread (buf, sizeof (char), BUFSIZE, fp);
+      readCnt++;
+      if (k < 0)
+        fprintf (stderr, "++ERROR reading %s, error %d\n", sfn, errno);
+
+
+      if (k == 0)
+        {
+          /* close the file */
+          fclose (fp);
+          fp = NULL;
+          otherIOCnt++;
+          break;
+
+        }
+      else if (k != BUFSIZE)
+        {
+          /* short read */
+          sprintf (buf, "\tunexpecter short read %d on %s\n", k, sfn);
+          fprintf (stderr, buf);
+          bRead += k;
+          break;
+        }
+      else
+        {
+          /* bump the block counter */
+          i++;
+          bRead += k;
+        }
+    }
+
+  if (fp != NULL)
+    {
+      fclose (fp);
+      fp = NULL;
+    }
+  sprintf (buf, "fread: %d blocks of %d", i, BUFSIZE);
+  bytes = whrvlog (gethrtime () - start, gethrvtime () - vstart, buf, NULL);
+  bWritten += bytes;
+  writeCnt++;
+
+  bWritten += 99; /* the number of bytes are written by the next fprintf */
+  writeCnt++;
+
+  unlink (sfn);
+  otherIOCnt++;
+  fprintf (fid2, "X   %14d  %14d  %17d  %15d  %17d   iofile\n",
+           bRead, readCnt, bWritten, writeCnt, otherIOCnt);
+  return 0;
+}
+
+/*  iotest - do various io syscalls */
+int
+iotest ()
+{
+  char *fname = "/tmp/foobar";
+  int fd;   /* file descriptor for raw IO */
+  int fd2;  /* file descriptor for raw IO */
+  int k;    /* temp value for loop */
+  char buf[BUFSIZE];
+  unsigned long size = 0;
+  int readCnt = 0;
+  int bRead = 0;
+  int writeCnt = 0;
+  int bWritten = 0;
+  int otherIOCnt = 0;
+  int bytes = 0;
+
+  /* Log the regular read */
+  bytes = wlog ("start of iotest", NULL);
+  bWritten += bytes;
+  writeCnt++;
+
+  /* create an empty file */
+  fd = creat (fname, 0666);
+  otherIOCnt++;
+
+  /* dup the file descriptor */
+  fd2 = dup (fd);
+  otherIOCnt++;
+  close (fd2);
+  otherIOCnt++;
+  close (fd);
+  otherIOCnt++;
+
+  /* now open the empty file */
+  fd = open (fname, O_RDONLY);
+  otherIOCnt++;
+
+  /* loop, reading into the buffer */
+  size = 0;
+  for (;;)
+    {
+      k = read (fd, buf, BUFSIZE);
+      readCnt++;
+      if (k < 0)
+        fprintf (stderr, "++ERROR reading %s, error %d\n", fname, errno);
+      else
+        {
+          size = size + k;
+          bRead += k;
+        }
+      if (k != BUFSIZE)
+        {
+          /* close the file */
+          close (fd);
+          fd = -1;
+          otherIOCnt++;
+          bRead += k;
+
+          /* short eread = EOF */
+          break;
+        }
+    }
+  if (fd != -1)
+    {
+      close (fd);
+      fd = -1;
+    }
+  bWritten += 99; /* the number of bytes are written by the next fprintf */
+  writeCnt++;
+
+  /* remove the file */
+  unlink (fname);
+  otherIOCnt++;
+  fprintf (fid2, "X   %14d  %14d  %17d  %15d  %17d   iotest\n",
+           bRead, readCnt, bWritten, writeCnt, otherIOCnt);
+
+  return 0;
+}
+
+/*
+ * Memory mapping routines-
+ *
+ *  Allocate and deallocate memory using mmap and malloc.
+ *
+ *  There is one parameter--the total number of megabytes to write,
+ *  written in as many 16 megabyte files as are needed
+ */
+
+unsigned char *start = (unsigned char*) 0x80000000;
+unsigned char *stop;
+int nblocks;
+
+void
+memorymap (int megabytes)
+{
+  int readCnt = 0;
+  int bRead = 0;
+  int writeCnt = 0;
+  int bWritten = 0;
+  int otherIOCnt = 0;
+  int bytes;
+
+  /*
+   * First, see how much time it takes to mmap all the files.
+   *
+   * Second, pull in just a few pages of information to see how much
+   * time the "How much IBM do I hold?" question would take.
+   *
+   * Next, compare updating the database shared with updating it private
+   * and then recopying the changed segments.
+
+   * (We could catch the pages that we have altered by mapping the
+   * entire BIS read-only and then punching holes in it via an
+   * mprotect call as we catch segfaults.  This gives us a list
+   * of the pages that we need to write, at the added expense of
+   * handling lots of interrupts.)
+   * (Notice that we don't test the case where we are adding to
+   * the BIS files.  This is an interesting situation as we either
+   * have to open the last page past the last write point or reopen
+   * extendable in some way.  We could do that by opening /dev/zero
+   * with MAP_ANON for addresses above our current usage point.
+   */
+
+  int i;
+  stop = start + 1024 * 1024 * (long long) megabytes;
+
+  printf ("Creating %d random numbers\n", SIZE);
+  for (i = 0; i < SIZE; i++)
+    buffer[i] = random ();  // set pseudo-bis to noise
+  printf ("Done creating random numbers\n");
+
+
+  /*
+   * Write a database consisting of 16 megabyte files.
+   * Each filename contains the memory address into which
+   * the file should be reloaded.
+   */
+
+  printf ("Writing pseudo-bis files\n");
+  unsigned char* base = start;
+  nblocks = 0;
+  for (i = 0; i < megabytes; i += 16)
+    {
+      nblocks++;
+      // write data in 16MB files
+      char filename[256];
+      sprintf (filename, "bistest.%p.%d", base, i);
+      int fd = open (filename, O_CREAT | O_TRUNC | O_WRONLY, 0660);
+      otherIOCnt++;
+      if (fd == -1)
+        {
+          printf ("open of %s failed: %s\n", filename, strerror (errno));
+          exit (0);
+        }
+      bytes = write (fd, buffer, SIZE);
+      bWritten += bytes;
+      writeCnt++;
+      close (fd);
+      otherIOCnt++;
+      printf ("\twrote %d megabytes\n", i + 16);
+      base += 16 * 1024 * 1024;
+    }
+  printf ("Done writing files from %p to %p\n", start, stop);
+
+  int j;
+
+  printf ("Memory map all the files (private)\n");
+  for (i = 0; i < megabytes; i += 16)
+    {
+      unsigned char* base = start;
+      base += i * 1024 * 1024;
+      char filename[256];
+      sprintf (filename, "bistest.%p.%d", base, i);
+      int fd = open (filename, O_RDWR);
+      otherIOCnt++;
+      if (fd < 0)
+        printf ("open of %s failed: %s\n", filename, strerror (errno));
+      unsigned char *mp = (unsigned char*) mmap ((char*) base,
+                                                 SIZE, PROT_READ | PROT_WRITE,
+                                                 MAP_PRIVATE | MAP_FIXED, fd, 0);
+      if (mp == MAP_FAILED || mp != base)
+        {
+          printf ("mmap of %s failed: %s\n", filename, strerror (errno));
+          exit (1);
+        }
+
+      printf ("mapped %d bytes at %p\n", SIZE, base);
+      close (fd); // mmap will hold the file open for us
+      otherIOCnt++;
+    }
+
+  printf ("Mapping done\n");
+  fflush (stdout);
+  otherIOCnt++;
+
+  int ranlimit = 1000;
+  printf ("Access %d bytes at random\n", ranlimit);
+  int sum = 0;
+  for (i = 0; i < ranlimit; i++)
+    {
+      unsigned char *where = start +
+              (((unsigned long) random ()) % (stop - start));
+      sum += (int) *where;
+    }
+  printf ("Random byte access done\n");
+
+  ranlimit = 1000;
+  int ranrange = 256;
+  printf ("Alter %d random locations, %d bytes each (private)\n",
+          ranlimit, ranrange);
+
+  for (i = 0; i < ranlimit; i++)
+    {
+      unsigned char *where = start +
+              (((unsigned long) random ()) % (stop - start));
+      for (j = 0; j < ranrange; j++)
+        *where++ = j;
+    }
+
+  printf ("Memory alteration done\n");
+  fflush (stdout);
+  otherIOCnt++;
+
+  printf ("Copy all memory back to disk\n");
+
+  for (i = 0; i < megabytes; i += 16)
+    {
+      unsigned char* base = start;
+      base += i * 1024 * 1024;
+      char filename[256];
+      sprintf (filename, "bistest2.%p.%d", base, i);
+      int fd = open (filename, O_RDWR | O_CREAT | O_TRUNC, 0660);
+      otherIOCnt++;
+      if ((bytes = write (fd, base, SIZE)) == -1)
+        {
+          printf ("write of %s failed: %s\n", filename, strerror (errno));
+          exit (1);
+        }
+      bWritten += bytes;
+      writeCnt++;
+      close (fd);
+      otherIOCnt++;
+    }
+
+  printf ("Disk copy complete\n");
+  fflush (stdout);
+  otherIOCnt++;
+
+  printf ("Unmap all segments\n");
+  for (i = 0; i < megabytes; i += 16)
+    {
+      unsigned char* base = start;
+      base += i * 1024 * 1024;
+      if (munmap ((char*) base, SIZE) == -1)
+        {
+          printf ("munmap failed: %s\n", strerror (errno));
+          exit (1);
+        }
+      printf ("unmapped %d bytes at %p\n", SIZE, base);
+    }
+  printf ("Segment unmapping complete\n");
+  fflush (stdout);
+  otherIOCnt++;
+
+  printf ("Remap all segments as shared\n");
+  for (i = 0; i < megabytes; i += 16)
+    {
+      unsigned char* base = start;
+      base += i * 1024 * 1024;
+      char filename[256];
+      sprintf (filename, "bistest.%p.%d", base, i);
+      int fd = open (filename, O_RDWR);
+      otherIOCnt++;
+      char* mp = mmap ((char*) base, SIZE, PROT_READ | PROT_WRITE,
+                       MAP_SHARED | MAP_FIXED, fd, 0);
+      if (mp == MAP_FAILED || (unsigned char*) mp != base)
+        {
+          printf ("re mmap of %s failed: %s\n", filename, strerror (errno));
+          exit (1);
+        }
+      printf ("remapped %d bytes at %p\n", SIZE, base);
+      close (fd); // mmap will hold the file open for us
+      otherIOCnt++;
+    }
+  printf ("Remapping complete\n");
+  fflush (stdout);
+  otherIOCnt++;
+
+  ranlimit = 1000;
+  ranrange = 256;
+  printf ("Alter %d random locations, %d bytes each (shared)\n",
+          ranlimit, ranrange);
+  for (i = 0; i < ranlimit; i++)
+    {
+      unsigned char* where = start +
+              (((unsigned long) random ()) % (stop - start));
+      for (j = 0; j < ranrange; j++)
+        *where++ = j;
+    }
+  printf ("Memory alteration done\n");
+  fflush (stdout);
+  otherIOCnt++;
+
+  printf ("Unmap all segments\n");
+  for (i = 0; i < megabytes; i += 16)
+    {
+      unsigned char *base = start;
+      base += i * 1024 * 1024;
+      if (munmap ((char*) base, SIZE) == -1)
+        {
+          printf ("munmap failed: %s\n", strerror (errno));
+          exit (1);
+        }
+      printf ("unmapped %d bytes at %p\n", SIZE, base);
+    }
+  printf ("Segment unmapping complete\n");
+  fflush (stdout);
+  otherIOCnt++;
+
+  base = start;
+
+  for (i = 0; i < megabytes; i += 16)
+    {
+      // write data in 16MB files
+      char filename[256];
+      sprintf (filename, "bistest.%p.%d", base, i);
+      if (unlink (filename) != 0)
+        {
+          printf ("unlink of %s failed: %s\n", filename, strerror (errno));
+        }
+      base += 16 * 1024 * 1024;
+      otherIOCnt++;
+    }
+
+  for (i = 0; i < megabytes; i += 16)
+    {
+      unsigned char* base = start;
+      base += i * 1024 * 1024;
+      char filename[256];
+      sprintf (filename, "bistest2.%p.%d", base, i);
+      if (unlink (filename) != 0)
+        {
+          printf ("unlink of %s failed: %s\n", filename, strerror (errno));
+        }
+      otherIOCnt++;
+    }
+  bWritten += 102; /* the number of bytes are written by the next fprintf */
+  writeCnt++;
+
+  fflush (fid2);
+  otherIOCnt++;
+
+  /* Record accounting record */
+  fprintf (fid2, "X   %14d  %14d  %17d  %15d  %17d   memorymap\n",
+           bRead, readCnt, bWritten, writeCnt, otherIOCnt);
+  printf ("Deleted scratch files\n");
+}
diff --git a/gprofng/testsuite/gprofng.display/synprog/pagethrash.c b/gprofng/testsuite/gprofng.display/synprog/pagethrash.c
new file mode 100644 (file)
index 0000000..a909600
--- /dev/null
@@ -0,0 +1,75 @@
+/* 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 <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "stopwatch.h"
+
+/*=======================================================*/
+
+/* pagethrash - allocate some memory, and thrash around in it */
+int
+pagethrash (int thrashmb)
+{
+  char buf[1024];
+
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = gethrvtime ();
+
+  /* Log the event */
+  wlog ("start of pagethrash", NULL);
+
+  /* Start a stopwatch */
+  stopwatch_t *w = stpwtch_alloc ("pagethrash", 0);
+
+  /* compute the size */
+  unsigned long size = thrashmb * 1024 * 1024;
+  int pagesize = getpagesize ();
+  void *space = malloc (size + pagesize);
+  if (space == NULL)
+    {
+      fprintf (stderr, "\tpagethrash failed; can't get %ld bytes.\n", size);
+      exit (1);
+    }
+
+  /* round address to page boundary */
+  unsigned long loc = (((unsigned long) space + pagesize - 1) & ~(pagesize - 1));
+  long npages = size / pagesize;
+
+  /* touch all the pages to force them in */
+  for (long i = 0; i < npages; i++)
+    {
+      stpwtch_start (w);
+      *(int *) (loc + i * pagesize) = i;
+      stpwtch_stop (w);
+    }
+
+  /* now free up the space */
+  free (space);
+
+  /* print the timing results */
+  stpwtch_print (w);
+  free ((void *) w);
+
+  sprintf (buf, "pagethrash: %ld pages", npages);
+  whrvlog (gethrtime () - start, gethrvtime () - vstart, buf, NULL);
+  return 0;
+}
diff --git a/gprofng/testsuite/gprofng.display/synprog/so_syn.c b/gprofng/testsuite/gprofng.display/synprog/so_syn.c
new file mode 100644 (file)
index 0000000..6fc5aa6
--- /dev/null
@@ -0,0 +1,69 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include "stopwatch.h"
+
+static void so_burncpu ();
+
+int
+so_cputime ()
+{
+  wlog ("start of so_cputime", NULL);
+
+  /* put a memory leak in here */
+  (void) malloc (13);
+
+  fprintf (stderr, "so_burncpu @ 0x%08x\n", (unsigned int) so_burncpu);
+  so_burncpu ();
+
+  wlog ("end of so_cputime", NULL);
+  return 13;
+}
+
+void so_init () __attribute__ ((constructor));
+
+void
+so_init ()
+{
+  fprintf (stderr, "so_init executed\n");
+}
+
+/*     so_burncpu - loop to use a bunch of user time */
+void
+so_burncpu ()
+{
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = gethrvtime ();
+  volatile float x = 0.;     /* temp variable for f.p. calculation */
+  long long count = 0;
+  do
+    {
+      x = 0.0;
+      for (int j = 0; j < 100000; j++)
+        x = x + 1.0;
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, gethrvtime () - vstart, "so_burncpu", NULL);
+}
diff --git a/gprofng/testsuite/gprofng.display/synprog/so_syx.c b/gprofng/testsuite/gprofng.display/synprog/so_syx.c
new file mode 100644 (file)
index 0000000..ae7da6f
--- /dev/null
@@ -0,0 +1,68 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include "stopwatch.h"
+
+static void sx_burncpu ();
+
+int
+sx_cputime ()
+{
+  wlog ("start of sx_cputime", NULL);
+
+  /* put a memory leak in here */
+  (void) malloc (13);
+
+  fprintf (stderr, "sx_burncpu @ 0x%08x\n", (unsigned int) sx_burncpu);
+  sx_burncpu ();
+  wlog ("end of sx_cputime", NULL);
+  return 13;
+}
+
+void sx_init () __attribute__ ((constructor));
+
+void
+sx_init ()
+{
+  fprintf (stderr, "sx_init executed\n");
+}
+
+/* sx_burncpu - loop to use a bunch of user time */
+void
+sx_burncpu ()
+{
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = gethrvtime ();
+  volatile float x = 0.;    /* temp variable for f.p. calculation */
+  long long count = 0;
+  do
+    {
+      x = 0.0;
+      for (int j = 0; j < 100000; j++)
+        x = x + 1.0;
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, gethrvtime () - vstart, "sx_burncpu", NULL);
+}
diff --git a/gprofng/testsuite/gprofng.display/synprog/stopwatch.c b/gprofng/testsuite/gprofng.display/synprog/stopwatch.c
new file mode 100644 (file)
index 0000000..5cb5281
--- /dev/null
@@ -0,0 +1,294 @@
+/* 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "stopwatch.h"
+
+static char *prhrdelta (hrtime_t);
+static char *prhrvdelta (hrtime_t);
+void init_micro_acct ();
+
+/* stopwatch routines */
+void
+stpwtch_calibrate ()
+{
+  struct timeval ttime;
+  char buf[1024];
+
+  (void) gettimeofday (&ttime, NULL);
+  time_t secs = (time_t) ttime.tv_sec;
+  sprintf (buf, "%s Stopwatch calibration", prtime (&secs));
+  wlog (buf, NULL);
+
+  init_micro_acct ();
+  stopwatch_t *inner = stpwtch_alloc ("inner", 0);
+  stopwatch_t *outer = stpwtch_alloc ("outer", 0);
+  for (int i = 0; i < 1000; i++)
+    {
+      stpwtch_start (outer);
+      stpwtch_start (inner);
+      stpwtch_stop (inner);
+      stpwtch_stop (outer);
+    }
+  stpwtch_print (inner);
+  stpwtch_print (outer);
+  free ((void *) inner);
+  free ((void *) outer);
+}
+
+stopwatch_t *
+stpwtch_alloc (char *name, int histo)
+{
+  stopwatch_t *w = (stopwatch_t *) malloc (sizeof (stopwatch_t));
+  if (w == NULL)
+    {
+      fprintf (stderr, "stpwtch_alloc(%s, %d): malloc failed\n", name, histo);
+      return NULL;
+    }
+  w->sum = 0.;
+  w->sumsq = 0.;
+  w->count = 0;
+  w->min = 0;
+  w->last = 0;
+  w->name = strdup (name);
+  stpwtch_start (w);
+  w->begin = w->start;
+
+  return w;
+}
+
+void
+stpwtch_start (stopwatch_t *w)
+{
+  w->start = gethrtime ();
+}
+
+void
+stpwtch_stop (stopwatch_t *w)
+{
+  if (w->start == 0)    /* if never started, ignore the call */
+    return;
+
+  /* get stopping high-res time */
+  w->tempus = gethrtime ();
+
+  /* bump count of stops */
+  w->count++;
+
+  /* compute the delta for this call */
+  w->delta = w->tempus - w->start;
+
+  /* add in this one */
+  w->last = (double) (w->delta);
+  w->sum = w->sum + w->last;
+  w->sumsq = w->sumsq + w->last * w->last;
+
+  if (w->max == 0)
+    w->max = w->last;
+  else if (w->max < w->last)
+    w->max = w->last;
+  if (w->min == 0)
+    w->min = w->last;
+  else if (w->min > w->last)
+    w->min = w->last;
+
+  /* show stopwatch stopped */
+  w->start = 0;
+}
+
+void
+stpwtch_print (stopwatch_t *w)
+{
+  char cvdbuf[1024];
+
+  /* get stopping high-res time */
+  w->tempus = gethrtime ();
+  double duration = (double) (w->tempus - w->begin);
+
+  if (w->count == 0)
+    sprintf (cvdbuf, "       0.       s. ( 0. %% of %12.6f s.) -- %s\n",
+             (duration / 1000000000.), w->name);
+  else if (w->count == 1)
+    sprintf (cvdbuf, "    %12.6f s. (%4.1f %%%% of %.6f s.) -- %s\n",
+             w->sum / 1000000000., (100. * w->sum) / duration,
+             duration / 1000000000., w->name);
+  else
+    sprintf (cvdbuf,
+             "    %12.6f s.  (%4.1f %%%% of %.6f s.) -- %s\n\tN = %d,"
+             " avg = %.3f us., min = %.3f, max = %.3f\n",
+             w->sum / 1000000000., (100. * w->sum) / duration,
+             duration / 1000000000., w->name, w->count,
+             w->sum / 1000. / ((double) (w->count > 0 ? w->count : 1)),
+             ((double) w->min / 1000.), ((double) w->max / 1000.));
+  fprintf (stderr, cvdbuf);
+}
+
+/* hrtime routines */
+int
+whrlog (hrtime_t delta, char *event, char *string)
+{
+  char buf[1024];
+  if (string == NULL)
+    sprintf (buf, "  %s secs. in %s\n", prhrdelta (delta), event);
+  else
+    sprintf (buf, "  %s secs. in %s\n\t%s\n", prhrdelta (delta), event, string);
+  int bytes = fprintf (stderr, "%s", buf);
+  return bytes;
+}
+
+/* hrtime routines */
+int
+whrvlog (hrtime_t delta, hrtime_t vdelta, char *event, char *string)
+{
+  char buf[1024];
+  if (string == NULL)
+    sprintf (buf, "  %s wall-secs., %s CPU-secs., in %s\n",
+             prhrdelta (delta), prhrvdelta (vdelta), event);
+  else
+    sprintf (buf, "  %s wall-secs., %s CPU-secs., in %s\n\t%s\n",
+             prhrdelta (delta), prhrvdelta (vdelta), event, string);
+  int bytes = fprintf (stderr, "%s", buf);
+  return bytes;
+}
+
+/* prhrdelta (hrtime_t delta)
+ *  returns a pointer to a static string in the form:
+ *      sec.micros
+ *       1.123456
+ *      0123456789
+ *
+ *  prhrvdelta is the same, but uses a different static buffer
+ */
+static char *
+prhrdelta (hrtime_t delta)
+{
+  static char cvdbuf[26];
+
+  /* convert to seconds */
+  double tempus = ((double) delta) / (double) 1000000000.;
+  sprintf (cvdbuf, "%10.6f", tempus);
+  return cvdbuf;
+}
+
+static char *
+prhrvdelta (hrtime_t delta)
+{
+  static char cvdbuf[26];
+
+  /* convert to seconds */
+  double tempus = ((double) delta) / (double) 1000000000.;
+  sprintf (cvdbuf, "%10.6f", tempus);
+  return cvdbuf;
+}
+
+/* time of day routines */
+
+/* starting time - first timestamp; initialized on first call */
+static struct timeval starttime = {0, 0};
+static struct timeval ttime;        /* last-recorded timestamp */
+static struct timeval deltatime;    /* delta of last-rec'd timestamp */
+
+static void
+snaptod ()
+{
+  (void) gettimeofday (&ttime, NULL);
+  if (starttime.tv_sec == 0)
+    starttime = ttime;
+
+  deltatime.tv_sec = ttime.tv_sec - starttime.tv_sec;
+  deltatime.tv_usec = ttime.tv_usec - starttime.tv_usec;
+  while (deltatime.tv_usec < 0)
+    {
+      deltatime.tv_sec--;
+      deltatime.tv_usec += 1000000;
+    }
+}
+
+int
+wlog (char *event, char *string)
+{
+  char buf[1024];
+
+  snaptod ();
+  if (string == NULL)
+    sprintf (buf, "%s ===== (%d) %s\n", prdelta (deltatime),
+             (int) getpid (), event);
+  else
+    sprintf (buf, "%s ===== (%d) %s\n\t%s\n", prdelta (deltatime),
+             (int) getpid (), event, string);
+  int bytes = fprintf (stderr, "%s", buf);
+  return bytes;
+}
+
+/* prtime (ttime)
+ *  returns a pointer to a static string in the form:
+ *      Thu  01 Jan 90  00:00:00\0
+ *      01234567890122345678901234
+ *
+ *  ttime is a pointer to a UNIX time in seconds since epoch
+ *  library routine localtime() is used
+ */
+char *
+prtime (time_t *ttime)
+{
+  static char *days[] = {
+    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+  };
+  static char *months[] = {
+    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+  };
+  static char cvbuf[26];
+
+  /* get the date and time */
+  struct tm *tp = localtime (ttime);
+
+  /* convert to string */
+  sprintf (cvbuf, "%3s  %02d %s %02d  %02d:%02d:%02d", days[tp->tm_wday],
+           tp->tm_mday, months[tp->tm_mon], tp->tm_year % 100,
+           tp->tm_hour, tp->tm_min, tp->tm_sec);
+  return cvbuf;
+}
+
+char *
+prdelta (struct timeval tempus)
+{
+  static char cvdbuf[26];
+  while (tempus.tv_usec < 0)
+    {
+      tempus.tv_sec--;
+      tempus.tv_usec += 1000000;
+    }
+  long seconds = tempus.tv_sec % 60;
+  long minutes = tempus.tv_sec / 60;
+  long hours = minutes / 60;
+  minutes = minutes % 60;
+  sprintf (cvdbuf, "%02ld:%02ld:%02ld.%03ld ",
+           hours, minutes, seconds, (long) tempus.tv_usec / 1000);
+  return cvdbuf;
+}
diff --git a/gprofng/testsuite/gprofng.display/synprog/stopwatch.h b/gprofng/testsuite/gprofng.display/synprog/stopwatch.h
new file mode 100644 (file)
index 0000000..704b165
--- /dev/null
@@ -0,0 +1,61 @@
+/* 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 _STOPWATCH_
+#define _STOPWATCH_
+
+#include <time.h>
+#include <sys/time.h>
+
+typedef int processorid_t;
+typedef long long hrtime_t;
+typedef struct timespec timespec_t;
+extern hrtime_t gethrtime ();
+extern hrtime_t gethrvtime ();
+
+extern double testtime;
+char *prtime (time_t *t);
+char *prdelta (struct timeval t);
+int wlog (char *, char *);
+int whrlog (hrtime_t delta, char *, char *);
+int whrvlog (hrtime_t delta, hrtime_t vdelta, char *, char *);
+
+typedef struct stopwatch
+{
+  double sum;       /* in nanoseconds */
+  double sumsq;     /* in (nanoseconds ** 2) */
+  double last;      /* in nanoseconds */
+  hrtime_t begin;
+  hrtime_t start;
+  hrtime_t tempus;
+  hrtime_t delta;
+  hrtime_t min;
+  hrtime_t max;
+  int count;
+  char *name;
+} stopwatch_t;
+
+stopwatch_t *stpwtch_alloc (char *, int);
+void stpwtch_calibrate ();
+void stpwtch_start (stopwatch_t *);
+void stpwtch_stop (stopwatch_t *);
+void stpwtch_print (stopwatch_t *);
+
+#endif
diff --git a/gprofng/testsuite/gprofng.display/synprog/synprog.c b/gprofng/testsuite/gprofng.display/synprog/synprog.c
new file mode 100644 (file)
index 0000000..a5361a4
--- /dev/null
@@ -0,0 +1,1823 @@
+/* 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.  */
+
+/* synprog.c - synthetic program to use for testing performance tools */
+#define _GNU_SOURCE
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/ucontext.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <sched.h>
+#include <sys/resource.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include "stopwatch.h"
+
+int get_ncpus ();
+int get_clock_rate ();
+void acct_init (char *);        /* initialize accounting */
+void iotrace_init (char *);     /* initialize IO trace accounting */
+void commandline (char *);      /* routine execute a scenario */
+void forkcopy (char *, int);    /* fork copy of self to run string */
+int clonecopy (void *);
+#define CLONE_STACK_SIZE    8388608
+#define CLONE_TLS_SIZE      4096
+#define CLONE_RED_SIZE      4096
+#define CLONE_IO            0x80000000      /* Clone io context */
+void forkchild (char *);    /* fork child to run string */
+void reapchildren (void);   /* reap all children */
+void reapchild (int);       /* reap a child after getting SIGCLD */
+void check_sigmask ();      /* check that SIGPROF and SIGEMT are not masked */
+void masksig ();            /* real code to mask SIGPROF and SIGEMT */
+
+hrtime_t progstart;
+hrtime_t progvstart;
+hrtime_t gethrustime ();
+static int include_system_time = 0;
+
+static hrtime_t
+getmyvtime ()
+{
+  if (include_system_time == 0)
+    return gethrvtime ();
+  return gethrustime ();
+}
+
+void (*sigset (int sig, void (*disp)(int)))(int);
+#define ITIMER_REALPROF ITIMER_REAL
+/* Linux needs to have this defined for RTLD_NEXT and RTLD_DEFAULT */
+/* If the first argument of `dlsym' or `dlvsym' is set to RTLD_NEXT */
+#define RTLD_NEXT      ((void *) -1l)
+/* If the first argument to `dlsym' or `dlvsym' is set to RTLD_DEFAULT */
+#define RTLD_DEFAULT   ((void *) 0)
+
+FILE *fid;
+FILE *fid2;
+double testtime = 3.0;
+static char acct_file[128];
+static char new_name[128];
+static char child_name[128];
+
+/* descendant process tracking */
+static unsigned syn_fork = 0;
+static unsigned syn_exec = 0;
+static unsigned syn_combo = 0;
+
+/* various behavior routines */
+int bounce (int);       /* bounce with a->b->a->b-> ... */
+int callso (int);       /* so load test */
+int callsx (int);       /* alternate so load test */
+int correlate (int);    /* test correlation with profiling */
+int cputime (int);      /* use a bunch of user cpu time (fp) */
+int doabort (int);      /* force a SEGV by dereferencing NULL */
+int dousleep (int);     /* loop with a usleep call */
+int endcases (int);     /* test various code construct endcases */
+int fitos (int);        /* test various code construct endcases */
+int gpf (int);          /* show gprof fallacy */
+int hrv (int);          /* gethrvtime calls */
+int icputime (int);     /* use a bunch of user cpu time (long) */
+int iofile (int);       /* do operations on a temporary file */
+int iotest (int);       /* do various io system calls */
+int ioerror (int);      /* do various erroneous io system calls */
+int ldso (int);         /* use a bunch of time in ld.so */
+int masksignals (int);  /* mask the SIGEMT and SIGPROF signals */
+int memorymap (int);    /* do mmap operation for io tracing */
+int muldiv (int);       /* do integer multiply/divide for a time */
+int naptime (int);      /* sleep for a time */
+int pagethrash (int);   /* thrash around in memory */
+int recurse (int);      /* recursion test */
+int recursedeep (int);  /* deep recursion test */
+int sched (int);        /* loop over sched_yield calls */
+int sigtime (int);      /* use a bunch of time in a signal handler */
+int synccall (int);     /* loop over sync() system calls */
+int systime (int);      /* use a bunch of system time */
+int tailcallopt (int);  /* tail call optimization test */
+int underflow (int);    /* force underflow arithmetic */
+int unwindcases (int);  /* test various unwind corner cases */
+
+int itimer_realprof (int); /* mess with itimer ITIMER_REALPROF */
+int sigprof (int);      /* mess with SIGPROF sigaction */
+int sigprofh (int);     /* mess with SIGPROF handler */
+int do_chdir (int);     /* do a chdir() */
+int do_exec (int);      /* do an exec() call */
+int do_popen (int);     /* do a popen() call */
+int do_system (int);    /* do a system() call */
+int do_forkexec (int);  /* do a fork()+exec() call combo */
+int
+do_vforkexec (int);     /* do a vfork()+exec() call combo */
+
+/* lookup table for behavior scripts */
+struct scripttab
+{
+  char *name;
+  int (*function)(int);
+  char *acctname;
+  int param;
+  int noverify;
+};
+
+static int CLONE_FLAGS[] = {
+  SIGCHLD,
+  CLONE_FILES | CLONE_FS | CLONE_SYSVSEM | CLONE_IO | SIGCHLD
+};
+
+/* the default script */
+static char DEFAULT_COMMAND[] =
+        "icpu.md.cpu.rec.recd.dousl.gpf.fitos.ec.tco.b.nap.uf."
+        "sys.sig.so.sx.so.sched.uwdc";
+
+struct scripttab scripttab[] = {
+  {"abt",       doabort,        "doabort",      0,  0},
+  {"b",         bounce,         "bounce",       0,  0},
+  {"c",         correlate,      "correlate",    0,  0},
+  {"chdir",     do_chdir,       "chdir",        0,  0},
+  {"chdirX",    do_chdir,       "chdir",        -1, 0},
+  {"cpu",       cputime,        "cputime",      0,  0},
+  {"dousl",     dousleep,       "dousleep",     0,  1},
+  {"ec",        endcases,       "endcases",     0,  0},
+  {"exec",      do_exec,        "exec",         0,  0},
+  {"execX",     do_exec,        "do_exec",      -1, 0},
+  {"fitos",     fitos,          "fitos",        0,  1},
+  {"gpf",       gpf,            "gpf",          0,  0},
+  {"hrv",       hrv,            "hrv",          0,  0},
+  {"icpu",      icputime,       "icputime",     0,  0},
+  {"iofile",    iofile,         "iofile",       0,  0},
+  {"iotest",    iotest,         "iotest",       0,  0},
+  {"ioerror",   ioerror,        "ioerror",      0,  0},
+  {"itimer",    itimer_realprof, "itimer",      1,  0},
+  {"itimer0",   itimer_realprof, "itimer",      0,  0},
+  {"ldso",      ldso,           "ldso",         0,  0},
+  {"masksig",   masksignals,    "masksig",      0,  0},
+  {"md",        muldiv,         "muldiv",       0,  0},
+  {"memorymap", memorymap,      "memorymap",    100, 0},
+  {"nap",       naptime,        "naptime",      0,  0},
+  {"pg",        pagethrash,     "pagethrash",   32, 0},
+  {"popen",     do_popen,       "popen",        0,  0},
+  {"popenX",    do_popen,       "popen",        -1, 0},
+  {"rec",       recurse,        "recurse",      50, 0},
+  {"recd",      recursedeep,    "<Truncated-stack>", 500, 0},
+  {"sched",     sched,          "sched",        0,  1},
+  {"so",        callso,         "callso",       0,  0},
+  {"sx",        callsx,         "callsx",       0,  0},
+  {"sig",       sigtime,        "sigtime",      0,  1},
+  {"sigprof",   sigprof,        "sigprof",      1,  0},
+  {"sigprof0",  sigprof,        "sigprof",      0,  0},
+  {"sigprofh",  sigprofh,       "sigprofh",     1,  0},
+  {"sigprofh0", sigprofh,       "sigprofh",     0,  0},
+  {"sync",      synccall,       "synccall",     0,  1},
+  {"sys",       systime,        "systime",      0,  1},
+  {"system",    do_system,      "system",       0,  0},
+  {"systemX",   do_system,      "do_system",    -1, 0},
+  {"tco",       tailcallopt,    "tailcallopt",  0,  0},
+  {"uf",        underflow,      "underflow",    0,  1},
+  {"forkexec",  do_forkexec,    "forkexec",     0,  0},
+  {"vforkexec", do_vforkexec,   "vforkexec",    0,  0},
+  {"uwdc",      unwindcases,    "unwindcases",  0,  0},
+  {NULL, NULL, NULL, 0, 0}
+};
+
+int
+main (int argc, char **argv)
+{
+  int i;
+  hrtime_t start;
+  hrtime_t vstart;
+  char *name;
+  char buf[1024];
+  char arglist[4096];
+
+  // need a more robust test of whether system HWC events are being counted
+  if (getenv ("TILDECLAUSE"))
+    include_system_time = 1;
+  progstart = gethrtime ();
+  progvstart = getmyvtime ();
+  name = getenv ("SP_COLLECTOR_TEST_TIMER");
+  if (name)
+    {
+      testtime = atof (name);
+      if (testtime <= 0)
+        testtime = 1.0;
+    }
+  name = getenv ("_SP_NAME");
+  if (name == NULL || strlen (name) == 0)
+    strcpy (acct_file, "synprog.acct");
+  else
+    strcpy (acct_file, name);
+
+  strcpy (arglist, argv[0]);
+  for (i = 1; i < argc; i++)
+    {
+      strcat (arglist, " ");
+      strcat (arglist, argv[i]);
+    }
+
+  sprintf (buf, "%s run", argv[0]);
+  wlog (buf, NULL);
+
+  int ncpus = get_ncpus ();
+  acct_init (acct_file);
+  iotrace_init ("synprog.acct2");
+
+  /* Start a timer */
+  start = gethrtime ();
+  vstart = getmyvtime ();
+
+#ifndef NO_MS_ACCT
+  stpwtch_calibrate ();
+#endif
+
+  if (argc == 1)
+    commandline (DEFAULT_COMMAND);
+  else
+    {
+      i = 2;
+      while (i < argc)
+        {
+          forkcopy (argv[i], i - 1);
+          i++;
+        }
+
+      /* do the last one ourself */
+      commandline (argv[1]);
+    }
+  reapchildren ();
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, buf, NULL);
+  fflush (fid);
+  fflush (fid2);
+  fclose (fid);
+  fclose (fid2);
+  return 0;
+}
+
+/* acct_init: initialize accounting */
+void
+acct_init (char *acct_file)
+{
+  fid = fopen (acct_file, "w");
+  if (fid == NULL)
+    {
+      fprintf (stderr, "Open of %s for output failed: %s\n",
+               acct_file, strerror (errno));
+      exit (1);
+    }
+  fprintf (fid, "MHz: %d\n", get_clock_rate ());
+  fprintf (fid, "X   Incl. Total  Incl. CPU  Name\n");
+  fflush (fid);
+
+  /* write a record for <Unknown>, which should have zero times */
+  fprintf (fid, "X   %6.3f        %6.3f       %s\n", 0.0, 0.0, "<Unknown>");
+
+  /* set up to reap any children */
+  (void) sigset (SIGCHLD, reapchild);
+  /* verify the signal mask */
+}
+
+/* iotrace_init: initialize IO trace accounting */
+void
+iotrace_init (char *acct_file)
+{
+  fid2 = fopen (acct_file, "w");
+  if (fid2 == NULL)
+    {
+      fprintf (stderr, "Open of %s for output failed: %s\n",
+               acct_file, strerror (errno));
+      exit (1);
+    }
+  fprintf (fid2, "X   Incl.BytesRead  Incl.ReadCount  ");
+  fprintf (fid2, "Incl.BytesWritten  Incl.WriteCount  ");
+  fprintf (fid2, "Incl.OtherIOCount   Name\n");
+  fflush (fid2);
+}
+
+/* commandline -- process a command line string:
+ *     verbs are separated by a . character; each verb is looked-up
+ *     in a table, and the routine to process it, and argument fetched.
+ *     the routine is called.
+ */
+void
+commandline (char *cmdline)
+{
+  char *p;
+  char *j;
+  char prevj;
+  struct scripttab *k;
+  char buf[1024];
+  hrtime_t pstart;
+  hrtime_t pvstart;
+  hrtime_t pend;
+  hrtime_t pvend;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog (" Begin commandline", cmdline);
+
+  p = cmdline;
+  while (*p != 0)
+    {
+      /* find the terminator for this verb (a . or NULL) */
+      j = p;
+      while (*j != 0 && *j != '.')
+        j++;
+      prevj = *j;
+      *j = 0;
+
+      /* now look up the phase in the table */
+      for (k = &scripttab[0];; k++)
+        {
+          if (k->name == NULL)
+            break;
+          if (strcmp (p, k->name) == 0)
+            {
+              /* found a match */
+              pstart = gethrtime ();
+              pvstart = getmyvtime ();
+              (k->function)(k->param);
+              pend = gethrtime ();
+              pvend = getmyvtime ();
+              fprintf (fid, "%c   %6.3f        %6.3f       %s\n",
+                       k->noverify == 0 ? 'X' : 'Y',
+                       (double) (pend - pstart) / (double) 1000000000.,
+                       (double) (pvend - pvstart) / (double) 1000000000.,
+                       k->acctname);
+              fflush (fid);
+              break;
+            }
+        }
+      if (k->name == NULL)
+        {
+          sprintf (buf, "++ ignoring `%s'\n", p);
+          fprintf (stderr, buf);
+        }
+
+      /* continue processing */
+      *j = prevj;
+      p = j;
+      if (prevj != 0)
+        p++;
+    }
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "commandline", cmdline);
+}
+
+int
+clonecopy (void * script)
+{
+  syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
+
+  strcpy (acct_file, child_name);
+  /*printf("_SP_NAME=\"%s\" (for clone-child)\n", acct_file);*/
+  acct_init (acct_file);
+
+  /* execute the script */
+  commandline ((char *) script);
+
+  /* reap the child's descendants */
+  reapchild (0);
+  exit (0);
+}
+
+/* forkcopy -- fork a copy to run a script */
+void
+forkcopy (char *script, int child)
+{
+  int child_pid;
+  if (strncmp ("clone", script, 5) == 0)
+    {
+      //clone instead of fork
+      /* Log the event */
+      wlog ("cloning copy ... ", script);
+
+      sprintf (child_name, "%s_C%d", acct_file, ++syn_fork);
+      /* clone a new process */
+      void * stack;
+      void * stack_space;
+      int stack_size = CLONE_STACK_SIZE;
+
+      stack_space = mmap (NULL, stack_size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_GROWSDOWN | MAP_ANONYMOUS, -1, 0);
+      if ((void*) - 1 == stack_space)
+        {
+          fprintf (stderr, "Error: mmap returned -1\n");
+          exit (1);
+        }
+      mprotect (stack_space, CLONE_RED_SIZE, PROT_NONE);
+      stack = (char *) stack_space + stack_size - CLONE_TLS_SIZE; // stack grows back
+      child_pid = clone (clonecopy, stack, CLONE_FLAGS[(child + 1) % 2],
+                         (void *) (script + sizeof ("clone") - 1));
+      if (child_pid < 0)
+        {
+          /* error, could not fork */
+          fprintf (stderr, "forkcopy: clone failed--error %d\n", errno);
+          exit (1);
+        }
+
+      fprintf (stderr, "child process %d cloned by %d.\n",
+               child_pid, (int) getpid ());
+      return;
+    }
+
+  /* Log the event */
+  wlog ("forking copy ... ", script);
+  sprintf (child_name, "%s_f%d", acct_file, ++syn_fork);
+
+  /* fork a new process */
+  child_pid = fork ();
+  if (child_pid < 0)
+    {
+      /* error, could not fork */
+      fprintf (stderr, "forkcopy: fork failed--error %d\n", errno);
+      exit (1);
+
+    }
+  else if (child_pid == 0)
+    {
+      syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
+      strcpy (acct_file, child_name);
+      acct_init (acct_file);
+
+      /* execute the script */
+      commandline (script);
+
+      /* reap the child's descendants */
+      reapchild (0);
+      exit (0);
+    }
+  fprintf (stderr, "child process %d forked by %d.\n",
+           child_pid, (int) getpid ());
+}
+
+void
+forkchild (char * cmdline)
+{
+  stopwatch_t *prog;
+  char mbuf[1024];
+
+  /* Start a stopwatch */
+  sprintf (mbuf, "%s pid[%d]", "Synprog child", (int) getpid ());
+  prog = stpwtch_alloc (mbuf, 0);
+
+  /* process this child's command-line */
+  commandline (cmdline);
+
+  /* reap the child's descendants */
+  reapchild (0);
+
+  /* Stop print, and free the stopwatch */
+  stpwtch_stop (prog);
+  stpwtch_print (prog);
+  free (prog);
+
+  exit (0);
+}
+
+/* reap a child process, called in response to SIGCLD */
+void
+reapchild (int sig)
+{
+  int status;
+  int ret = wait (&status);
+  sigset (SIGCLD, reapchild);
+}
+
+/* reap all child processes prior to exit */
+void
+reapchildren ()
+{
+  int status;
+  int ret;
+
+  /* wait for all children to exit */
+  for (;;)
+    {
+      while ((ret = wait (&status)) != (pid_t) - 1)
+        fprintf (stderr, "synprog: reap child %x\n", ret);
+      if (errno == EINTR)
+        continue;
+      if (errno == ECHILD)
+        return;
+      fprintf (stderr, "synprog: unexpected errno from wait() syscall -- %s\n",
+               strerror (errno));
+    }
+}
+
+/* doabort -- force a SEGV */
+int
+doabort (int k)
+{
+  char *nullptr = NULL;
+  char c;
+
+  /* Log the event */
+  wlog ("start of doabort", NULL);
+
+  /* and dereference a NULL */
+  c = *nullptr;
+
+  /* this should never be reached */
+  return (int) c;
+}
+
+/* =============================================================== */
+
+/*     dousleep -- loop with a usleep */
+int
+dousleep (int k)
+{
+  volatile double x;
+  long long count = 0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of dousleep", NULL);
+  do
+    {
+      x = 0.0;
+      for (int j = 0; j < 1000000; j++)
+        x = x + 1.0;
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "dousleep", NULL);
+  /* this should never be reached */
+  return (int) 0;
+}
+
+/* =============================================================== */
+/*     correlate -- generate CPU use, correlated with profiling clock */
+
+static void csig_handler (int);
+
+int
+correlate (int k)
+{
+  volatile float x; /* temp variable for f.p. calculation */
+  struct itimerval tval;
+  int retval;
+  long long count = 0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of correlate", NULL);
+
+  /* set up the signal handler */
+  sigset (SIGALRM, csig_handler);
+
+  /* set an itimer, to break out of the sleep loop */
+  tval.it_value.tv_sec = 0;
+  tval.it_value.tv_usec = 10000;
+  tval.it_interval.tv_sec = 0;
+  tval.it_interval.tv_usec = 10000;
+
+  retval = setitimer (ITIMER_REAL, &tval, 0);
+  if (retval != 0)
+    fprintf (stderr, "setitimer(ITIMER_REAL) got %d returned: %s\n",
+             retval, strerror (errno));
+  do
+    {
+      x = 0.0;
+      for (int j = 0; j < 1000000; j++)
+        x = x + 1.0;
+      sleep (1); /* relying on the timer to break out */
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  /* now disable the itimer */
+  tval.it_value.tv_sec = 0;
+  tval.it_value.tv_usec = 0;
+  tval.it_interval.tv_sec = 0;
+  tval.it_interval.tv_usec = 0;
+
+  retval = setitimer (ITIMER_REAL, &tval, 0);
+  if (retval != 0)
+    fprintf (stderr, "setitimer(ITIMER_REAL) got %d returned: %s\n",
+             retval, strerror (errno));
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "correlate", NULL);
+  return 0;
+}
+
+static void
+csig_handler (int sig)
+{
+  return;
+}
+
+/* cputime -- loop to use a bunch of user time (f.p.) */
+int
+cputime (int k)
+{
+  volatile float x; /* temp variable for f.p. calculation */
+  long long count = 0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of cputime", NULL);
+  do
+    {
+      x = 0.0;
+      for (int j = 0; j < 1000000; j++)
+        x = x + 1.0;
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "cputime", NULL);
+  return 0;
+}
+
+/* icputime -- loop to use a bunch of user time (long) */
+int
+icputime (int k)
+{
+  volatile long x; /* temp variable for long calculation */
+  long long count = 0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of icputime", NULL);
+  do
+    {
+      x = 0;
+      for (int j = 0; j < 1000000; j++)
+        x = x + 1;
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "icputime", NULL);
+  return 0;
+}
+
+/* hrv -- loop to do lots of gethrvtime calls */
+int
+hrv (int k)
+{
+  long long count = 0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of hrv", NULL);
+  do
+    {
+      for (int j = 0; j < 10000; j++)
+        (void) gethrvtime ();
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "hrv", NULL);
+  return 0;
+}
+
+/* =============================================================== */
+
+/*     ldso -- use up time in ld.so */
+
+int
+ldso (int k)
+{
+  long long count = 0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of ldso", NULL);
+  do
+    {
+      for (int j = 0; j < 10000; j++)
+        (void) dlsym (RTLD_DEFAULT, "nosuchfoo");
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "ldso", NULL);
+  return 0;
+}
+
+/* masksignals -- debug aid -- call routine to mask SIGPROF and SIGEMT */
+int
+masksignals (int n)
+{
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "masksignals", NULL);
+  return 0;
+}
+
+/* =============================================================== */
+/*     muldiv -- loop to do a bunch of integer multiply and divide */
+
+volatile int tmp_ival = 0;
+
+int
+muldiv (int n)
+{
+  long long count = 0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of muldiv", NULL);
+  do
+    {
+      for (int i = 0; i < 1000; i++)
+        {
+          for (int j = 0; j < 1000; j++)
+            tmp_ival = j * i / (i + 1.0);
+        }
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "muldiv", NULL);
+  return 0;
+}
+
+
+/* =============================================================== */
+/*     underflow -- loop triggering arithmetic underflow */
+volatile float tmp_fval;
+
+int
+underflow (int k)
+{
+  float x, y;
+  long long count = 0;
+
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of underflow", NULL);
+  do
+    {
+      x = 1.e-20;
+      y = 1.e-20;
+      for (int j = 0; j < 50000; j++)
+        tmp_fval = x * y;
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "underflow", NULL);
+  return 0;
+}
+
+/* naptime -- spend time in the system sleeping */
+int
+naptime (int k)
+{
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of naptime", NULL);
+  if (k == 0)
+    {
+      k = testtime;
+      if (k < 1)
+        k = 1;
+    }
+  for (int i = 0; i < k; i++)
+    sleep (1);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "naptime", NULL);
+  return 0;
+}
+
+/* recurse -- loop to show recursion */
+int real_recurse (int, int); /* real routine to do recursion */
+
+int
+recurse (int k)
+{
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of recurse", NULL);
+  if (k == 0)
+    k = 80;
+  (void) real_recurse (0, k);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "recurse", NULL);
+  return 0;
+}
+
+int
+recursedeep (int k)
+{
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of recursedeep", NULL);
+  if (k == 0)
+    k = 500;
+  (void) real_recurse (0, k);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "recursedeep", NULL);
+  return 0;
+}
+
+static int rec_count = 0;
+
+int
+real_recurse (int i, int imax)
+{
+  if (i == imax)
+    {
+      volatile float x;
+      long long count = 0;
+      hrtime_t start = gethrtime ();
+      do
+        {
+          x = 0.0;
+          for (int j = 0; j < 10000000; j++)
+            x = x + 1.0;
+          count++;
+        }
+      while (start + testtime * 1e9 > gethrtime ());
+      fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+      return rec_count;
+    }
+  else
+    {
+      real_recurse (i + 1, imax);
+      rec_count++;
+      return rec_count;
+    }
+}
+
+/* gpf -- simple example showing the gprof fallacy */
+float gpf_a (void);
+float gpf_b (void);
+float gpf_work (int);
+
+#define MAX_GPF_WORK_COUNT 1000
+
+int
+gpf (int k)
+{
+  long long count = 0;
+  float x = -1.0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of gpf", NULL);
+
+  do
+    {
+      x = gpf_a ();
+      x += gpf_b ();
+      count++;
+      if (count == MAX_GPF_WORK_COUNT)
+        fprintf (stderr, "Execution error -- %lld iterations of gpf_[ab]; possible compiler bug\n",
+                 count);
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  if (x < 0.0)
+    fprintf (stderr, "Execution error -- x < 0.0; possible compiler bug (x = %f)\n", x);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "gpf - total", NULL);
+  return 0;
+}
+
+float
+gpf_a ()
+{
+  float x = -1.0;
+  for (int i = 0; i < 9; i++)
+    x += gpf_work (1);
+  return x;
+}
+
+float
+gpf_b ()
+{
+  float x = -1.0;
+  x = gpf_work (10);
+  return x;
+}
+
+float
+gpf_work (int amt)
+{
+  volatile float x = 0.0;
+  int imax = 4 * amt * amt;
+  for (int i = 0; i < imax; i++)
+    {
+      x = 0.0;
+      for (int j = 0; j < 200000; j++)
+        x = x + 1.0;
+    }
+  return x;
+}
+
+/*     bounce -- example of indirect recursion */
+void bounce_a (int, int);
+void bounce_b (int, int);
+
+int
+bounce (int k)
+{
+  long long count = 0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of bounce", NULL);
+  if (k == 0)
+    k = 20;
+  do
+    {
+      bounce_a (0, k);
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "bounce", NULL);
+  return 0;
+}
+
+void
+bounce_a (int i, int imax)
+{
+  if (i == imax)
+    {
+      volatile float x = 0.0;
+      for (int k = 0; k < 8; k++)
+        {
+          for (int j = 0; j < 2000000; j++)
+            x = x + 1.0;
+        }
+      return;
+    }
+  else
+    bounce_b (i, imax);
+}
+
+void
+bounce_b (int i, int imax)
+{
+  bounce_a (i + 1, imax);
+  return;
+}
+
+/* =============================================================== */
+
+/*     sched -- spend time calling sched_yield() */
+
+int
+sched (int k)
+{
+  long long count = 0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of sched", NULL);
+  if (k == 0)
+    {
+      k = testtime;
+      if (k < 1)
+        k = 1;
+    }
+  do
+    {
+      for (int i = 0; i < 1000000; i++)
+        sched_yield ();
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "sched", NULL);
+  return 0;
+}
+
+/* synccall -- spend time calling sync() */
+int
+synccall (int k)
+{
+  long long count = 0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of synccall", NULL);
+  if (k == 0)
+    {
+      k = testtime;
+      if (k < 1)
+        k = 1;
+    }
+  do
+    {
+      sync ();
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  fprintf (stderr, "   Performed %lld sync() calls\n", count);
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "synccall", NULL);
+  return 0;
+}
+
+/* sigtime -- spend time in a signal handler */
+static void sigtime_handler (int);
+
+int
+sigtime (int k)
+{
+  long long count = 0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of sigtime", NULL);
+
+  /* set up the signal handler */
+  sigset (SIGHUP, sigtime_handler);
+  do
+    {
+      kill (getpid (), SIGHUP);
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  sigset (SIGHUP, SIG_DFL);
+  fprintf (stderr, "   Sent %lld SIGHUP signals\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "sigtime", NULL);
+  return 0;
+}
+
+static void
+sigtime_handler (int sig)
+{
+  volatile int x;
+  for (int i = 0; i < 50; i++)
+    {
+      x = 0;
+      for (int j = 0; j < 1000000; j++)
+        x = x + 1;
+    }
+  return;
+}
+
+/* systime -- spend time in a few system calls */
+int
+systime (int k)
+{
+  struct timeval ttime;
+  int j;
+  long long count = 0;
+  double t = testtime / 5;
+  if (t < 1.0)
+    t = 1.0;
+  hrtime_t start = gethrtime ();
+  hrtime_t rstart = start;
+  hrtime_t vstart = getmyvtime ();
+  hrtime_t rvstart = vstart;
+
+  /* Log the event */
+  wlog ("start of systime", NULL);
+
+  /* do gettimeofday calls */
+  do
+    {
+      for (j = 0; j < 30000; j++)
+        {
+          (void) gettimeofday (&ttime, NULL);
+        }
+      count++;
+    }
+  while (start + t * 1e9 > gethrtime ());
+
+  hrtime_t end = gethrtime ();
+  hrtime_t vend = getmyvtime ();
+  fprintf (stderr, "   Performed %lld while-loop iterations gettimeofday\n", count);
+  whrvlog (end - start, vend - vstart, "systime -- 10**6 gettimeofday", NULL);
+
+  /* do gethrtime calls */
+  start = gethrtime ();
+  vstart = getmyvtime ();
+  count = 0;
+  do
+    {
+      (void) gethrtime ();
+      count++;
+    }
+  while (start + t * 1e9 > gethrtime ());
+
+  end = gethrtime ();
+  vend = getmyvtime ();
+  fprintf (stderr, "   Performed %lld while-loop iterations gethrtime\n", count);
+  whrvlog ((end - start), (vend - vstart), "systime -- 10**6 gethrtime", NULL);
+
+  /* do pairs of gethrtime calls */
+  start = gethrtime ();
+  vstart = getmyvtime ();
+
+  count = 0;
+  do
+    {
+      for (j = 0; j < 30000; j++)
+        {
+          (void) gethrtime ();
+          (void) gethrtime ();
+        }
+      count++;
+    }
+  while (start + t * 1e9 > gethrtime ());
+
+  end = gethrtime ();
+  vend = getmyvtime ();
+  fprintf (stderr, "   Performed %lld while-loop iterations pairs of gethrtime\n",
+           count);
+  whrvlog (end - start, vend - vstart, "systime -- 10**6  pairs of gethrtime",
+  NULL);
+
+  /* do gethrvtime calls */
+  start = gethrtime ();
+  vstart = getmyvtime ();
+
+  count = 0;
+  do
+    {
+      for (j = 0; j < 30000; j++)
+        {
+          (void) gethrvtime ();
+        }
+      count++;
+    }
+  while (start + t * 1e9 > gethrtime ());
+
+  end = gethrtime ();
+  vend = getmyvtime ();
+  fprintf (stderr, "   Performed %lld while-loop iterations gethrvtime\n", count);
+  whrvlog (end - start, vend - vstart, "systime -- 10**6 gethrvtime", NULL);
+
+  /* do getrusage calls */
+  start = gethrtime ();
+  vstart = getmyvtime ();
+
+  count = 0;
+  do
+    {
+      for (j = 0; j < 30000; j++)
+        {
+          struct rusage rusage;
+          (void) getrusage (RUSAGE_SELF, &rusage);
+        }
+      count++;
+    }
+  while (start + t * 1e9 > gethrtime ());
+
+  end = gethrtime ();
+  vend = getmyvtime ();
+  fprintf (stderr, "   Performed %lld while-loop iterations getrusage\n", count);
+  whrvlog ((end - start), (vend - vstart), "systime -- 10**6 getrusage", NULL);
+  whrvlog ((gethrtime () - rstart), (getmyvtime () - rvstart), "systime", NULL);
+  return 0;
+}
+
+/* unwindcases -- test various unwind corner cases */
+static void unwindcases_handler (int);
+
+int
+unwindcases (int k)
+{
+  long long count = 0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of unwindcases", NULL);
+
+  /* set up the signal handler */
+  sigset (SIGHUP, unwindcases_handler);
+
+  /* initialize the new signal mask */
+  sigset_t new_mask;
+  sigset_t old_mask;
+  sigfillset (&new_mask);
+  sigdelset (&new_mask, SIGHUP);
+
+  /* block all signals except SIGHUP*/
+  sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
+  do
+    {
+      kill (getpid (), SIGHUP);
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  sigprocmask (SIG_SETMASK, &old_mask, NULL);
+  sigset (SIGHUP, SIG_DFL);
+  fprintf (stderr, "   Sent %lld SIGHUP signals\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "unwindcases", NULL);
+  return 0;
+}
+
+#define unwindcases_memcpy memcpy
+#define unwindcases_memset memset
+#define unwindcases_memnum (4096)
+
+static char unwindcases_array[4097];
+static volatile int srcind = 1024;
+
+static void
+unwindcases_handler (int sig)
+{
+  for (int i = 0; i < 1000; i++)
+    {
+      for (int j = 0; j < 1000; j++)
+        {
+          unwindcases_memset ((void*) unwindcases_array, 0, unwindcases_memnum);
+          for (int k = 0; k < 10; k++)
+            {
+              unwindcases_array[k] = unwindcases_array[srcind];
+              unwindcases_array[k + srcind / 4] = 0;
+              unwindcases_array[k] = unwindcases_array[strlen (unwindcases_array + k) + 1];
+            }
+          unwindcases_memcpy ((void*) unwindcases_array,
+                              (void*) (unwindcases_array + 4096 / 2),
+                              unwindcases_memnum / 2);
+        }
+    }
+  return;
+}
+
+/*     tailcallopt -- call routines that would be tail-call optimized when
+ *             compiled with optimization
+ */
+void tailcall_a (void);
+void tailcall_b (void);
+void tailcall_c (void);
+
+int
+tailcallopt (int n)
+{
+  long long count = 0;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of tailcallopt", NULL);
+  do
+    {
+      tailcall_a ();
+      count++;
+    }
+  while (start + testtime * 1e9 > gethrtime ());
+
+  fprintf (stderr, "   Performed %lld while-loop iterations\n", count);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "tailcallopt", NULL);
+  return 0;
+}
+
+void
+tailcall_a ()
+{
+  volatile float x = 0.0;
+  for (int j = 0; j < 4000000; j++)
+    x = x + 1.0;
+  tailcall_b ();
+}
+
+void
+tailcall_b ()
+{
+  volatile float x = 0.0;
+  for (int j = 0; j < 4000000; j++)
+    x = x + 1.0;
+  tailcall_c ();
+}
+
+void
+tailcall_c ()
+{
+  volatile float x = 0.0;
+  for (int j = 0; j < 4000000; j++)
+    x = x + 1.0;
+}
+
+int
+itimer_realprof (int k) /* mess with itimer ITIMER_REALPROF */
+{
+  struct itimerval tval;
+  int retval;
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* set an itimer */
+  if (k != 0)
+    {
+      wlog ("start of itimer_realprof", NULL);
+      tval.it_interval.tv_sec = 1;
+      tval.it_interval.tv_usec = 300000;
+      tval.it_value = tval.it_interval;
+    }
+  else
+    {
+      wlog ("start of itimer_realprof(0)", NULL);
+      tval.it_interval.tv_sec = 0;
+      tval.it_interval.tv_usec = 0;
+      tval.it_value = tval.it_interval;
+    }
+  retval = setitimer (ITIMER_REALPROF, &tval, 0);
+  if (retval != 0)
+    fprintf (stderr, "setitimer(ITIMER_REALPROF) got %d returned: %s\n",
+             retval, strerror (errno));
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "itimer_realprof",
+           NULL);
+  return 0;
+}
+
+static struct sigaction old_sigprof_handler;
+static void sigprof_handler (int sig);
+static void sigprof_sigaction (int sig, siginfo_t *sip, ucontext_t *uap);
+
+int
+sigprof (int k)
+{
+  struct sigaction act;
+
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of sigprof", NULL);
+
+  /* query current handler */
+  if (sigaction (SIGPROF, NULL, &act) == -1)
+    printf ("\tFailed current sigaction query: %s\n", strerror (errno));
+  else
+    printf ("\tCurrently installed sigaction 0x%p\n", act.sa_sigaction);
+
+  sigemptyset (&act.sa_mask);
+  act.sa_flags = SA_RESTART | SA_SIGINFO;
+  act.sa_sigaction = (void(*)(int, siginfo_t*, void*))sigprof_sigaction;
+
+  if (k != 0)
+    {
+      /* install with deferral to original handler (if set) */
+      if (sigaction (SIGPROF, &act, &old_sigprof_handler) == -1)
+        printf ("\tFailed to install sigprof_sigaction: %s\n", strerror (errno));
+      if (old_sigprof_handler.sa_sigaction == (void (*)(int, siginfo_t *, void *))SIG_DFL)
+        {
+          old_sigprof_handler.sa_sigaction = (void (*)(int, siginfo_t *, void *))SIG_IGN;
+          printf ("\tReplaced default sigprof handler with 0x%p\n",
+                  act.sa_sigaction);
+        }
+      else
+        printf ("\tReplaced sigprof handler 0x%p with 0x%p\n",
+                old_sigprof_handler.sa_sigaction, act.sa_sigaction);
+    }
+  else
+    {
+      /* installed without deferral to any original handler */
+      old_sigprof_handler.sa_sigaction = (void (*)(int, siginfo_t *, void *))SIG_IGN;
+      if (sigaction (SIGPROF, &act, NULL) == -1)
+        printf ("\tFailed to install sigprof_sigaction: %s\n", strerror (errno));
+      else
+        printf ("\tInstalled sigprof_sigaction 0x%p\n", act.sa_sigaction);
+    }
+
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "sigprof", NULL);
+  return 0;
+}
+
+int
+sigprofh (int k)
+{
+  struct sigaction act;
+
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  /* Log the event */
+  wlog ("start of sigprofh", NULL);
+
+  /* query current handler */
+  if (sigaction (SIGPROF, NULL, &act) == -1)
+    printf ("\tFailed current sigaction query: %s\n", strerror (errno));
+  else
+    printf ("\tCurrently installed handler 0x%p\n", act.sa_handler);
+
+  sigemptyset (&act.sa_mask);
+  act.sa_flags = SA_RESTART;
+  act.sa_handler = sigprof_handler;
+  if (k != 0)
+    {
+      /* install with deferral to original handler (if set) */
+      if (sigaction (SIGPROF, &act, &old_sigprof_handler) == -1)
+        printf ("\tFailed to install sigprof_handler: %s\n", strerror (errno));
+      if (old_sigprof_handler.sa_handler == SIG_DFL)
+        {
+          old_sigprof_handler.sa_handler = SIG_IGN;
+          printf ("\tReplaced default sigprof handler with 0x%p\n",
+                  act.sa_handler);
+        }
+      else
+        printf ("\tReplaced sigprof handler 0x%p with 0x%p\n",
+                old_sigprof_handler.sa_handler, act.sa_handler);
+    }
+  else
+    {
+      /* installed without deferral to any original handler */
+      old_sigprof_handler.sa_handler = SIG_IGN;
+      if (sigaction (SIGPROF, &act, NULL) == -1)
+        printf ("\tFailed to install sigprof_handler: %s\n", strerror (errno));
+      else
+        printf ("\tInstalled sigprof_handler 0x%p\n", act.sa_handler);
+    }
+
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "sigprofh", NULL);
+  return 0;
+}
+
+static void
+sigprof_handler (int sig)
+{
+  int j;
+  volatile int x;
+
+  hrtime_t now = gethrtime ();
+  if (old_sigprof_handler.sa_handler == SIG_IGN)
+    {
+      whrvlog (now, 0, "sigprof_handler (ign)", NULL);
+      for (j = 0, x = 0; j < 1000000; j++)
+        x = x + 1;
+    }
+  else
+    {
+      whrvlog (now, 0, "sigprof_handler (fwd)", NULL);
+      for (j = 0, x = 0; j < 1000000; j++)
+        x = x + 1;
+      /* forward signal to original handler */
+      if (old_sigprof_handler.sa_flags & SA_SIGINFO)
+        (old_sigprof_handler.sa_sigaction)(sig, NULL, NULL);
+      else
+        (old_sigprof_handler.sa_handler)(sig);
+      printf ("\tReturned from original sigprof handler!\n");
+    }
+
+  return;
+}
+
+static void
+sigprof_sigaction (int sig, siginfo_t *sip, ucontext_t *uap)
+{
+  int j;
+  volatile int x;
+
+  hrtime_t now = gethrtime ();
+  if (old_sigprof_handler.sa_sigaction == (void (*)(int, siginfo_t *, void *))SIG_IGN)
+    {
+      whrvlog (now, 0, "sigprof_sigaction (ign)", NULL);
+      for (j = 0, x = 0; j < 1000000; j++)
+        x = x + 1;
+    }
+  else
+    {
+      whrvlog (now, 0, "sigprof_sigaction (fwd)", NULL);
+      for (j = 0, x = 0; j < 1000000; j++)
+        x = x + 1;
+      /* forward signal to original handler */
+      if (old_sigprof_handler.sa_flags & SA_SIGINFO)
+        (old_sigprof_handler.sa_sigaction)(sig, sip, uap);
+      else
+        (old_sigprof_handler.sa_handler)(sig);
+      printf ("\tReturned from original sigprof sigaction!\n");
+    }
+  return;
+}
+
+#if 0
+Need to consider various signal handler / sigaction scenarios :
+
+1. A handler is already installed, and a new handler is being installed.
+(The original handler may be one of the defaults.)
+2. A handler is already installed, and a sigaction is being installed.
+3. A sigaction is already installed, and a new sigaction is being installed.
+4. A sigaction is already installed, and a handler is being installed.
+#endif
+
+int
+do_chdir (int k) /* switch to a new working directory */
+{
+  char *workdir;
+  char *workdir0 = "/tmp";
+  char *workdir1 = "/";
+  char currworkdir[MAXPATHLEN];
+
+  hrtime_t start = gethrtime ();
+  hrtime_t vstart = getmyvtime ();
+
+  if (k != 0)
+    {
+      wlog ("start of do_chdir(X)", NULL);
+      workdir = workdir1;
+    }
+  else
+    {
+      wlog ("start of do_chdir", NULL);
+      workdir = workdir0;
+    }
+
+  if (getcwd (currworkdir, sizeof (currworkdir)) == NULL)
+    fprintf (stderr, "old getcwd failed: %s\n", strerror (errno));
+  else
+    printf ("old getcwd returned \"%s\"\n", currworkdir);
+
+  if (chdir (workdir) != 0)
+    fprintf (stderr, "chdir(\"%s\") failed: %s\n", workdir, strerror (errno));
+
+  if (getcwd (currworkdir, sizeof (currworkdir)) == NULL)
+    fprintf (stderr, "new getcwd failed: %s\n", strerror (errno));
+  else
+    printf ("new getcwd returned \"%s\"\n", currworkdir);
+  whrvlog (gethrtime () - start, getmyvtime () - vstart, "do_chdir", NULL);
+  return 0;
+}
+
+int
+do_exec (int k) /* do an exec() call */
+{
+  sprintf (new_name, "_SP_NAME=%s_x%d", acct_file, ++syn_exec);
+  if (putenv (new_name))
+    fprintf (stderr, "Failed to name child! %s\n", strerror (errno));
+  if (k >= 0)
+    {
+      wlog ("about to exec", NULL);
+      execl ("./synprog", "synprog", "gpf.cpu.sx", NULL);
+      wlog ("exec failed!!!", NULL);
+    }
+  else
+    {
+      wlog ("about to execX", NULL);
+      execl ("./no-such-file", "no-such-file", "gpf.cpu.sx", NULL);
+      wlog ("execX failed (as expected)", NULL);
+    }
+  return 0;
+}
+
+/* preloading libcollector to a setuid executable will fail! */
+const char *cmdX = "/random/crash_n_burn";
+const char *cmd0 = "/bin/uptime";
+const char *cmd1 = "/bin/echo hello world!";
+const char *cmd2 = "/usr/bin/sleep 5";
+const char *cmd3 = "/usr/bin/sleep 5; /bin/echo hello world!";
+const char *cmd4 = "/usr/bin/sleep 2; /bin/echo hello world!; /usr/bin/sleep 2";
+const char *cmd5 = "/bin/date; /bin/sleep 2; /bin/date; /bin/sleep 2; /bin/date";
+const char *cmd6 = "w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w";
+const char *cmd7 = "synprog";
+const char *cmd8 = "synprog icpu.sx 2>&1";
+
+int
+do_popen (int k) /* do a popen() call */
+{
+  int ret;
+  FILE *fd;
+  char buf[BUFSIZ];
+  const char *mode = "r";
+
+  /* XXXX popen() will temporarily vfork+exec() a new child */
+  /* but there will be no accounting for it, unless it's synprog! */
+  sprintf (new_name, "_SP_NAME=%s_c%d", acct_file, ++syn_combo);
+  if (putenv (new_name))
+    fprintf (stderr, "Failed to name child! %s\n", strerror (errno));
+
+  /* ignore reapchild to catch child here */
+  (void) sigset (SIGCHLD, 0);
+  if (k >= 0)
+    {
+      wlog ("about to popen", NULL);
+      fd = popen (cmd8, mode);
+    }
+  else
+    {
+      wlog ("about to popenX!", NULL);
+      fd = popen (cmdX, mode);
+    }
+  if (fd == NULL)
+    printf ("do_popen failed: %s\n", strerror (errno));
+  else
+    printf ("do_popen succeeded: fileno=%d\n", fileno (fd));
+
+  /* restore pre-popen environment */
+  sprintf (new_name, "_SP_NAME=%s", acct_file);
+  if (putenv (new_name))
+    fprintf (stderr, "Failed to restore name! %s\n", strerror (errno));
+
+  if (fd != NULL)
+    {
+      while (fgets (buf, BUFSIZ, fd) != NULL)
+        printf ("&    %s", buf);
+
+      if ((ret = pclose (fd)) == -1)
+        printf ("do_popen pclose error: %s\n", strerror (errno));
+      else
+        printf ("do_popen pclose returned %d\n", ret);
+    }
+
+  /* set up to reap any children */
+  (void) sigset (SIGCHLD, reapchild);
+  return 0;
+}
+
+int
+do_system (int k) /* do a system() call */
+{
+  int ret;
+
+  /* XXXX system() will temporarily vfork+exec() a new child */
+  /* but there will be no accounting for it, unless it's synprog! */
+  sprintf (new_name, "_SP_NAME=%s_c%d", acct_file, ++syn_combo);
+  if (putenv (new_name))
+    fprintf (stderr, "Failed to name child! %s\n", strerror (errno));
+
+  if (k >= 0)
+    {
+      wlog ("about to system", NULL);
+      ret = system (cmd8);
+    }
+  else
+    {
+      wlog ("about to systemX!", NULL);
+      ret = system (cmd0);
+    }
+  if (ret < 0)
+    printf ("do_system failed: %s\n", strerror (errno));
+  else
+    printf ("do_system succeeded, ret=%d\n", ret);
+
+  /* restore pre-system environment */
+  sprintf (new_name, "_SP_NAME=%s", acct_file);
+  if (putenv (new_name))
+    fprintf (stderr, "Failed to restore name! %s\n", strerror (errno));
+  return 0;
+}
+
+int
+do_forkexec (int k) /* do a fork()+exec() call combo */
+{
+  int ret, pid;
+  int status = -1;
+  char arg0[128], arg1[128];
+  arg1[0] = (char) 0;
+
+  /* ignore reapchild to catch child here */
+  (void) sigset (SIGCHLD, 0);
+
+  sprintf (child_name, "%s_f%d", acct_file, ++syn_fork);
+  if ((pid = fork ()) == 0)
+    {
+      syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
+      strcpy (acct_file, child_name);
+      acct_init (acct_file);
+      sprintf (new_name, "_SP_NAME=%s_x%d", acct_file, ++syn_exec);
+      if (putenv (new_name))
+        {
+          fprintf (stderr, "Failed to name fork child! %s\n", strerror (errno));
+        }
+      (void) execl (arg0, "fork+exec", arg1[0] ? arg1 : NULL, NULL);
+      fprintf (stderr, "fork execl failed! %s\n", strerror (errno));
+      _exit (127);
+    }
+  else if (pid == -1)
+    fprintf (stderr, "fork failed! %s\n", strerror (errno));
+  else
+    {
+      do
+        {
+          ret = waitpid (pid, &status, WNOHANG | WUNTRACED);
+        }
+      while ((ret == -1) && (errno == EINTR));
+
+      if (ret == -1)
+        fprintf (stderr, "waitpid failed: %s\n", strerror (errno));
+#if 0
+      else
+        {
+          if (WIFEXITED (status))
+            printf ("WEXITSTATUS=%d\n", WEXITSTATUS (status));
+          if (WIFSTOPPED (status))
+            printf ("WSTOPSIG=%d\n", WSTOPSIG (status));
+          if (WIFSIGNALED (status))
+            printf ("WTERMSIG=%d\n", WTERMSIG (status));
+          if (WIFCONTINUED (status))
+            printf ("WIFCONTINUED=%d\n", WIFCONTINUED (status));
+        }
+#endif
+      if (WIFEXITED (status))
+        printf ("do_forkexec succeeded: child exit status=%d\n",
+                WEXITSTATUS (status));
+      else
+        printf ("do_forkexec failed! status=%d\n", status);
+    }
+
+  /* set up to reap any children */
+  (void) sigset (SIGCHLD, reapchild);
+  return 0;
+}
+
+int
+do_vforkexec (int k) /* do a vfork()+exec() call combo */
+{
+  int ret, pid;
+  int status = 1;
+  char arg0[128], arg1[128];
+  arg1[0] = (char) 0;
+  /* ignore reapchild to catch child here */
+  (void) sigset (SIGCHLD, 0);
+
+  sprintf (child_name, "%s_f%d", acct_file, ++syn_fork);
+
+  if ((pid = vfork ()) == 0)
+    {
+      syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
+      strcpy (acct_file, child_name);
+      acct_init (acct_file);
+      sprintf (new_name, "_SP_NAME=%s_x%d", acct_file, ++syn_exec);
+      if (putenv (new_name))
+        fprintf (stderr, "Failed to name vfork child! %s\n", strerror (errno));
+      (void) execl (arg0, "vfork+exec", arg1[0] ? arg1 : NULL, NULL);
+      printf ("vfork execl failed! %s\n", strerror (errno));
+      _exit (127);
+    }
+  else if (pid == -1)
+    fprintf (stderr, "vfork failed! %s\n", strerror (errno));
+  else
+    {
+      do
+        {
+          ret = waitpid (pid, &status, WNOHANG | WUNTRACED);
+        }
+      while (ret == -1 && errno == EINTR);
+
+      if (ret == -1)
+        fprintf (stderr, "waitpid failed: %s\n", strerror (errno));
+#if 0
+      else
+        {
+          if (WIFEXITED (status))
+            printf ("WEXITSTATUS=%d\n", WEXITSTATUS (status));
+          if (WIFSTOPPED (status))
+            printf ("WSTOPSIG=%d\n", WSTOPSIG (status));
+          if (WIFSIGNALED (status))
+            printf ("WTERMSIG=%d\n", WTERMSIG (status));
+          if (WIFCONTINUED (status))
+            printf ("WIFCONTINUED=%d\n", WIFCONTINUED (status));
+        }
+#endif
+      if (WIFEXITED (status))
+        printf ("do_vforkexec succeeded: child exit status=%d\n",
+                WEXITSTATUS (status));
+      else
+        printf ("do_vforkexec failed! status=%d\n", status);
+    }
+
+  /* set up to reap any children */
+  (void) sigset (SIGCHLD, reapchild);
+  return 0;
+}
diff --git a/gprofng/testsuite/lib/Makefile.skel b/gprofng/testsuite/lib/Makefile.skel
new file mode 100644 (file)
index 0000000..7134c27
--- /dev/null
@@ -0,0 +1,61 @@
+# Skeleton makefile for display tests
+#   Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+CC          = gcc
+CFLAGS      = -g -Wall
+SHAREDOPT      = -fpic -shared
+
+#JAVABIN = /usr/java/latest/bin
+JAVABIN = $(shell dirname `which java`)
+JAVA    = $(JAVABIN)/java
+JAVAC   = $(JAVABIN)/javac
+
+COLLECT_FLAGS   = -p on
+TARGET_FLAGS    =
+DISPLAY_FLAGS   = -func
+GPROFNG_OPT = -func
+
+GPROFNG     = gprofng
+COLLECT            = $(GPROFNG) collect app
+DISPLAY            = $(GPROFNG) display text
+
+EXPERIMENT  = test.er
+DISPLAY_LOG = display.log
+
+
+export LD_LIBRARY_PATH := $(shell dirname $$(find ../root -name libgprofng.so.0 | head -1))
+
+.PHONY: all collect compare clobber clean
+
+all: compare
+
+# We intentionally use incomplete dependencies here, because we don't want to
+# regenerate test.er during the later display/compare phases.
+collect: $(EXPERIMENT)
+
+$(DISPLAY_LOG): $(EXPERIMENT)
+       $(DISPLAY) $(DISPLAY_FLAGS) $(EXPERIMENT) > $@
+
+compare: $(DISPLAY_LOG)
+       perl -I $(srcdir)/../../lib $(srcdir)/check_results.pl $(ACCT_FILE) $(DISPLAY_LOG)
+
+clobber clean:
+       rm -rf *.er
+       rm -f *.acct *.acct2 *.log core* *.class *.o $(TARGETS) *.out
diff --git a/gprofng/testsuite/lib/acct.pm b/gprofng/testsuite/lib/acct.pm
new file mode 100644 (file)
index 0000000..1b0168e
--- /dev/null
@@ -0,0 +1,774 @@
+#   Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+use strict;
+package acct;
+use vars qw(%Acct $Erp);
+my($debug_f, $retVal, $OpenDis, $OpenFsingle, $Read_rules_txt);
+my(@Comparison, @hashSample, @acctHeader);
+my(%RANGE, %Rules);
+my($ERROR_ACCT_MISMATCH, $ERROR_NEGATIVE_TIME, $ERROR_PERL_ERROR,
+   $ERROR_DIFF_RANGE, $ERROR_ZERO_METRIC, $ERROR_HIGH_UNKNOWN,
+   $ERROR_CALLER_VERIF, $ERROR_SIGNAL_LOST);
+
+BEGIN {
+#    use Exporter ();
+#    @ISA = 'Exporter';
+#    @EXPORT_OK = ('&readAcct', '%Acct');
+    $debug_f = $ENV{PERL_DEBUG};
+    $retVal = 0;
+    $OpenDis = 0;
+    $OpenFsingle = 0;
+    $#Comparison = -1;
+    $Read_rules_txt = 0;
+    $Erp = {};
+    @hashSample = [];
+
+    %RANGE = (
+        Count => {  P_RANGE =>  0,      P_RATE => 0,
+                    N_RANGE =>  0,      N_RATE => 0,    FMT => "%d"
+                 },
+        Total => {  P_RANGE =>  0.20,   P_RATE =>  3,
+                    N_RANGE => -0.20,   N_RATE => -3,   FMT => "%6.3f"
+                 },
+        Cpu   => {  P_RANGE =>  0.5,    P_RATE => 10,
+                    N_RANGE => -0.5,   N_RATE => -10,   FMT => "%6.3f"
+                    ,P_RANGE_2AVG =>  0.5,    P_RATE_2AVG => 10,
+                    N_RANGE_2AVG =>  -0.5,    N_RATE_2AVG => -10
+                 },
+        Cycles => {  P_RANGE =>  0.5,    P_RATE => 10,
+                    N_RANGE => -0.5,   N_RATE => -10,   FMT => "%6.3f"
+                    ,P_RANGE_2AVG =>  0.5,    P_RATE_2AVG => 10,
+                    N_RANGE_2AVG =>  -0.5,    N_RATE_2AVG => -10
+                 },
+        Cycles1 => {  P_RANGE =>  0.5,    P_RATE => 10,
+                    N_RANGE => -0.5,   N_RATE => -10,   FMT => "%6.3f"
+                    ,P_RANGE_2AVG =>  0.5,    P_RATE_2AVG => 10,
+                    N_RANGE_2AVG =>  -0.5,    N_RATE_2AVG => -10
+                 },
+        Sync  => {  P_RANGE =>  0.5,    P_RATE =>  3,
+                    N_RANGE => -0.5,    N_RATE => -3,   FMT => "%6.3f"
+                 },
+        Unkn  => {  P_RANGE =>  0.10,   P_RATE =>  0.5,   FMT => "%6.3f" }
+    );
+
+    $ERROR_SIGNAL_LOST = 44;
+    $ERROR_DIFF_RANGE = 84;
+    $ERROR_HIGH_UNKNOWN = 85;
+    $ERROR_PERL_ERROR = 86;
+    $ERROR_ACCT_MISMATCH = 87;
+    $ERROR_CALLER_VERIF = 88;
+    $ERROR_ZERO_METRIC = 94;
+    $ERROR_NEGATIVE_TIME = 103;
+}
+
+sub debug
+{
+    my ($lineN, $fmt);
+    if ( $debug_f == 0 ) {
+        return;
+    }
+    $lineN = shift @_;
+    $fmt = shift @_;
+    if ( $debug_f == 2 ) {
+        warn "DEBUG:#$lineN:\n";
+    }
+    warn sprintf($fmt, @_);
+}
+
+sub set_retVal
+{
+    if ( $retVal == 0 ) {
+        $retVal = $_[0];
+        if ($retVal != 0 ) {
+          warn sprintf("DEBUG: retVal=%d\n", $retVal);
+        }
+    }
+    return $retVal;
+}
+
+sub diffRule
+{
+    # The format of the comparison rule is:
+    #   <Name>, <Column number in *.acct>, <Column number in erprint.out>, <message>
+    #   Cpu,   3, 1
+    #   Total, 2, 3
+    my ($str) = @_;
+    my (@arr);
+
+    @arr = split (/,/, $str);
+    if ($#arr == 2) {
+        # Old version
+        push @arr, $arr[0];
+    }
+    push @Comparison, [@arr];
+}
+
+sub read_rules
+{
+    my ($name, $rule, $line, @arr);
+    return if ( $Read_rules_txt == 1);
+    $Read_rules_txt = 1;
+    open(FP, "<rules.txt") or return;
+    while ($line = <FP>) {
+        chomp ($line);
+        $line =~ s/\s*//g;   # Remove all blanks
+        $line =~ s/\\s/ /g;  # Replace \s with space
+        next if ( $line =~ m/^$/ );
+        next if ( $line =~ m/^#/ );
+
+        if ( $line =~ m/=/ ) {
+            # Set a calculation rule
+            ($name, $rule) = split (/=/, $line);
+            $Rules{$name} = [split(/\+/, $rule)];
+            next;
+        }
+
+        # Set a comparison rule
+        &diffRule($line);
+    }
+    close(FP);
+}
+
+sub dump_acct()
+{
+    my ($i, $n, $key, $fmt, @fmt_head);
+    printf "dump_acct:\n";
+    foreach $i ( @acctHeader ) {
+        $fmt = sprintf("%%%ds ", length($i));
+        push @fmt_head, $fmt;
+        printf $fmt, $i;
+    }
+    printf "\n";
+    foreach $key (sort keys %Acct) {
+        $n = 0;
+        foreach $i ( @{$Acct{$key}} ) {
+            $fmt = $n <= $#fmt_head ? $fmt_head[$n] : " %10s";
+            $n++;
+            printf $fmt, $i;
+        }
+        printf "   '%s'", $key;
+        if ( exists $Rules{$key} ) {
+            printf " := %s", join(" + ", @{$Rules{$key}});
+        }
+        printf "\n";
+    }
+}
+
+sub readAcct
+{
+    # Read the *.acct file into hash $Acct with the function name as key.
+    # The format of *.acct is :
+    #   X <time1> ... <timeN> <func_name>
+    my ($fileName, @checkTime) = @_;
+    my ($name, $i, $key, $line, @arr);
+
+    # file *.acct is generated while the test program is running.
+    if (!open(FP, "<$fileName")) {
+        printf "acct::readAcct: Cannot open '%s'\n\n", $fileName;
+        exit($ERROR_ACCT_MISMATCH);
+    }
+    while ($line = <FP>) {  # Skip the first lines (header)
+        last if ( $line =~ m/^X\s+/ );
+    }
+    @acctHeader = split (/\s+/, $line);
+    push @acctHeader, "Comment";
+    while ($line = <FP>) {
+        chomp($line);
+        $line =~ s/^\s*//;   # Delete leading spaces
+        next if ( $line =~ m/^$/ );
+        @arr = split (/\s+/, $line);
+        $name = pop(@arr);
+        if (defined $Acct{$name}) {
+            for ($i = 1; $i <= $#arr; $i++ ) {
+                $Acct{$name}[$i] += $arr[$i];
+            }
+        } else {
+            $Acct{$name} = [ @arr ];
+        }
+
+        foreach $i ( @checkTime ) {
+            next if ($i > $#arr);
+            if ( $arr[$i] < 0 ) {
+                &set_retVal($ERROR_NEGATIVE_TIME);
+                last;
+            }
+        }
+    }
+    close(FP);
+
+    &read_rules;
+    # &checkCallersCallees;
+
+    if ( $debug_f != 0 ) {
+        printf "\nreadAcct: '%s'\n", $fileName;
+        printf "checkTime: ";
+        if( $#checkTime == -1 ) {
+                printf "<None>\n";
+        } else {
+            print "[ ", join(", ", @checkTime), " ]\n";
+        }
+        foreach $i ( @Comparison ) {
+            print "Comparison rule: ", join(", ", @{$i}), "\n";
+        }
+        &dump_acct;
+        printf "\n";
+    }
+}
+
+
+sub read_er_print_out
+{
+    my ($fileName, $colName) = @_;
+    my ($name, @arr, $head_f, $line, $key, $i);
+
+    $Erp = {};
+    $head_f = 1;
+    open(FP, "<$fileName") or return;
+    while ($line = <FP>) {
+        chomp($line);
+        $line =~ s/^\s*//;   # Delete leading spaces
+        next if ( $line =~ m/^$/ );
+        if ($head_f == 1) {
+            # Skip the first lines (header)
+            next unless ( $line =~ m/^\d/ );
+            next unless ( ($line =~ m/<Total>\s*$/) ||
+                          ($line =~ m/<Stack-unwind-failed>\s*$/) );
+            $head_f = 0;
+            if ($colName == -1) {
+                @arr = split (/\s+/, $line);
+                $colName = $#arr + 1;
+            }
+        }
+        @arr = split (/\s+/, $line, $colName);
+        $name = pop(@arr);
+        if (defined $Erp->{$name}) {
+            for ($i = 0; $i <= $#arr; $i++ ) {
+                $Erp->{$name}[$i] += $arr[$i];
+            }
+        } else {
+            $Erp->{$name} = [ @arr ];
+        }
+
+        $i = index($name, "(");
+        if ($i > 0) {
+          my $funcName = substr($name, 0, $i);
+          if (defined $Erp->{$funcName}) {
+            for ($i = 0; $i <= $#arr; $i++ ) {
+              $Erp->{$funcName}[$i] += $arr[$i];
+            }
+          } else {
+            $Erp->{$funcName} = [ @arr ];
+          }
+        }
+    }
+    close(FP);
+
+    if ( $debug_f != 0 ) {
+        printf "read_er_print_out:\n";
+        foreach $key (sort keys %{$Erp}) {
+            foreach $i ( @{$Erp->{$key}} ) {
+                printf " %10s", $i;
+            }
+            printf "  %-10s", "'$key'";
+            if ( exists $Rules{$key} ) {
+                printf " += %s", join(" + ", @{$Rules{$key}});
+            }
+            printf "\n";
+        }
+    }
+}
+
+
+sub createKDiff
+{
+    my ($colSample) = @_;
+    my ($key, $str, $i, $head_str);
+
+    open(DIFF_fp, ">diff.out");
+    $head_str = "X";
+    for $i ( 0..$#Comparison ) {
+        $head_str .= &get_head_str($i);
+    }
+    $head_str .= "   Name";
+    printf DIFF_fp "%s\n", $head_str;
+    foreach $key (sort keys %Acct) {
+        # Restore a hash 'Erp'
+        $Erp = $hashSample[$Acct{$key}[$colSample]];
+        $str = &doComp($key, $head_str);
+        printf DIFF_fp "%s (Sample %d)\n", $str,$Acct{$key}[$colSample];
+    }
+    close(DIFF_fp);
+    &closeDisFile();
+}
+
+sub commandToScr1_fp()
+{
+    my ($str) = @_;
+    printf Scr1_fp "#\n#%s\n%s\n", $str, $str;
+}
+
+sub openFsingleScr
+{
+    return if ($OpenFsingle == 1);
+    open(Scr1_fp, ">>erp_fsingle.scr");
+    $OpenFsingle = 1;
+}
+
+sub closeFsingleScr
+{
+    return if ($OpenFsingle != 1);
+    $OpenFsingle = 2;
+    close(Scr1_fp);
+}
+
+sub openDisFile
+{
+    &openFsingleScr();
+    return if ($OpenDis == 1);
+    open(Dis_fp, ">>discrepancy.out");
+    $OpenDis = 1;
+}
+
+sub closeDisFile
+{
+    &closeFsingleScr();
+    return if ($OpenDis != 1);
+    $OpenDis = 2;
+    close(Dis_fp);
+}
+
+sub with_diff
+{
+    my ($i) = @_;
+    my ($key);
+
+    $key = $Comparison[$i][0];
+    if( ! exists $RANGE{$key} ) {
+        printf "acct::with_diff: '$key' is a wrong key\n\n";
+        exit $ERROR_PERL_ERROR;
+    }
+    if ($RANGE{$key}->{FMT} !~ m/^%d/) {
+        return 1;
+    }
+    return 0;
+}
+
+sub get_head_str()
+{
+    my ($i) = @_;
+    my ($str);
+    $str = $Comparison[$i][3];
+    while (length($str) < 16) {
+        $str = "*" . $str . "*";
+    }
+    if (with_diff($i)) {
+        return sprintf("| %17s %7s %7s %s", $str, "Diff", "%", "x");
+    } else {
+        return sprintf("| %17s %s", $str, "x");
+    }
+}
+
+sub doComp
+{
+    my ($fname, $head_str) = @_;
+    my ($key, $R, $r1, $r2, $diff, $rate, $flagX, $x, $i,
+        $retStr, $discrepancy, $err_diff_range, $err_zero_metric, $err_acct_mismatch);
+
+    sub setRate
+    {
+        my ($val, $diff) = @_;
+        return sprintf("%6.1f", ($diff/$val)*100) if ( $val != 0 );
+        return sprintf("%6.1f", "0.0") if ( $diff >= -0.05 && $diff <= 0.05);
+        return sprintf("%6.1f", "100") if ( $diff > 0 );
+        return sprintf("%6.1f", "-100");
+    }
+
+    $err_diff_range = 0;
+    $err_zero_metric = 0;
+    $err_acct_mismatch = 0;
+    $discrepancy = " ";
+    $flagX = " ";
+    $retStr = "";
+    for $i ( 0..$#Comparison ) {
+        $r1 = $Acct{$fname}[$Comparison[$i][1]];
+        $r2 = 0;
+        if ( ! exists $Rules{$fname} ) {
+            if ( exists $Erp->{$fname} ) {
+                $r2 = $Erp->{$fname}[$Comparison[$i][2]];
+            }
+        } else {
+            foreach my $key1 ( @{$Rules{$fname}} ) {
+                my $sign = 1;
+                $key = $key1;
+                if (substr($key1, 0, 1) eq '-') {
+                    $key = substr($key1, 1);
+                    $sign = -1;
+                }
+                if ( exists $Erp->{$key} ) {
+                    $r2 += $sign * $Erp->{$key}[$Comparison[$i][2]];
+                }
+            }
+        }
+
+        $key = $Comparison[$i][0];
+        if( ! exists $RANGE{$key} ) {
+            printf "acct::doComp: '$key' is a wrong key\n\n";
+            exit $ERROR_PERL_ERROR;
+        }
+        $R = $RANGE{$key};
+        $r1 = sprintf($R->{FMT}, $r1);
+        $r2 = sprintf($R->{FMT}, $r2);
+        $diff = sprintf($R->{FMT}, $r1 - $r2);
+        $rate = &setRate($r1, $diff);
+        if ((( $diff > $R->{P_RANGE} ) && ( $rate >= $R->{P_RATE} ))
+         || ( ( $fname ne '<Unknown>') && ( $diff < $R->{N_RANGE} ) && ( $rate <= $R->{N_RATE} ))) {
+            $x = ($Acct{$fname}[0] eq "Y") ? "y" : "x";
+            if ( $x ne "y" ) {
+                $flagX = "X";
+                &openDisFile();
+                printf Dis_fp "%s/ %s\n", $fname, $Comparison[$i][3];
+
+                $discrepancy .= " $Comparison[$i][3]";
+                if (with_diff($i)) {
+                    if ( $r2 > 0 ) {
+                        $err_diff_range = $ERROR_DIFF_RANGE;
+                    } else {
+                        $err_zero_metric = $ERROR_ZERO_METRIC;
+                    }
+                } else {
+                    $err_acct_mismatch = $ERROR_ACCT_MISMATCH;
+                }
+           }
+        } else {
+            $x = " ";
+        }
+
+        if (with_diff($i)) {
+            $retStr .= sprintf("| %8s %8s %7s %7s %s", $r1, $r2, $diff, $rate, $x);
+        } else {
+            $retStr .= sprintf("| %8s %8s %s", $r1, $r2, $x);
+        }
+    }
+    $retStr = $flagX . $retStr . sprintf("   %-10s", $fname);
+    if ( exists $Rules{$fname} ) {
+        $retStr .=  sprintf " := %s", join(" + ", @{$Rules{$fname}});
+    }
+    if ($discrepancy ne " ") {
+        if ($err_acct_mismatch != 0) {
+            $retVal = $err_acct_mismatch;
+        }
+        &set_retVal($err_zero_metric);
+        &set_retVal($err_diff_range);
+        printf Scr1_fp "#%s\n#%s\n", $head_str, $retStr;
+        &commandToScr1_fp(sprintf("%s %s 1", 'fsingle', $fname));
+        &commandToScr1_fp(sprintf("%s %s 1", 'csingle', $fname));
+    }
+    return ($retStr);
+}
+
+sub doComp2AVG
+{
+    my ($fname, $head_str, @avg) = @_;
+    my ($key, $R, $r1, $r2, $diff, $rate, $flagX, $x, $i,
+        $retStr, $discrepancy, $err_diff_range, $err_zero_metric, $err_acct_mismatch);
+
+    sub setRate
+    {
+        my ($val, $diff) = @_;
+        return sprintf("%6.1f", ($diff/$val)*100) if ( $val != 0 );
+        return sprintf("%6.1f", "0.0") if ( $diff >= -0.05 && $diff <= 0.05);
+        return sprintf("%6.1f", "100") if ( $diff > 0 );
+        return sprintf("%6.1f", "-100");
+    }
+
+    $err_diff_range = 0;
+    $err_zero_metric = 0;
+    $err_acct_mismatch = 0;
+    $discrepancy = " ";
+    $flagX = " ";
+    $retStr = "";
+    for $i ( 0..$#Comparison ) {
+        $r1 = $avg[$i];
+        $r2 = 0;
+        if ( ! exists $Rules{$fname} ) {
+            if ( exists $Erp->{$fname} ) {
+                $r2 = $Erp->{$fname}[$Comparison[$i][2]];
+            }
+        } else {
+            foreach my $key1 ( @{$Rules{$fname}} ) {
+                my $sign = 1;
+                $key = $key1;
+                if (substr($key1, 0, 1) eq '-') {
+                    $key = substr($key1, 1);
+                    $sign = -1;
+                }
+                if ( exists $Erp->{$key} ) {
+                    $r2 += $sign * $Erp->{$key}[$Comparison[$i][2]];
+                }
+            }
+        }
+
+        $key = $Comparison[$i][0];
+        if( ! exists $RANGE{$key} ) {
+            printf "acct::doComp: '$key' is a wrong key\n\n";
+            exit $ERROR_PERL_ERROR;
+        }
+        $R = $RANGE{$key};
+        $r1 = sprintf($R->{FMT}, $r1);
+        $r2 = sprintf($R->{FMT}, $r2);
+        $diff = sprintf($R->{FMT}, $r1 - $r2);
+        $rate = &setRate($r1, $diff);
+        if ((( $diff > $R->{P_RANGE_2AVG} ) && ( $rate >= $R->{P_RATE_2AVG} ))
+         || ( ( $fname ne '<Unknown>') && ( $diff < $R->{N_RANGE_2AVG} ) && ( $rate <= $R->{N_RATE_2AVG} ))) {
+            $flagX = "X";
+            $x = "x";
+            $discrepancy .= " $Comparison[$i][3]";
+            if (with_diff($i)) {
+                if ( $r2 > 0 ) {
+                    $err_diff_range = $ERROR_DIFF_RANGE;
+                } else {
+                    $err_zero_metric = $ERROR_ZERO_METRIC;
+                }
+            } else {
+                $err_acct_mismatch = $ERROR_ACCT_MISMATCH;
+            }
+        } else {
+            $x = " ";
+        }
+
+        if (with_diff($i)) {
+            $retStr .= sprintf("| %8s %8s %7s %7s %s", $r1, $r2, $diff, $rate, $x);
+        } else {
+            $retStr .= sprintf("| %8s %8s %s", $r1, $r2, $x);
+        }
+    }
+    $retStr = $flagX . $retStr . sprintf("   %-10s", $fname);
+    if ( exists $Rules{$fname} ) {
+        $retStr .=  sprintf " := %s", join(" + ", @{$Rules{$fname}});
+    }
+    if ($discrepancy ne " ") {
+        if ($err_acct_mismatch != 0) {
+            $retVal = $err_acct_mismatch;
+        }
+        &set_retVal($err_zero_metric);
+        &set_retVal($err_diff_range);
+        &openDisFile();
+        printf Scr1_fp "#%s\n#%s\n", $head_str, $retStr;
+        &commandToScr1_fp(sprintf("%s %s 1", 'fsingle', $fname));
+        printf Dis_fp "%s/%s\n", $fname, $discrepancy;
+    } else {
+    }
+    return ($retStr);
+}
+
+
+sub checkUnknown()
+{
+    my ($total, $i, $R);
+
+    sub checkUnknRate()
+    {
+        my ($name, $N) = @_;
+        my ($val, $rate, $fmt);
+
+        $val = $Erp->{$name}[$Comparison[$N][2]];
+        $val = sprintf($R->{FMT}, $val);
+        $rate = sprintf($R->{FMT},($val / $total) * 100);
+
+       if (($val > $R->{'P_RANGE'}) && ($rate > $R->{'P_RATE'})) {
+           &set_retVal($ERROR_HIGH_UNKNOWN);
+           &openFsingleScr();
+           $fmt = "#%-8s %10s %10s %s\n";
+           printf Scr1_fp $fmt, $Comparison[$N][0], '%', '<Total>', $name;
+           printf Scr1_fp $fmt, ' ', $rate, $total, $val;
+           &commandToScr1_fp(sprintf("%s %s 1", 'fsingle', '<Total>'));
+           &commandToScr1_fp(sprintf("%s %s 1", 'csingle', '<Total>'));
+           &commandToScr1_fp(sprintf("%s %s 1", 'fsingle', $name));
+           &commandToScr1_fp(sprintf("%s %s 1", 'csingle', $name));
+           &closeFsingleScr();
+           return 1;
+       }
+       return 0;
+    }
+
+    return if ( ! exists $Erp->{'<Total>'} );
+    return if ( $ENV{NOJAVA} );
+    $R = $RANGE{'Unkn'};
+    for $i ( 0..$#Comparison ) {
+        $total = $Erp->{'<Total>'}[$Comparison[$i][2]];
+        next if ( $total == 0 );
+        $total = sprintf($R->{FMT}, $total);
+#        last if &checkUnknRate('<Stack-unwind-failed>', $i);
+        last if &checkUnknRate('<Unknown>', $i);
+        last if &checkUnknRate('<no', $i);
+    }
+}
+
+sub createDiff
+{
+    my ($key, $str, $i, $head_str);
+
+    &checkUnknown();
+    open(DIFF_fp, ">diff.out");
+    $head_str = " ";
+    for $i ( 0..$#Comparison ) {
+        printf DIFF_fp "Comparison[%d]: %s,%d,%d\n", $i,
+            $Comparison[$i][0], $Comparison[$i][1], $Comparison[$i][2], $Comparison[$i][3];
+        $head_str .= &get_head_str($i);
+    }
+    printf DIFF_fp "\nX| Compare the acct file (first column) with the er_print output (second column):\n";
+    $head_str .= "   Name";
+    printf DIFF_fp "%s\n", $head_str;
+    foreach $key (sort keys %Acct) {
+        $str = &doComp($key, $head_str);
+        printf DIFF_fp "%s\n", $str;
+    }
+    &checkCallersCallees;
+    close(DIFF_fp);
+    &closeDisFile();
+    return -s "discrepancy.out"
+}
+
+sub createDiff2AVG
+{
+    my ($key, $str, $i, $n, $head_str, @avg, $temp, $fname);
+
+    &checkUnknown();
+    open(DIFF_fp, ">>diff.out");
+    printf DIFF_fp "\n==================\n";
+    $head_str = " ";
+    for $i ( 0..$#Comparison ) {
+        printf DIFF_fp "Comparison[%d]: %s,%d\n", $i,
+            $Comparison[$i][0], $Comparison[$i][2];
+        $head_str .= &get_head_str($i);
+    }
+    printf DIFF_fp "\n#| Compare the avg value (first column) with the er_print output (second column):\n";
+    $head_str .= "   Name";
+    printf DIFF_fp "%s\n", $head_str;
+    for $i ( 0..$#Comparison ) {
+        $avg[$i] = 0;
+    }
+    $n=0;
+    foreach $fname (sort keys %Acct) {
+        $n++;
+        for $i ( 0..$#Comparison ) {
+            if ( ! exists $Rules{$fname} ) {
+                if ( exists $Erp->{$fname} ) {
+                    $temp = $Erp->{$fname}[$Comparison[$i][2]];
+                }
+            } else {
+                foreach my $key1 ( @{$Rules{$fname}} ) {
+                    my $sign = 1;
+                    $key = $key1;
+                    if (substr($key1, 0, 1) eq '-') {
+                        $key = substr($key1, 1);
+                        $sign = -1;
+                    }
+                    if ( exists $Erp->{$key} ) {
+                        $temp += $sign * $Erp->{$key}[$Comparison[$i][2]];
+                    }
+                }
+            }
+            $avg[$i] += $temp;
+        }
+    }
+    for $i ( 0..$#Comparison ) {
+            $avg[$i] /= $n;
+    }
+
+    foreach $key (sort keys %Acct) {
+        $str = &doComp2AVG($key, $head_str, @avg);
+        printf DIFF_fp "%s\n", $str;
+    }
+    close(DIFF_fp);
+    &closeDisFile();
+}
+
+sub sumOutlinedCode
+{   # Add a time of the outlined code.
+    my ($name, $eName);
+    foreach $name (keys %Acct) {
+        foreach $eName (keys %$Erp) {
+            next if ("$eName" !~ m/^($name)\s--/);
+            if (defined $Rules{$name}) {
+                push @{$Rules{$name}}, $eName;
+            } else {
+                $Rules{$name} = [$eName];
+            }
+        }
+    }
+}
+
+sub checkCallersCallees
+{
+    my (@arr, $name, $colName, $line, $nline, %Calls);
+
+    open(FP, "<caller_callee.out") or return;
+    while ($line = <FP>) {
+        last if ( $line =~ m/\s+sec.\s+/ );
+    }
+    $nline = 0;
+    while ($line = <FP>) {
+        chomp($line);
+        $line =~ s/^\s*//;   # Delete leading spaces
+        next if ( $line =~ m/^$/ );
+        @arr = split (/\s+/, $line, $colName);
+        $name = pop(@arr);
+        # New Callers-Callees format does not have * in the Stack Fragment section
+        # - translate old format to new format for compatibility
+        if ($name eq "*MAIN") { $name = "MAIN"; };
+        last if ($name eq "MAIN");
+        $nline += 1;
+    }
+    if ($nline == 0) {
+        printf "checkCallersCallees: No Callers of MAIN\n";
+        &set_retVal($ERROR_CALLER_VERIF);
+        close(FP);
+        return;
+    }
+    while ($line = <FP>) {
+        chomp($line);
+        $line =~ s/^\s*//;   # Delete leading spaces
+        next if ( $line =~ m/^$/ );
+        @arr = split (/\s+/, $line, $colName);
+        $name = pop(@arr);
+        $Calls{$name} = 1;
+        if ( $line =~ /Parallel/ ) { #f90synprog M_EXPERT or M_MACHINE
+            @arr = split (/\s\s+/, $line, $colName);
+            $name = pop(@arr);
+            @arr = split (/\s/, $name);
+            $Calls{$arr[0]} = 1;
+        }
+    }
+    close(FP);
+
+    foreach $name (sort keys %Acct) {
+        next if ( $name eq '<Total>' ) ;
+        next if ( $name eq '<Unknown>' ) ;
+        next if (defined $Calls{$name}) ;
+        printf "checkCallersCallees: '$name' is not inside callees\n";
+        &set_retVal($ERROR_CALLER_VERIF);
+    }
+}
+
+
+return 1;
+END{}
+
diff --git a/gprofng/testsuite/lib/display-lib.exp b/gprofng/testsuite/lib/display-lib.exp
new file mode 100644 (file)
index 0000000..38ecb8d
--- /dev/null
@@ -0,0 +1,105 @@
+# Support routines for display-testing machinery in gprofng testsuite.
+#   Copyright (C) 1994-2021 Free Software Foundation, Inc.
+#
+# This file is part of the GNU Binutils.
+#
+# 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; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+# Run the COMMAND on the host and return a list of the form
+# { exit-status OUTPUT }.
+proc run_native_host_cmd { command } {
+    global link_output
+    global ld
+
+    verbose -log "$command"
+    set run_output ""
+    try {
+       set run_output [exec "sh" "-c" "$command" "2>@1"]
+       set status 0
+    } trap CHILDSTATUS {results options} {
+       set status [lindex [dict get $options -errorcode] 2]
+       set run_output $results
+    }
+    regsub "\n$" $run_output "" run_output
+    if { [lindex $status 0] != 0 && [string match "" $run_output] } then {
+       append run_output "child process exited abnormally"
+    }
+
+    if [string match "" $run_output] then {
+       return ""
+    }
+
+    return [list [lindex $status 0] $run_output]
+}
+
+# Run a display test in DIR.
+# Unanswered questions: do we want to cycle through compilation flags,
+# display options, collect flags, app options?  Do we want these to be
+# set on a per-app basis? (If so, they should probably be driven by a
+# file in the test dir.)
+proc run_display_test { dir cflags gprofflags } {
+    global srcdir MAKE CC CFLAGS LDFLAGS LIBS BUILDDIR
+    set stripped [string map {" " ""} $dir]
+    set testdir [string map {" " ""} "$dir.$cflags,$gprofflags"]
+    set sdir "$srcdir/gprofng.display/$dir"
+    set tdir "tmpdir/$testdir"
+       send_log "create dir: $tdir\n"
+       set output [run_native_host_cmd "mkdir -p $tdir"]
+       set gprofng [exec find $BUILDDIR/tmpdir -type f -name gprofng -perm -u+x | head -1]
+
+       set fd [open "$tdir/rules.txt" "w"]
+       switch -regexp -- $testdir {
+         {-p,on.*-h,on} {
+         set DISPLAY_FLAGS "-metrics i.totalcpu:i.cycles -func"
+            puts $fd "Cpu, 2, 0\n"
+            puts $fd "Cycles, 2, 1\n"
+         }
+         {-h,on} {
+         set DISPLAY_FLAGS "-metrics i.cycles -func"
+            puts $fd "Cycles, 2, 0\n"
+         }
+         default {
+         set DISPLAY_FLAGS "-metrics i.totalcpu -func"
+            puts $fd "Cpu, 2, 0\n"
+         }
+       }
+       close $fd 
+
+    set make_args "-f $sdir/Makefile srcdir=\"$sdir\" builddir=\"$BUILDDIR\" \
+        VPATH=\"$dir\" CC=\"$CC\" CFLAGS=\"$cflags\" LDFLAGS=\"$LDFLAGS\" \
+        DISPLAY_FLAGS=\"$DISPLAY_FLAGS\" \
+        COLLECT_FLAGS=\"$gprofflags\" GPROFNG=\"$gprofng\" MAKE=\"$MAKE\""
+    set output [run_native_host_cmd "cd $tdir && $MAKE $make_args all"]
+#      send_log "run_native_host_cmd output:\n$output\n"    
+    if { [lindex $output 0] != 0 } then {
+      set out [lindex $output 1]
+      if {[file exists "$tdir/diff.out"]} then {
+        send_log "comparison of results in $dir failed:\n$out\n"
+        set pltf [exec uname -i]
+        if { $pltf == "aarch64" } {
+          xfail $dir
+          return 0
+        }
+        perror "comparison of results in $dir failed"
+      } else {
+        send_log "compilation of test program in $dir failed:\n$out\n"
+        perror "compilation of test program in $dir failed"
+      }
+      fail $dir
+      return 0
+    }
+    pass $dir
+}
index 416fb6b877881da2feb3c0badabda693d9cce580..6cda7e6cbc531da7fe66c4eab76167ada416887f 100644 (file)
@@ -1,3 +1,9 @@
+2022-03-11  Vladimir Mezentsev  <vladimir.mezentsev@oracle.com>
+
+       * collectorAPI.h: New file.
+       * libcollector.h: New file.
+       * libfcollector.h: New file.
+
 2022-01-25  Klaus Ziegler  <klausz@haus-gisela.de>
 
        PR 28816
diff --git a/include/collectorAPI.h b/include/collectorAPI.h
new file mode 100644 (file)
index 0000000..df0d0cd
--- /dev/null
@@ -0,0 +1,73 @@
+/* Copyright (C) 2021-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.  */
+
+#ifndef _COLLECTORAPI_H
+#define _COLLECTORAPI_H
+
+/* This file contains function prototypes for the user-callable API
+   routines in libcollector.  */
+
+#include <pthread.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+  /* Routine to record a sample in the experiment.  */
+  extern void collector_sample (const char *name);
+
+  /* Routine to suspend data collection during an experiment.  */
+  extern void collector_pause (void);
+
+  /* Routine to resume data collection during an experiment.  */
+  extern void collector_resume (void);
+
+  /* Routine to suspend per-thread data collection during an experiment.  */
+  extern void collector_thread_pause (pthread_t tid);
+
+  /* Routine to resume per-thread data collection during an experiment.  */
+  extern void collector_thread_resume (pthread_t tid);
+
+  /* Routine to close the experiment, and stop all data collection.  */
+  extern void  collector_terminate_expt (void);
+
+  typedef struct
+  {
+    unsigned int offset;
+    unsigned int lineno;
+  } Lineno;
+
+  /* Routines to let libcollector know about dynamically loaded functions.  */
+  extern void collector_func_load (const char *name, const char *alias,
+                                  const char *sourcename, void *vaddr,
+                                  int size, int lntsize, Lineno *lntable);
+
+  extern void collector_func_unload (void *vaddr);
+
+#ifdef NEED_COLLECTOR_MODULE
+  extern void collector_module_load (const char *modulename, void *vaddr);
+  extern void collector_module_unload (void *vaddr);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _COLLECTORAPI_H */
diff --git a/include/libcollector.h b/include/libcollector.h
new file mode 100644 (file)
index 0000000..5627cfd
--- /dev/null
@@ -0,0 +1,89 @@
+/* Copyright (C) 2021-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.  */
+
+#ifndef _LIBCOLLECTOR_H
+#define _LIBCOLLECTOR_H
+
+typedef struct
+{
+  unsigned int offset;
+  unsigned int lineno;
+} Lineno;
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+  /* This file contains function prototypes for the user-callable API
+     routines in libcollector for C and C++ codes.  */
+
+  /* Routine to record a sample in the experiment.  */
+  void collector_sample (char *name);
+
+  /* Routine to suspend data collection during an experiment.  */
+  void collector_pause (void);
+
+  /* Routine to resume data collection during an experiment.  */
+  void collector_resume (void);
+
+  /* Routine to suspend per-thread data collection during an experiment.  */
+  void collector_thread_pause (unsigned int tid);
+
+  /* Routine to resume per-thread data collection during an experiment.  */
+  void collector_thread_resume (unsigned int tid);
+
+  /* Routine to close the experiment, and stop all data collection.  */
+  void collector_terminate_expt (void);
+
+  /* Routines to let libcollector know about a dynamically loaded function.  */
+  void collector_func_load (char *name, char *alias, char *sourcename,
+                         void *vaddr, int size, int lntsize, Lineno *lntable);
+  void collector_func_unload (void *vaddr);
+
+  /* Define the weak symbols for the API.  */
+  void collector_sample () __attribute__ ((weak));
+  void collector_pause () __attribute__ ((weak));
+  void collector_resume () __attribute__ ((weak));
+  void collector_thread_pause () __attribute__ ((weak));
+  void collector_thread_resume () __attribute__ ((weak));
+  void collector_terminate_expt () __attribute__ ((weak));
+  void collector_func_load () __attribute__ ((weak));
+  void collector_func_unload () __attribute__ ((weak));
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Define the macros that actually get inserted in the caller's code.  */
+#define collector_sample(x)    (collector_sample ? collector_sample(x), 0 : 0)
+#define collector_pause()      (collector_pause ? collector_pause(), 0 : 0)
+#define collector_resume()     (collector_resume ? collector_resume(),0 : 0 
+#define collector_thread_pause(tid) \
+       (collector_thread_pause ? collector_thread_pause(tid), 0 : 0)
+#define collector_thread_resume(tid) \
+       (collector_thread_resume ? collector_thread_resume(tid), 0 : 0)
+#define collector_terminate_expt() \
+       (collector_terminate_expt ? collector_terminate_expt(), 0 : 0)
+#define collector_func_load(x0,x1,x2,x3,x4,x5,x6) \
+       collector_func_load ? collector_func_load(x0,x1,x2,x3,x4,x5,x6), 0 : 0)
+#define collector_func_unload(x) \
+       (collector_func_unload ? collector_func_unload(x), 0 : 0)
+#endif /* _LIBCOLLECTOR_H */
diff --git a/include/libfcollector.h b/include/libfcollector.h
new file mode 100644 (file)
index 0000000..c9a840a
--- /dev/null
@@ -0,0 +1,42 @@
+! Copyright (C) 2021-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.
+!
+! Developer Sampling Collector interface include file
+
+        interface
+
+        ! Routine to record a sample in the experiment.
+        subroutine collector_sample(name)
+        character(len=*), intent(in) :: name
+        end subroutine
+
+        ! Routine to suspend data collection during an experiment.
+        subroutine collector_pause()
+        end subroutine
+
+        ! Routine to resume data collection during an experiment.
+        subroutine collector_resume()
+        end subroutine
+
+        ! Routine to stop all data collection and close the experiment.
+        subroutine collector_terminate_expt()
+        end subroutine
+
+        end interface
index 86f6802f96a959480aac82b142ae7d8f00a25c44..079b545ae7cec242defd6ac7c0644ca35e9255e6 100755 (executable)
@@ -93,7 +93,7 @@ do_proto_toplev()
     # built in the gold dir.  The disables speed the build a little.
     enables=
     disables=
-    for dir in binutils gas gdb gold gprof ld libctf libdecnumber readline sim; do
+    for dir in binutils gas gdb gold gprof gprofng ld libctf libdecnumber readline sim; do
        case " $tool $support_files " in
            *" $dir "*) enables="$enables --enable-$dir" ;;
            *) disables="$disables --disable-$dir" ;;
@@ -295,7 +295,7 @@ gdb_tar_compress()
 }
 
 # The FSF "binutils" release includes gprof and ld.
-BINUTILS_SUPPORT_DIRS="bfd gas include libiberty libctf opcodes ld elfcpp gold gprof intl setup.com makefile.vms cpu zlib"
+BINUTILS_SUPPORT_DIRS="bfd gas include libiberty libctf opcodes ld elfcpp gold gprof gprofng intl setup.com makefile.vms cpu zlib"
 binutils_release()
 {
     compressors=$1