aboutsummaryrefslogtreecommitdiff
path: root/gprofng
diff options
context:
space:
mode:
authorVladimir Mezentsev <vladimir.mezentsev@oracle.com>2022-03-11 08:58:31 +0000
committerNick Clifton <nickc@redhat.com>2022-03-11 08:58:31 +0000
commitbb368aad297fe3ad40cf397e6fc85aa471429a28 (patch)
tree0ab25909b8fe789d676bbdb00d501d4d485e4afe /gprofng
parenta655f19af95eb685ba64f48ee8fc2b3b7a3d886a (diff)
downloadbinutils-bb368aad297fe3ad40cf397e6fc85aa471429a28.zip
binutils-bb368aad297fe3ad40cf397e6fc85aa471429a28.tar.gz
binutils-bb368aad297fe3ad40cf397e6fc85aa471429a28.tar.bz2
gprofng: a new GNU profiler
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.
Diffstat (limited to 'gprofng')
-rw-r--r--gprofng/Makefile.am79
-rw-r--r--gprofng/Makefile.in940
-rw-r--r--gprofng/README100
-rw-r--r--gprofng/acinclude.m44
-rw-r--r--gprofng/aclocal.m41254
-rw-r--r--gprofng/common/cc_libcollector.h44
-rw-r--r--gprofng/common/config.h.in117
-rw-r--r--gprofng/common/core_pcbe.c3023
-rw-r--r--gprofng/common/cpu_frequency.h303
-rw-r--r--gprofng/common/cpuid.c203
-rw-r--r--gprofng/common/gp-defs.h58
-rw-r--r--gprofng/common/gp-experiment.h186
-rw-r--r--gprofng/common/gp-time.h46
-rw-r--r--gprofng/common/hwc_cpus.h198
-rw-r--r--gprofng/common/hwcdrv.c1454
-rw-r--r--gprofng/common/hwcdrv.h330
-rw-r--r--gprofng/common/hwcentry.h417
-rw-r--r--gprofng/common/hwcfuncs.c704
-rw-r--r--gprofng/common/hwcfuncs.h269
-rw-r--r--gprofng/common/hwctable.c5410
-rw-r--r--gprofng/common/opteron_pcbe.c448
-rw-r--r--gprofng/config/bison.m492
-rwxr-xr-xgprofng/configure19350
-rw-r--r--gprofng/configure.ac189
-rw-r--r--gprofng/doc/Makefile.am37
-rw-r--r--gprofng/doc/Makefile.in834
-rw-r--r--gprofng/doc/fdl.texi506
-rw-r--r--gprofng/doc/gprofng.texi3399
-rwxr-xr-xgprofng/doc/mdate-sh224
-rw-r--r--gprofng/doc/texinfo.tex11731
-rw-r--r--gprofng/doc/version.texi4
-rw-r--r--gprofng/gp-display-html/Makefile.am60
-rw-r--r--gprofng/gp-display-html/Makefile.in630
-rw-r--r--gprofng/gp-display-html/gp-display-html.in256
-rwxr-xr-xgprofng/libcollector/CHK_LIBC_OBJ82
-rw-r--r--gprofng/libcollector/Makefile.am79
-rw-r--r--gprofng/libcollector/Makefile.in1131
-rw-r--r--gprofng/libcollector/aclocal.m41237
-rw-r--r--gprofng/libcollector/collector.c2494
-rw-r--r--gprofng/libcollector/collector.h236
-rw-r--r--gprofng/libcollector/collectorAPI.c140
-rwxr-xr-xgprofng/libcollector/configure18081
-rw-r--r--gprofng/libcollector/configure.ac60
-rw-r--r--gprofng/libcollector/descendants.h81
-rw-r--r--gprofng/libcollector/dispatcher.c1263
-rw-r--r--gprofng/libcollector/envmgmt.c840
-rw-r--r--gprofng/libcollector/gethrtime.c41
-rw-r--r--gprofng/libcollector/heaptrace.c503
-rw-r--r--gprofng/libcollector/hwprofile.c905
-rw-r--r--gprofng/libcollector/hwprofile.h89
-rw-r--r--gprofng/libcollector/iolib.c1156
-rw-r--r--gprofng/libcollector/iotrace.c3728
-rw-r--r--gprofng/libcollector/jprofile.c1315
-rw-r--r--gprofng/libcollector/libcol-i386-dis.c28
-rw-r--r--gprofng/libcollector/libcol_hwcdrv.c25
-rw-r--r--gprofng/libcollector/libcol_hwcfuncs.c27
-rw-r--r--gprofng/libcollector/libcol_util.c1693
-rw-r--r--gprofng/libcollector/libcol_util.h321
-rw-r--r--gprofng/libcollector/linetrace.c2005
-rw-r--r--gprofng/libcollector/mapfile.aarch64-Linux40
-rw-r--r--gprofng/libcollector/mapfile.amd64-Linux79
-rw-r--r--gprofng/libcollector/mapfile.intel-Linux81
-rw-r--r--gprofng/libcollector/mapfile.sparc-Linux40
-rw-r--r--gprofng/libcollector/mapfile.sparcv9-Linux58
-rw-r--r--gprofng/libcollector/memmgr.c396
-rw-r--r--gprofng/libcollector/memmgr.h59
-rw-r--r--gprofng/libcollector/mmaptrace.c1691
-rw-r--r--gprofng/libcollector/profile.c287
-rw-r--r--gprofng/libcollector/synctrace.c1064
-rw-r--r--gprofng/libcollector/tsd.c149
-rw-r--r--gprofng/libcollector/tsd.h80
-rw-r--r--gprofng/libcollector/unwind.c4630
-rw-r--r--gprofng/src/ABS.h62
-rw-r--r--gprofng/src/Application.cc259
-rw-r--r--gprofng/src/Application.h108
-rw-r--r--gprofng/src/ArchiveExp.cc149
-rw-r--r--gprofng/src/ArchiveExp.h41
-rw-r--r--gprofng/src/BaseMetric.cc975
-rw-r--r--gprofng/src/BaseMetric.h246
-rw-r--r--gprofng/src/BaseMetricTreeNode.cc329
-rw-r--r--gprofng/src/BaseMetricTreeNode.h100
-rw-r--r--gprofng/src/CacheMap.h186
-rw-r--r--gprofng/src/CallStack.cc1250
-rw-r--r--gprofng/src/CallStack.h114
-rw-r--r--gprofng/src/CatchOutOfMemory.cc59
-rw-r--r--gprofng/src/ClassFile.cc1639
-rw-r--r--gprofng/src/ClassFile.h63
-rw-r--r--gprofng/src/Command.cc562
-rw-r--r--gprofng/src/Command.h286
-rw-r--r--gprofng/src/CompCom.cc313
-rw-r--r--gprofng/src/CompCom.h63
-rw-r--r--gprofng/src/DataObject.cc193
-rw-r--r--gprofng/src/DataObject.h82
-rw-r--r--gprofng/src/DataSpace.cc558
-rw-r--r--gprofng/src/DataSpace.h55
-rw-r--r--gprofng/src/DataStream.cc55
-rw-r--r--gprofng/src/DataStream.h51
-rw-r--r--gprofng/src/Data_window.cc241
-rw-r--r--gprofng/src/Data_window.h99
-rw-r--r--gprofng/src/Dbe.cc10371
-rw-r--r--gprofng/src/Dbe.h294
-rw-r--r--gprofng/src/DbeApplication.cc113
-rw-r--r--gprofng/src/DbeApplication.h50
-rw-r--r--gprofng/src/DbeArray.h99
-rw-r--r--gprofng/src/DbeCacheMap.h109
-rw-r--r--gprofng/src/DbeFile.cc541
-rw-r--r--gprofng/src/DbeFile.h103
-rw-r--r--gprofng/src/DbeJarFile.cc505
-rw-r--r--gprofng/src/DbeJarFile.h46
-rw-r--r--gprofng/src/DbeLinkList.h73
-rw-r--r--gprofng/src/DbeLock.cc41
-rw-r--r--gprofng/src/DbeLock.h38
-rw-r--r--gprofng/src/DbeSession.cc3527
-rw-r--r--gprofng/src/DbeSession.cc.13531
-rw-r--r--gprofng/src/DbeSession.h481
-rw-r--r--gprofng/src/DbeSyncMap.h224
-rw-r--r--gprofng/src/DbeThread.cc224
-rw-r--r--gprofng/src/DbeThread.h61
-rw-r--r--gprofng/src/DbeView.cc3126
-rw-r--r--gprofng/src/DbeView.h842
-rw-r--r--gprofng/src/DefaultHandler.h114
-rw-r--r--gprofng/src/DefaultMap.h232
-rw-r--r--gprofng/src/DefaultMap2D.h147
-rw-r--r--gprofng/src/DerivedMetrics.cc293
-rw-r--r--gprofng/src/DerivedMetrics.h54
-rw-r--r--gprofng/src/Disasm.cc403
-rw-r--r--gprofng/src/Disasm.h66
-rw-r--r--gprofng/src/Dwarf.cc1041
-rw-r--r--gprofng/src/Dwarf.h87
-rw-r--r--gprofng/src/DwarfLib.cc2203
-rw-r--r--gprofng/src/DwarfLib.h313
-rw-r--r--gprofng/src/Elf.cc1138
-rw-r--r--gprofng/src/Elf.h170
-rw-r--r--gprofng/src/Emsg.cc614
-rw-r--r--gprofng/src/Emsg.h112
-rw-r--r--gprofng/src/Emsgnum.h135
-rw-r--r--gprofng/src/ExpGroup.cc163
-rw-r--r--gprofng/src/ExpGroup.h50
-rw-r--r--gprofng/src/Exp_Layout.cc422
-rw-r--r--gprofng/src/Exp_Layout.h158
-rw-r--r--gprofng/src/Experiment.cc6961
-rw-r--r--gprofng/src/Experiment.h689
-rw-r--r--gprofng/src/Expression.cc1279
-rw-r--r--gprofng/src/Expression.h180
-rw-r--r--gprofng/src/FileData.cc400
-rw-r--r--gprofng/src/FileData.h522
-rw-r--r--gprofng/src/Filter.cc514
-rw-r--r--gprofng/src/Filter.h111
-rw-r--r--gprofng/src/FilterExp.h56
-rw-r--r--gprofng/src/FilterSet.cc106
-rw-r--r--gprofng/src/FilterSet.h72
-rw-r--r--gprofng/src/Function.cc1160
-rw-r--r--gprofng/src/Function.h222
-rw-r--r--gprofng/src/HashMap.h435
-rw-r--r--gprofng/src/HeapActivity.cc408
-rw-r--r--gprofng/src/HeapActivity.h76
-rw-r--r--gprofng/src/HeapData.cc284
-rw-r--r--gprofng/src/HeapData.h450
-rw-r--r--gprofng/src/HeapMap.cc325
-rw-r--r--gprofng/src/HeapMap.h59
-rw-r--r--gprofng/src/Hist_data.cc1886
-rw-r--r--gprofng/src/Hist_data.h292
-rw-r--r--gprofng/src/Histable.h333
-rw-r--r--gprofng/src/IOActivity.cc825
-rw-r--r--gprofng/src/IOActivity.h86
-rw-r--r--gprofng/src/IndexMap2D.h119
-rw-r--r--gprofng/src/IndexObject.cc554
-rw-r--r--gprofng/src/IndexObject.h111
-rw-r--r--gprofng/src/IntervalMap.h194
-rw-r--r--gprofng/src/LoadObject.cc1242
-rw-r--r--gprofng/src/LoadObject.h210
-rw-r--r--gprofng/src/MachineModel.cc317
-rw-r--r--gprofng/src/Makefile.am202
-rw-r--r--gprofng/src/Makefile.in1171
-rw-r--r--gprofng/src/Map.h61
-rw-r--r--gprofng/src/Map2D.h53
-rw-r--r--gprofng/src/MemObject.cc44
-rw-r--r--gprofng/src/MemObject.h62
-rw-r--r--gprofng/src/MemorySpace.cc452
-rw-r--r--gprofng/src/MemorySpace.h113
-rw-r--r--gprofng/src/Metric.cc1660
-rw-r--r--gprofng/src/Metric.h188
-rw-r--r--gprofng/src/MetricList.cc1075
-rw-r--r--gprofng/src/MetricList.h163
-rw-r--r--gprofng/src/Module.cc1840
-rw-r--r--gprofng/src/Module.h284
-rw-r--r--gprofng/src/Ovw_data.cc242
-rw-r--r--gprofng/src/Ovw_data.h102
-rw-r--r--gprofng/src/PRBTree.cc480
-rw-r--r--gprofng/src/PRBTree.h106
-rw-r--r--gprofng/src/PathTree.cc2637
-rw-r--r--gprofng/src/PathTree.h405
-rw-r--r--gprofng/src/PreviewExp.cc113
-rw-r--r--gprofng/src/PreviewExp.h49
-rw-r--r--gprofng/src/Print.cc3485
-rw-r--r--gprofng/src/Print.h283
-rw-r--r--gprofng/src/QLParser.h61
-rw-r--r--gprofng/src/QLParser.tab.cc1453
-rw-r--r--gprofng/src/QLParser.tab.hh2038
-rw-r--r--gprofng/src/QLParser.yy390
-rw-r--r--gprofng/src/SAXParser.h49
-rw-r--r--gprofng/src/SAXParserFactory.cc666
-rw-r--r--gprofng/src/SAXParserFactory.h75
-rw-r--r--gprofng/src/Sample.cc94
-rw-r--r--gprofng/src/Sample.h80
-rw-r--r--gprofng/src/SegMem.h76
-rw-r--r--gprofng/src/Settings.cc1586
-rw-r--r--gprofng/src/Settings.h425
-rw-r--r--gprofng/src/SourceFile.cc229
-rw-r--r--gprofng/src/SourceFile.h117
-rw-r--r--gprofng/src/Stabs.cc2650
-rw-r--r--gprofng/src/Stabs.h160
-rw-r--r--gprofng/src/Stats_data.cc203
-rw-r--r--gprofng/src/Stats_data.h59
-rw-r--r--gprofng/src/StringBuilder.cc585
-rw-r--r--gprofng/src/StringBuilder.h101
-rw-r--r--gprofng/src/StringMap.h238
-rw-r--r--gprofng/src/Table.cc1687
-rw-r--r--gprofng/src/Table.h618
-rw-r--r--gprofng/src/UserLabel.cc177
-rw-r--r--gprofng/src/UserLabel.h61
-rw-r--r--gprofng/src/checks.cc516
-rw-r--r--gprofng/src/collctrl.cc3149
-rw-r--r--gprofng/src/collctrl.h405
-rw-r--r--gprofng/src/collect.h156
-rw-r--r--gprofng/src/collector_module.h223
-rw-r--r--gprofng/src/comp_com.c3481
-rw-r--r--gprofng/src/comp_com.h903
-rw-r--r--gprofng/src/count.cc237
-rw-r--r--gprofng/src/data_pckts.h595
-rw-r--r--gprofng/src/dbe_collctrl.cc28
-rw-r--r--gprofng/src/dbe_hwc.h38
-rw-r--r--gprofng/src/dbe_hwcdrv.c23
-rw-r--r--gprofng/src/dbe_hwcfuncs.c23
-rw-r--r--gprofng/src/dbe_hwctable.c23
-rw-r--r--gprofng/src/dbe_memmgr.c118
-rw-r--r--gprofng/src/dbe_structs.h219
-rw-r--r--gprofng/src/dbe_types.h62
-rw-r--r--gprofng/src/debug.h89
-rw-r--r--gprofng/src/enums.h195
-rw-r--r--gprofng/src/envsets.cc420
-rw-r--r--gprofng/src/gethrtime.c166
-rw-r--r--gprofng/src/gp-archive.cc700
-rw-r--r--gprofng/src/gp-archive.h64
-rw-r--r--gprofng/src/gp-collect-app.cc1598
-rw-r--r--gprofng/src/gp-display-src.cc752
-rw-r--r--gprofng/src/gp-display-text.cc2834
-rw-r--r--gprofng/src/gp-print.h118
-rw-r--r--gprofng/src/gprofng.cc301
-rw-r--r--gprofng/src/gprofng.h2m4
-rw-r--r--gprofng/src/gprofng.rc132
-rw-r--r--gprofng/src/i18n.cc30
-rw-r--r--gprofng/src/i18n.h40
-rw-r--r--gprofng/src/info.h73
-rw-r--r--gprofng/src/ipc.cc2829
-rw-r--r--gprofng/src/ipcio.cc1025
-rw-r--r--gprofng/src/ipcio.h176
-rw-r--r--gprofng/src/machinemodels/generic.ermm32
-rw-r--r--gprofng/src/machinemodels/m5.ermm65
-rw-r--r--gprofng/src/machinemodels/m6.ermm65
-rw-r--r--gprofng/src/machinemodels/m7.ermm64
-rw-r--r--gprofng/src/machinemodels/t4.ermm67
-rw-r--r--gprofng/src/machinemodels/t5.ermm65
-rw-r--r--gprofng/src/parse.cc927
-rw-r--r--gprofng/src/stab.h205
-rw-r--r--gprofng/src/util.cc1582
-rw-r--r--gprofng/src/util.h185
-rw-r--r--gprofng/src/vec.h524
-rw-r--r--gprofng/testsuite/config/default.exp38
-rw-r--r--gprofng/testsuite/gprofng.display/display.exp86
-rw-r--r--gprofng/testsuite/gprofng.display/jsynprog/Intface.java6
-rw-r--r--gprofng/testsuite/gprofng.display/jsynprog/Launcher.java90
-rw-r--r--gprofng/testsuite/gprofng.display/jsynprog/Makefile56
-rw-r--r--gprofng/testsuite/gprofng.display/jsynprog/Routine.java224
-rw-r--r--gprofng/testsuite/gprofng.display/jsynprog/Sub_Routine.java54
-rwxr-xr-xgprofng/testsuite/gprofng.display/jsynprog/check_results.pl33
-rw-r--r--gprofng/testsuite/gprofng.display/jsynprog/cloop.cc114
-rw-r--r--gprofng/testsuite/gprofng.display/jsynprog/jsynprog.h74
-rw-r--r--gprofng/testsuite/gprofng.display/jsynprog/jsynprog.java229
-rw-r--r--gprofng/testsuite/gprofng.display/mttest/Makefile41
-rw-r--r--gprofng/testsuite/gprofng.display/mttest/check_results.pl46
-rw-r--r--gprofng/testsuite/gprofng.display/mttest/gethrtime.c265
-rw-r--r--gprofng/testsuite/gprofng.display/mttest/mttest.c1306
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/Makefile66
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/callso.c152
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/callsx.c152
-rwxr-xr-xgprofng/testsuite/gprofng.display/synprog/check_results.pl40
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/endcases.c208
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/fitos.c78
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/inc_body.h26
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/inc_brace.h26
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/inc_entry.h24
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/inc_exit.h25
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/inc_func.h28
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/inc_inline.h32
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/inc_macro.h26
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/iosyn.c614
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/pagethrash.c75
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/so_syn.c69
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/so_syx.c68
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/stopwatch.c294
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/stopwatch.h61
-rw-r--r--gprofng/testsuite/gprofng.display/synprog/synprog.c1823
-rw-r--r--gprofng/testsuite/lib/Makefile.skel61
-rw-r--r--gprofng/testsuite/lib/acct.pm774
-rw-r--r--gprofng/testsuite/lib/display-lib.exp105
306 files changed, 222206 insertions, 0 deletions
diff --git a/gprofng/Makefile.am b/gprofng/Makefile.am
new file mode 100644
index 0000000..3bf7074
--- /dev/null
+++ b/gprofng/Makefile.am
@@ -0,0 +1,79 @@
+## Process this file with automake to generate Makefile.in
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+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
index 0000000..08ffdd2
--- /dev/null
+++ b/gprofng/Makefile.in
@@ -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
index 0000000..66d2e7c
--- /dev/null
+++ b/gprofng/README
@@ -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
index 0000000..966da18
--- /dev/null
+++ b/gprofng/acinclude.m4
@@ -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
index 0000000..02b07b9
--- /dev/null
+++ b/gprofng/aclocal.m4
@@ -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
index 0000000..e078541
--- /dev/null
+++ b/gprofng/common/cc_libcollector.h
@@ -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
index 0000000..e46e64f
--- /dev/null
+++ b/gprofng/common/config.h.in
@@ -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
index 0000000..6f746d8
--- /dev/null
+++ b/gprofng/common/core_pcbe.c
@@ -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
index 0000000..b46b54d
--- /dev/null
+++ b/gprofng/common/cpu_frequency.h
@@ -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
index 0000000..211e09a
--- /dev/null
+++ b/gprofng/common/cpuid.c
@@ -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
index 0000000..440bfb1
--- /dev/null
+++ b/gprofng/common/gp-defs.h
@@ -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
index 0000000..040c2d1
--- /dev/null
+++ b/gprofng/common/gp-experiment.h
@@ -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
index 0000000..7755370
--- /dev/null
+++ b/gprofng/common/gp-time.h
@@ -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
index 0000000..ff7b303
--- /dev/null
+++ b/gprofng/common/hwc_cpus.h
@@ -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
index 0000000..caab983
--- /dev/null
+++ b/gprofng/common/hwcdrv.c
@@ -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
index 0000000..14c55cf
--- /dev/null
+++ b/gprofng/common/hwcdrv.h
@@ -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
index 0000000..8611ab7
--- /dev/null
+++ b/gprofng/common/hwcentry.h
@@ -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
index 0000000..2f9764d
--- /dev/null
+++ b/gprofng/common/hwcfuncs.c
@@ -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
index 0000000..ef0360b
--- /dev/null
+++ b/gprofng/common/hwcfuncs.h
@@ -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
index 0000000..bc441e1
--- /dev/null
+++ b/gprofng/common/hwctable.c
@@ -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
index 0000000..d479945
--- /dev/null
+++ b/gprofng/common/opteron_pcbe.c
@@ -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
index 0000000..0493587
--- /dev/null
+++ b/gprofng/config/bison.m4
@@ -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
index 0000000..3cf4dc7
--- /dev/null
+++ b/gprofng/configure
@@ -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 = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named 'Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running 'make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "$am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir=$dirpart/$fdir; as_fn_mkdir_p
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+ ;;
+ "libtool":C)
+
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags="CXX "
+
+# ### BEGIN LIBTOOL CONFIG
+
+# 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
index 0000000..8977e8b
--- /dev/null
+++ b/gprofng/configure.ac
@@ -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
index 0000000..3dc2cac
--- /dev/null
+++ b/gprofng/doc/Makefile.am
@@ -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
index 0000000..31e298c
--- /dev/null
+++ b/gprofng/doc/Makefile.in
@@ -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
index 0000000..8805f1a
--- /dev/null
+++ b/gprofng/doc/fdl.texi
@@ -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
index 0000000..3e75a6c
--- /dev/null
+++ b/gprofng/doc/gprofng.texi
@@ -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
index 0000000..f80075c
--- /dev/null
+++ b/gprofng/doc/mdate-sh
@@ -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
index 0000000..2bab634
--- /dev/null
+++ b/gprofng/doc/texinfo.tex
@@ -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}
+
+% 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
index 0000000..d282161
--- /dev/null
+++ b/gprofng/doc/version.texi
@@ -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
index 0000000..7fc27d1
--- /dev/null
+++ b/gprofng/gp-display-html/Makefile.am
@@ -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
index 0000000..10f59ee
--- /dev/null
+++ b/gprofng/gp-display-html/Makefile.in
@@ -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
index 0000000..f8fbc24
--- /dev/null
+++ b/gprofng/gp-display-html/gp-display-html.in
@@ -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
index 0000000..dbeb9cb
--- /dev/null
+++ b/gprofng/libcollector/CHK_LIBC_OBJ
@@ -0,0 +1,82 @@
+#!/bin/sh
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+#
+# CHK_LIBC_OBJ -- a script to scan the .o's in an output directory,
+# which is one of ../{intel-S2,sparc-S2,intel-Linux,sparc-Linux}
+#
+# usage: cd to the output directory, and invoke ../src/CHK_LIBC_OBJ
+
+
+check_obj() {
+ logF="nm.`basename $1`.log"
+ if [ `uname` = 'Linux' ]; then
+ nm $1 | grep -v GLIBC_ > ${logF}
+ else
+ nm $1 > ${logF}
+ fi
+
+ FUNC_LIST="strcpy strlcpy strncpy strcat strlcat strncat strncmp strlen \
+ strerror strchr strrchr strpbrk strstr strtok strtok_r \
+ printf fprintf sprintf snprintf asprintf wsprintf \
+ vprintf vfprintf vsprintf vsnprintf vasprintf \
+ memset memcmp memcpy strtol strtoll strtoul strtoull \
+ getcpuid calloc malloc free strdup"
+ res=0
+ echo " -- Checking Object file '$1' for functions from libc"
+ for j in `echo ${FUNC_LIST}` ; do
+ grep -w ${j} ${logF} | grep UNDEF> grep.log 2>&1
+ if [ $? -eq 0 ]; then
+ grep -w ${j} ${logF}
+ res=1
+ fi
+ done
+ return ${res}
+}
+
+STATUS=0
+
+for i in *.o ; do
+ echo ""
+ check_obj ${i}
+ res=$?
+ if [ ${res} -eq 0 ]; then
+ echo "Object file ${i} does not reference functions in libc"
+ else
+ echo "======Object file: ${i} DOES reference functions in libc"
+ fi
+ if [ ${STATUS} -eq 0 ]; then
+ STATUS=${res}
+ fi
+done
+
+for i in *.so ; do
+ echo ""
+ check_obj ${i}
+ res=$?
+ if [ ${res} -eq 0 ]; then
+ echo "Object file ${i} does not reference functions in libc"
+ else
+ echo "======Object file: ${i} DOES reference functions in libc"
+ fi
+ if [ ${STATUS} -eq 0 ]; then
+ STATUS=${res}
+ fi
+done
+
+exit $STATUS
diff --git a/gprofng/libcollector/Makefile.am b/gprofng/libcollector/Makefile.am
new file mode 100644
index 0000000..bd86e97
--- /dev/null
+++ b/gprofng/libcollector/Makefile.am
@@ -0,0 +1,79 @@
+## Process this file with automake to generate Makefile.in
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+AUTOMAKE_OPTIONS = foreign
+ACLOCAL_AMFLAGS = -I . -I ../..
+
+GPROFNG_VARIANT = @GPROFNG_VARIANT@
+
+CSOURCES = \
+ gethrtime.c \
+ dispatcher.c \
+ iolib.c \
+ mmaptrace.c \
+ memmgr.c \
+ tsd.c \
+ profile.c \
+ envmgmt.c \
+ linetrace.c \
+ libcol_hwcdrv.c \
+ libcol_hwcfuncs.c \
+ libcol-i386-dis.c \
+ hwprofile.c \
+ jprofile.c \
+ unwind.c \
+ libcol_util.c \
+ collector.c \
+ $(NULL)
+
+AM_CFLAGS = $(GPROFNG_CFLAGS) -Wno-nonnull-compare
+AM_CPPFLAGS = $(GPROFNG_CPPFLAGS) -I.. -I$(srcdir) \
+ -I$(srcdir)/../common -I$(srcdir)/../src \
+ -I$(srcdir)/../../include
+AM_LDFLAGS = -module -avoid-version \
+ -Wl,--version-script,$(srcdir)/mapfile.$(GPROFNG_VARIANT) \
+ $(LD_NO_AS_NEEDED) -Wl,-lrt -Wl,-ldl
+
+myincludedir = @includedir@
+myinclude_HEADERS = $(srcdir)/../../include/collectorAPI.h \
+ $(srcdir)/../../include/libcollector.h \
+ $(srcdir)/../../include/libfcollector.h
+
+lib_LTLIBRARIES = libgp-collector.la libgp-collectorAPI.la libgp-heap.la \
+ libgp-sync.la libgp-iotrace.la
+
+libgp_collector_la_SOURCES = $(CSOURCES)
+libgp_collector_la_CPPFLAGS = $(AM_CPPFLAGS) $(jdk_inc) \
+ -I../../bfd -I$(srcdir)/../..
+# Prevent libtool from reordering -Wl,--no-as-needed after -lrt by
+# disguising -lrt as a linker flag.
+libgp_collector_la_LDFLAGS = $(AM_LDFLAGS)
+libgp_collector_la_LIBADD =
+
+libgp_heap_la_SOURCES = heaptrace.c
+libgp_heap_la_LDFLAGS = $(AM_LDFLAGS)
+
+libgp_sync_la_SOURCES = synctrace.c
+libgp_sync_la_LDFLAGS = $(AM_LDFLAGS)
+
+libgp_iotrace_la_SOURCES = iotrace.c
+libgp_iotrace_la_LDFLAGS = $(AM_LDFLAGS)
+
+libgp_collectorAPI_la_SOURCES = collectorAPI.c
+libgp_collectorAPI_la_LIBADD = -lc -ldl
+
diff --git a/gprofng/libcollector/Makefile.in b/gprofng/libcollector/Makefile.in
new file mode 100644
index 0000000..920c7a7
--- /dev/null
+++ b/gprofng/libcollector/Makefile.in
@@ -0,0 +1,1131 @@
+# Makefile.in generated by automake 1.15.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2017 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#
+# Copyright (C) 2021 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = .
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/../../config/depstand.m4 \
+ $(top_srcdir)/../../config/lead-dot.m4 \
+ $(top_srcdir)/../../config/override.m4 \
+ $(top_srcdir)/../../libtool.m4 \
+ $(top_srcdir)/../../ltoptions.m4 \
+ $(top_srcdir)/../../ltsugar.m4 \
+ $(top_srcdir)/../../ltversion.m4 \
+ $(top_srcdir)/../../lt~obsolete.m4 \
+ $(top_srcdir)/../../bfd/version.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
+ $(am__configure_deps) $(myinclude_HEADERS) $(am__DIST_COMMON)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(SHELL) $(top_srcdir)/../../mkinstalldirs
+CONFIG_HEADER = lib-config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(myincludedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libgp_collector_la_DEPENDENCIES =
+am__objects_1 = libgp_collector_la-gethrtime.lo \
+ libgp_collector_la-dispatcher.lo libgp_collector_la-iolib.lo \
+ libgp_collector_la-mmaptrace.lo libgp_collector_la-memmgr.lo \
+ libgp_collector_la-tsd.lo libgp_collector_la-profile.lo \
+ libgp_collector_la-envmgmt.lo libgp_collector_la-linetrace.lo \
+ libgp_collector_la-libcol_hwcdrv.lo \
+ libgp_collector_la-libcol_hwcfuncs.lo \
+ libgp_collector_la-libcol-i386-dis.lo \
+ libgp_collector_la-hwprofile.lo libgp_collector_la-jprofile.lo \
+ libgp_collector_la-unwind.lo libgp_collector_la-libcol_util.lo \
+ libgp_collector_la-collector.lo
+am_libgp_collector_la_OBJECTS = $(am__objects_1)
+libgp_collector_la_OBJECTS = $(am_libgp_collector_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgp_collector_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libgp_collector_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+libgp_collectorAPI_la_DEPENDENCIES =
+am_libgp_collectorAPI_la_OBJECTS = collectorAPI.lo
+libgp_collectorAPI_la_OBJECTS = $(am_libgp_collectorAPI_la_OBJECTS)
+libgp_heap_la_LIBADD =
+am_libgp_heap_la_OBJECTS = heaptrace.lo
+libgp_heap_la_OBJECTS = $(am_libgp_heap_la_OBJECTS)
+libgp_heap_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libgp_heap_la_LDFLAGS) $(LDFLAGS) -o $@
+libgp_iotrace_la_LIBADD =
+am_libgp_iotrace_la_OBJECTS = iotrace.lo
+libgp_iotrace_la_OBJECTS = $(am_libgp_iotrace_la_OBJECTS)
+libgp_iotrace_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libgp_iotrace_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+libgp_sync_la_LIBADD =
+am_libgp_sync_la_OBJECTS = synctrace.lo
+libgp_sync_la_OBJECTS = $(am_libgp_sync_la_OBJECTS)
+libgp_sync_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libgp_sync_la_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@
+depcomp = $(SHELL) $(top_srcdir)/../../depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgp_collector_la_SOURCES) \
+ $(libgp_collectorAPI_la_SOURCES) $(libgp_heap_la_SOURCES) \
+ $(libgp_iotrace_la_SOURCES) $(libgp_sync_la_SOURCES)
+DIST_SOURCES = $(libgp_collector_la_SOURCES) \
+ $(libgp_collectorAPI_la_SOURCES) $(libgp_heap_la_SOURCES) \
+ $(libgp_iotrace_la_SOURCES) $(libgp_sync_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+HEADERS = $(myinclude_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+AM_RECURSIVE_TARGETS = cscope
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/../../ar-lib \
+ $(top_srcdir)/../../compile $(top_srcdir)/../../config.guess \
+ $(top_srcdir)/../../config.sub $(top_srcdir)/../../depcomp \
+ $(top_srcdir)/../../install-sh $(top_srcdir)/../../ltmain.sh \
+ $(top_srcdir)/../../missing $(top_srcdir)/../../mkinstalldirs \
+ $(top_srcdir)/../common/config.h.in ../../COPYING \
+ ../../COPYING.LIB ../../ChangeLog ../../README ../../ar-lib \
+ ../../compile ../../config.guess ../../config.rpath \
+ ../../config.sub ../../depcomp ../../install-sh \
+ ../../ltmain.sh ../../missing ../../mkinstalldirs ../../ylwrap
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ if test -d "$(distdir)"; then \
+ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -rf "$(distdir)" \
+ || { sleep 5 && rm -rf "$(distdir)"; }; \
+ else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+DIST_ARCHIVES = $(distdir).tar.gz
+GZIP_ENV = --best
+DIST_TARGETS = dist-gzip
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GPROFNG_VARIANT = @GPROFNG_VARIANT@
+GREP = @GREP@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+VERSION = @VERSION@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = foreign
+ACLOCAL_AMFLAGS = -I . -I ../..
+CSOURCES = \
+ gethrtime.c \
+ dispatcher.c \
+ iolib.c \
+ mmaptrace.c \
+ memmgr.c \
+ tsd.c \
+ profile.c \
+ envmgmt.c \
+ linetrace.c \
+ libcol_hwcdrv.c \
+ libcol_hwcfuncs.c \
+ libcol-i386-dis.c \
+ hwprofile.c \
+ jprofile.c \
+ unwind.c \
+ libcol_util.c \
+ collector.c \
+ $(NULL)
+
+AM_CFLAGS = $(GPROFNG_CFLAGS) -Wno-nonnull-compare
+AM_CPPFLAGS = $(GPROFNG_CPPFLAGS) -I.. -I$(srcdir) \
+ -I$(srcdir)/../common -I$(srcdir)/../src \
+ -I$(srcdir)/../../include
+
+AM_LDFLAGS = -module -avoid-version \
+ -Wl,--version-script,$(srcdir)/mapfile.$(GPROFNG_VARIANT) \
+ $(LD_NO_AS_NEEDED) -Wl,-lrt -Wl,-ldl
+
+myincludedir = @includedir@
+myinclude_HEADERS = $(srcdir)/../../include/collectorAPI.h \
+ $(srcdir)/../../include/libcollector.h \
+ $(srcdir)/../../include/libfcollector.h
+
+lib_LTLIBRARIES = libgp-collector.la libgp-collectorAPI.la libgp-heap.la \
+ libgp-sync.la libgp-iotrace.la
+
+libgp_collector_la_SOURCES = $(CSOURCES)
+libgp_collector_la_CPPFLAGS = $(AM_CPPFLAGS) $(jdk_inc) \
+ -I../../bfd -I$(srcdir)/../..
+
+# Prevent libtool from reordering -Wl,--no-as-needed after -lrt by
+# disguising -lrt as a linker flag.
+libgp_collector_la_LDFLAGS = $(AM_LDFLAGS)
+libgp_collector_la_LIBADD =
+libgp_heap_la_SOURCES = heaptrace.c
+libgp_heap_la_LDFLAGS = $(AM_LDFLAGS)
+libgp_sync_la_SOURCES = synctrace.c
+libgp_sync_la_LDFLAGS = $(AM_LDFLAGS)
+libgp_iotrace_la_SOURCES = iotrace.c
+libgp_iotrace_la_LDFLAGS = $(AM_LDFLAGS)
+libgp_collectorAPI_la_SOURCES = collectorAPI.c
+libgp_collectorAPI_la_LIBADD = -lc -ldl
+all: lib-config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+am--refresh: Makefile
+ @:
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ $(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+lib-config.h: stamp-h1
+ @test -f $@ || rm -f stamp-h1
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(top_srcdir)/../common/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status lib-config.h
+$(top_srcdir)/../common/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f lib-config.h stamp-h1
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgp-collector.la: $(libgp_collector_la_OBJECTS) $(libgp_collector_la_DEPENDENCIES) $(EXTRA_libgp_collector_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgp_collector_la_LINK) -rpath $(libdir) $(libgp_collector_la_OBJECTS) $(libgp_collector_la_LIBADD) $(LIBS)
+
+libgp-collectorAPI.la: $(libgp_collectorAPI_la_OBJECTS) $(libgp_collectorAPI_la_DEPENDENCIES) $(EXTRA_libgp_collectorAPI_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(LINK) -rpath $(libdir) $(libgp_collectorAPI_la_OBJECTS) $(libgp_collectorAPI_la_LIBADD) $(LIBS)
+
+libgp-heap.la: $(libgp_heap_la_OBJECTS) $(libgp_heap_la_DEPENDENCIES) $(EXTRA_libgp_heap_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgp_heap_la_LINK) -rpath $(libdir) $(libgp_heap_la_OBJECTS) $(libgp_heap_la_LIBADD) $(LIBS)
+
+libgp-iotrace.la: $(libgp_iotrace_la_OBJECTS) $(libgp_iotrace_la_DEPENDENCIES) $(EXTRA_libgp_iotrace_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgp_iotrace_la_LINK) -rpath $(libdir) $(libgp_iotrace_la_OBJECTS) $(libgp_iotrace_la_LIBADD) $(LIBS)
+
+libgp-sync.la: $(libgp_sync_la_OBJECTS) $(libgp_sync_la_DEPENDENCIES) $(EXTRA_libgp_sync_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgp_sync_la_LINK) -rpath $(libdir) $(libgp_sync_la_OBJECTS) $(libgp_sync_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/collectorAPI.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/heaptrace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iotrace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-collector.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-dispatcher.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-envmgmt.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-gethrtime.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-hwprofile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-iolib.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-jprofile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-libcol-i386-dis.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-libcol_hwcdrv.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-libcol_hwcfuncs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-libcol_util.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-linetrace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-memmgr.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-mmaptrace.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-profile.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-tsd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgp_collector_la-unwind.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/synctrace.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+libgp_collector_la-gethrtime.lo: gethrtime.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-gethrtime.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-gethrtime.Tpo -c -o libgp_collector_la-gethrtime.lo `test -f 'gethrtime.c' || echo '$(srcdir)/'`gethrtime.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-gethrtime.Tpo $(DEPDIR)/libgp_collector_la-gethrtime.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gethrtime.c' object='libgp_collector_la-gethrtime.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-gethrtime.lo `test -f 'gethrtime.c' || echo '$(srcdir)/'`gethrtime.c
+
+libgp_collector_la-dispatcher.lo: dispatcher.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-dispatcher.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-dispatcher.Tpo -c -o libgp_collector_la-dispatcher.lo `test -f 'dispatcher.c' || echo '$(srcdir)/'`dispatcher.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-dispatcher.Tpo $(DEPDIR)/libgp_collector_la-dispatcher.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dispatcher.c' object='libgp_collector_la-dispatcher.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-dispatcher.lo `test -f 'dispatcher.c' || echo '$(srcdir)/'`dispatcher.c
+
+libgp_collector_la-iolib.lo: iolib.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-iolib.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-iolib.Tpo -c -o libgp_collector_la-iolib.lo `test -f 'iolib.c' || echo '$(srcdir)/'`iolib.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-iolib.Tpo $(DEPDIR)/libgp_collector_la-iolib.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='iolib.c' object='libgp_collector_la-iolib.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-iolib.lo `test -f 'iolib.c' || echo '$(srcdir)/'`iolib.c
+
+libgp_collector_la-mmaptrace.lo: mmaptrace.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-mmaptrace.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-mmaptrace.Tpo -c -o libgp_collector_la-mmaptrace.lo `test -f 'mmaptrace.c' || echo '$(srcdir)/'`mmaptrace.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-mmaptrace.Tpo $(DEPDIR)/libgp_collector_la-mmaptrace.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mmaptrace.c' object='libgp_collector_la-mmaptrace.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-mmaptrace.lo `test -f 'mmaptrace.c' || echo '$(srcdir)/'`mmaptrace.c
+
+libgp_collector_la-memmgr.lo: memmgr.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-memmgr.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-memmgr.Tpo -c -o libgp_collector_la-memmgr.lo `test -f 'memmgr.c' || echo '$(srcdir)/'`memmgr.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-memmgr.Tpo $(DEPDIR)/libgp_collector_la-memmgr.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='memmgr.c' object='libgp_collector_la-memmgr.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-memmgr.lo `test -f 'memmgr.c' || echo '$(srcdir)/'`memmgr.c
+
+libgp_collector_la-tsd.lo: tsd.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-tsd.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-tsd.Tpo -c -o libgp_collector_la-tsd.lo `test -f 'tsd.c' || echo '$(srcdir)/'`tsd.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-tsd.Tpo $(DEPDIR)/libgp_collector_la-tsd.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tsd.c' object='libgp_collector_la-tsd.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-tsd.lo `test -f 'tsd.c' || echo '$(srcdir)/'`tsd.c
+
+libgp_collector_la-profile.lo: profile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-profile.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-profile.Tpo -c -o libgp_collector_la-profile.lo `test -f 'profile.c' || echo '$(srcdir)/'`profile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-profile.Tpo $(DEPDIR)/libgp_collector_la-profile.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profile.c' object='libgp_collector_la-profile.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-profile.lo `test -f 'profile.c' || echo '$(srcdir)/'`profile.c
+
+libgp_collector_la-envmgmt.lo: envmgmt.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-envmgmt.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-envmgmt.Tpo -c -o libgp_collector_la-envmgmt.lo `test -f 'envmgmt.c' || echo '$(srcdir)/'`envmgmt.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-envmgmt.Tpo $(DEPDIR)/libgp_collector_la-envmgmt.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='envmgmt.c' object='libgp_collector_la-envmgmt.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-envmgmt.lo `test -f 'envmgmt.c' || echo '$(srcdir)/'`envmgmt.c
+
+libgp_collector_la-linetrace.lo: linetrace.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-linetrace.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-linetrace.Tpo -c -o libgp_collector_la-linetrace.lo `test -f 'linetrace.c' || echo '$(srcdir)/'`linetrace.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-linetrace.Tpo $(DEPDIR)/libgp_collector_la-linetrace.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='linetrace.c' object='libgp_collector_la-linetrace.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-linetrace.lo `test -f 'linetrace.c' || echo '$(srcdir)/'`linetrace.c
+
+libgp_collector_la-libcol_hwcdrv.lo: libcol_hwcdrv.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-libcol_hwcdrv.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-libcol_hwcdrv.Tpo -c -o libgp_collector_la-libcol_hwcdrv.lo `test -f 'libcol_hwcdrv.c' || echo '$(srcdir)/'`libcol_hwcdrv.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-libcol_hwcdrv.Tpo $(DEPDIR)/libgp_collector_la-libcol_hwcdrv.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libcol_hwcdrv.c' object='libgp_collector_la-libcol_hwcdrv.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-libcol_hwcdrv.lo `test -f 'libcol_hwcdrv.c' || echo '$(srcdir)/'`libcol_hwcdrv.c
+
+libgp_collector_la-libcol_hwcfuncs.lo: libcol_hwcfuncs.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-libcol_hwcfuncs.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-libcol_hwcfuncs.Tpo -c -o libgp_collector_la-libcol_hwcfuncs.lo `test -f 'libcol_hwcfuncs.c' || echo '$(srcdir)/'`libcol_hwcfuncs.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-libcol_hwcfuncs.Tpo $(DEPDIR)/libgp_collector_la-libcol_hwcfuncs.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libcol_hwcfuncs.c' object='libgp_collector_la-libcol_hwcfuncs.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-libcol_hwcfuncs.lo `test -f 'libcol_hwcfuncs.c' || echo '$(srcdir)/'`libcol_hwcfuncs.c
+
+libgp_collector_la-libcol-i386-dis.lo: libcol-i386-dis.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-libcol-i386-dis.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-libcol-i386-dis.Tpo -c -o libgp_collector_la-libcol-i386-dis.lo `test -f 'libcol-i386-dis.c' || echo '$(srcdir)/'`libcol-i386-dis.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-libcol-i386-dis.Tpo $(DEPDIR)/libgp_collector_la-libcol-i386-dis.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libcol-i386-dis.c' object='libgp_collector_la-libcol-i386-dis.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-libcol-i386-dis.lo `test -f 'libcol-i386-dis.c' || echo '$(srcdir)/'`libcol-i386-dis.c
+
+libgp_collector_la-hwprofile.lo: hwprofile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-hwprofile.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-hwprofile.Tpo -c -o libgp_collector_la-hwprofile.lo `test -f 'hwprofile.c' || echo '$(srcdir)/'`hwprofile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-hwprofile.Tpo $(DEPDIR)/libgp_collector_la-hwprofile.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hwprofile.c' object='libgp_collector_la-hwprofile.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-hwprofile.lo `test -f 'hwprofile.c' || echo '$(srcdir)/'`hwprofile.c
+
+libgp_collector_la-jprofile.lo: jprofile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-jprofile.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-jprofile.Tpo -c -o libgp_collector_la-jprofile.lo `test -f 'jprofile.c' || echo '$(srcdir)/'`jprofile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-jprofile.Tpo $(DEPDIR)/libgp_collector_la-jprofile.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='jprofile.c' object='libgp_collector_la-jprofile.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-jprofile.lo `test -f 'jprofile.c' || echo '$(srcdir)/'`jprofile.c
+
+libgp_collector_la-unwind.lo: unwind.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-unwind.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-unwind.Tpo -c -o libgp_collector_la-unwind.lo `test -f 'unwind.c' || echo '$(srcdir)/'`unwind.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-unwind.Tpo $(DEPDIR)/libgp_collector_la-unwind.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unwind.c' object='libgp_collector_la-unwind.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-unwind.lo `test -f 'unwind.c' || echo '$(srcdir)/'`unwind.c
+
+libgp_collector_la-libcol_util.lo: libcol_util.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-libcol_util.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-libcol_util.Tpo -c -o libgp_collector_la-libcol_util.lo `test -f 'libcol_util.c' || echo '$(srcdir)/'`libcol_util.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-libcol_util.Tpo $(DEPDIR)/libgp_collector_la-libcol_util.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='libcol_util.c' object='libgp_collector_la-libcol_util.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-libcol_util.lo `test -f 'libcol_util.c' || echo '$(srcdir)/'`libcol_util.c
+
+libgp_collector_la-collector.lo: collector.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgp_collector_la-collector.lo -MD -MP -MF $(DEPDIR)/libgp_collector_la-collector.Tpo -c -o libgp_collector_la-collector.lo `test -f 'collector.c' || echo '$(srcdir)/'`collector.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgp_collector_la-collector.Tpo $(DEPDIR)/libgp_collector_la-collector.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='collector.c' object='libgp_collector_la-collector.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgp_collector_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgp_collector_la-collector.lo `test -f 'collector.c' || echo '$(srcdir)/'`collector.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool config.lt
+install-myincludeHEADERS: $(myinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(myinclude_HEADERS)'; test -n "$(myincludedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(myincludedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(myincludedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(myincludedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(myincludedir)" || exit $$?; \
+ done
+
+uninstall-myincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(myinclude_HEADERS)'; test -n "$(myincludedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(myincludedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+ test ! -s cscope.files \
+ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+ -rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+ -rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ test -d "$(distdir)" || mkdir "$(distdir)"
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ -test -n "$(am__skip_mode_fix)" \
+ || find "$(distdir)" -type d ! -perm -755 \
+ -exec chmod u+rwx,go+rx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz
+ $(am__post_remove_distdir)
+
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+ $(am__post_remove_distdir)
+
+dist-lzip: distdir
+ tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+ $(am__post_remove_distdir)
+
+dist-xz: distdir
+ tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+ $(am__post_remove_distdir)
+
+dist-tarZ: distdir
+ @echo WARNING: "Support for distribution archives compressed with" \
+ "legacy program 'compress' is deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__post_remove_distdir)
+
+dist-shar: distdir
+ @echo WARNING: "Support for shar distribution archives is" \
+ "deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz
+ $(am__post_remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__post_remove_distdir)
+
+dist dist-all:
+ $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+ $(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.lz*) \
+ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+ *.tar.xz*) \
+ xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir)
+ chmod u+w $(distdir)
+ mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst
+ chmod a-w $(distdir)
+ test -d $(distdir)/_build || exit 0; \
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && am__cwd=`pwd` \
+ && $(am__cd) $(distdir)/_build/sub \
+ && ../../configure \
+ $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ --srcdir=../.. --prefix="$$dc_install_base" \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+ && cd "$$am__cwd" \
+ || exit 1
+ $(am__post_remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+ @test -n '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: trying to run $@ with an empty' \
+ '$$(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ $(am__cd) '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS) lib-config.h
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(myincludedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-hdr distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-myincludeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES uninstall-myincludeHEADERS
+
+.MAKE: all install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-am clean \
+ clean-cscope clean-generic clean-libLTLIBRARIES clean-libtool \
+ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \
+ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \
+ distcheck distclean distclean-compile distclean-generic \
+ distclean-hdr distclean-libtool distclean-tags distcleancheck \
+ distdir distuninstallcheck dvi dvi-am html html-am info \
+ info-am install install-am install-data install-data-am \
+ install-dvi install-dvi-am install-exec install-exec-am \
+ install-html install-html-am install-info install-info-am \
+ install-libLTLIBRARIES install-man install-myincludeHEADERS \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-libLTLIBRARIES uninstall-myincludeHEADERS
+
+.PRECIOUS: Makefile
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/gprofng/libcollector/aclocal.m4 b/gprofng/libcollector/aclocal.m4
new file mode 100644
index 0000000..b269c73
--- /dev/null
+++ b/gprofng/libcollector/aclocal.m4
@@ -0,0 +1,1237 @@
+# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# Copyright (C) 2002-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.15'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.15.1], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.15.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# Copyright (C) 2011-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_AR([ACT-IF-FAIL])
+# -------------------------
+# Try to determine the archiver interface, and trigger the ar-lib wrapper
+# if it is needed. If the detection of archiver interface fails, run
+# ACT-IF-FAIL (default is to abort configure with a proper error message).
+AC_DEFUN([AM_PROG_AR],
+[AC_BEFORE([$0], [LT_INIT])dnl
+AC_BEFORE([$0], [AC_PROG_LIBTOOL])dnl
+AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([ar-lib])dnl
+AC_CHECK_TOOLS([AR], [ar lib "link -lib"], [false])
+: ${AR=ar}
+
+AC_CACHE_CHECK([the archiver ($AR) interface], [am_cv_ar_interface],
+ [AC_LANG_PUSH([C])
+ am_cv_ar_interface=ar
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[int some_variable = 0;]])],
+ [am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+ AC_TRY_EVAL([am_ar_try])
+ if test "$ac_status" -eq 0; then
+ am_cv_ar_interface=ar
+ else
+ am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&AS_MESSAGE_LOG_FD'
+ AC_TRY_EVAL([am_ar_try])
+ if test "$ac_status" -eq 0; then
+ am_cv_ar_interface=lib
+ else
+ am_cv_ar_interface=unknown
+ fi
+ fi
+ rm -f conftest.lib libconftest.a
+ ])
+ AC_LANG_POP([C])])
+
+case $am_cv_ar_interface in
+ar)
+ ;;
+lib)
+ # Microsoft lib, so override with the ar-lib wrapper script.
+ # FIXME: It is wrong to rewrite AR.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__AR in this case,
+ # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+ # similar.
+ AR="$am_aux_dir/ar-lib $AR"
+ ;;
+unknown)
+ m4_default([$1],
+ [AC_MSG_ERROR([could not determine $AR interface])])
+ ;;
+esac
+AC_SUBST([AR])dnl
+])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC], [depcc="$CC" am_compiler_list=],
+ [$1], [CXX], [depcc="$CXX" am_compiler_list=],
+ [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+ [$1], [UPC], [depcc="$UPC" am_compiler_list=],
+ [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ am__universal=false
+ m4_case([$1], [CC],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac],
+ [CXX],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac])
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+ [--enable-dependency-tracking],
+ [do not reject slow dependency extractors])
+AS_HELP_STRING(
+ [--disable-dependency-tracking],
+ [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named 'Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running 'make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "$am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each '.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+ [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+ m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+ [ok:ok],,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target (and possibly the TAP driver). The
+# system "awk" is bad on some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES([CC])],
+ [m4_define([AC_PROG_CC],
+ m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES([CXX])],
+ [m4_define([AC_PROG_CXX],
+ m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES([OBJC])],
+ [m4_define([AC_PROG_OBJC],
+ m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+ [_AM_DEPENDENCIES([OBJCXX])],
+ [m4_define([AC_PROG_OBJCXX],
+ m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes. So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+ cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present. This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message. This
+can help us improve future automake versions.
+
+END
+ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+ echo 'Configuration will proceed anyway, since you have set the' >&2
+ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+ echo >&2
+ else
+ cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+ AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+ fi
+fi
+dnl The trailing newline in this macro's definition is deliberate, for
+dnl backward compatibility and to allow trailing 'dnl'-style comments
+dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+AC_SUBST([install_sh])])
+
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless 'enable' is passed literally.
+# For symmetry, 'disable' may be passed as well. Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+ [enable], [m4_define([am_maintainer_other], [disable])],
+ [disable], [m4_define([am_maintainer_other], [enable])],
+ [m4_define([am_maintainer_other], [enable])
+ m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+ AC_ARG_ENABLE([maintainer-mode],
+ [AS_HELP_STRING([--]am_maintainer_other[-maintainer-mode],
+ am_maintainer_other[ make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer])],
+ [USE_MAINTAINER_MODE=$enableval],
+ [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST([MAINT])dnl
+]
+)
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+ [whether $CC understands -c and -o together],
+ [am_cv_prog_cc_c_o],
+ [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+ ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[[\\\"\#\$\&\'\`$am_lf]]*)
+ AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
+ AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+ alias in your environment])
+ fi
+ if test "$[2]" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+ [AC_MSG_CHECKING([that generated files are newer than configure])
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+ [--enable-silent-rules],
+ [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+ [--disable-silent-rules],
+ [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+ [am_cv_make_support_nested_variables],
+ [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+ dnl Using '$V' instead of '$(V)' breaks IRIX make.
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004-2017 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+ [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+ [m4_case([$1],
+ [ustar],
+ [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+ # There is notably a 21 bits limit for the UID and the GID. In fact,
+ # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+ # and bug#13588).
+ am_max_uid=2097151 # 2^21 - 1
+ am_max_gid=$am_max_uid
+ # The $UID and $GID variables are not portable, so we need to resort
+ # to the POSIX-mandated id(1) utility. Errors in the 'id' calls
+ # below are definitely unexpected, so allow the users to see them
+ # (that is, avoid stderr redirection).
+ am_uid=`id -u || echo unknown`
+ am_gid=`id -g || echo unknown`
+ AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+ if test $am_uid -le $am_max_uid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi
+ AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+ if test $am_gid -le $am_max_gid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi],
+
+ [pax],
+ [],
+
+ [m4_fatal([Unknown tar format])])
+
+ AC_MSG_CHECKING([how to create a $1 tar archive])
+
+ # Go ahead even if we have the value already cached. We do so because we
+ # need to set the values for the 'am__tar' and 'am__untar' variables.
+ _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+ for _am_tool in $_am_tools; do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar; do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ AM_RUN_LOG([cat conftest.dir/file])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+ done
+ rm -rf conftest.dir
+
+ AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+ AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([../../config/depstand.m4])
+m4_include([../../config/lead-dot.m4])
+m4_include([../../config/override.m4])
+m4_include([../../libtool.m4])
+m4_include([../../ltoptions.m4])
+m4_include([../../ltsugar.m4])
+m4_include([../../ltversion.m4])
+m4_include([../../lt~obsolete.m4])
diff --git a/gprofng/libcollector/collector.c b/gprofng/libcollector/collector.c
new file mode 100644
index 0000000..93c9d33
--- /dev/null
+++ b/gprofng/libcollector/collector.c
@@ -0,0 +1,2494 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "config.h"
+#include <alloca.h>
+#include <errno.h>
+#include <signal.h>
+#include <ucontext.h>
+#include <stdlib.h> /* exit() */
+#include <sys/param.h>
+#include <sys/utsname.h> /* struct utsname */
+#include <sys/resource.h>
+#include <sys/syscall.h> /* system call fork() */
+
+#include "gp-defs.h"
+#include "collector.h"
+#include "descendants.h"
+#include "gp-experiment.h"
+#include "memmgr.h"
+#include "cc_libcollector.h"
+#include "tsd.h"
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+
+typedef unsigned long ulong_t;
+
+extern char **environ;
+extern void __collector_close_experiment ();
+extern int __collector_set_size_limit (char *par);
+
+/* ------- internal function prototypes ---------- */
+CollectorModule __collector_register_module (ModuleInterface *modint);
+static void write_sample (char *name);
+static const char *__collector_get_params ();
+static const char *__collector_get_expdir ();
+static FrameInfo __collector_getUserCtx (CollectorModule modl, HiResTime ts, int mode, void *arg);
+static FrameInfo __collector_getUID1 (CM_Array *arg);
+static int __collector_writeMetaData (CollectorModule modl, char *format, ...);
+static int __collector_writeDataRecord (CollectorModule modl, struct Common_packet *pckt);
+static int __collector_writeDataPacket (CollectorModule modl, struct CM_Packet *pckt);
+static void *allocCSize (struct Heap*, unsigned, int);
+static void freeCSize (struct Heap*, void*, unsigned);
+static void *allocVSize (struct Heap*, unsigned);
+static void *reallocVSize (struct Heap*, void*, unsigned);
+
+static int collector_create_expr_dir (const char *new_exp_name);
+static int collector_create_expr_dir_lineage (const char *parent_exp_name);
+static int collector_exp_dir_append_x (int linenum, const char *parent_exp_name);
+static int collector_tail_init (const char *parent_exp_name);
+static int log_open ();
+static void log_header_write (sp_origin_t origin);
+static void log_pause ();
+static void log_resume ();
+static void fs_warn ();
+static void log_close ();
+static void get_progspec (char *cmdline, int tmp_sz, char *progname, int sz);
+static void sample_handler (int, siginfo_t*, void*);
+static int sample_set_interval (char *);
+static int set_duration (char *);
+static int sample_set_user_sig (char *);
+static void pause_handler (int, siginfo_t*, void*);
+static int pause_set_user_sig (char *);
+static int set_user_sig_action (char*);
+static void ovw_open ();
+static hrtime_t ovw_write ();
+
+/* ------- global data controlling the collector's behavior -------- */
+
+static CollectorInterface collector_interface ={
+ __collector_register_module, /* registerModule */
+ __collector_get_params, /* getParams */
+ __collector_get_expdir, /* getExpDir */
+ __collector_log_write, /* writeLog */
+ __collector_getUserCtx, /* getFrameInfo */
+ __collector_getUID1, /* getUID */
+ __collector_getUID, /* getUID2 */
+ __collector_getStackTrace, /* getStackTrace */
+ __collector_writeMetaData, /* writeMetaData */
+ __collector_writeDataRecord, /* writeDataRecord */
+ __collector_writeDataPacket, /* writeDataPacket */
+ write_sample, /* write_sample */
+ get_progspec, /* get_progspec */
+ __collector_open_experiment, /* open_experiment */
+ NULL, /* getHiResTime */
+ __collector_newHeap, /* newHeap */
+ __collector_deleteHeap, /* deleteHeap */
+ allocCSize, /* allocCSize */
+ freeCSize, /* freeCSize */
+ allocVSize, /* allocVSize */
+ reallocVSize, /* reallocVSize */
+ __collector_tsd_create_key, /* createKey */
+ __collector_tsd_get_by_key, /* getKey */
+ __collector_dlog /* writeDebugInfo */
+};
+
+#define MAX_MODULES 32
+static ModuleInterface *modules[MAX_MODULES];
+static int modules_st[MAX_MODULES];
+static void *modules_hndl[MAX_MODULES];
+static volatile int nmodules = 0;
+
+/* flag set non-zero, if data collected implies a filesystem warning is appropriate */
+static int fs_matters = 0;
+static const char *collector_params = NULL;
+static const char *project_home = NULL;
+Heap *__collector_heap = NULL;
+int __collector_no_threads;
+int __collector_libthread_T1 = -1;
+
+static volatile int collector_paused = 0;
+
+int __collector_tracelevel = -1;
+static int collector_debug_opt = 0;
+
+hrtime_t __collector_next_sample = 0;
+int __collector_sample_period = 0; /* if non-zero, periodic sampling is enabled */
+
+hrtime_t __collector_delay_start = 0; /* if non-zero, delay before starting data */
+hrtime_t __collector_terminate_time = 0; /* if non-zero, fixed duration run */
+
+static collector_mutex_t __collector_glob_lock = COLLECTOR_MUTEX_INITIALIZER;
+static collector_mutex_t __collector_open_guard = COLLECTOR_MUTEX_INITIALIZER;
+static collector_mutex_t __collector_close_guard = COLLECTOR_MUTEX_INITIALIZER;
+static collector_mutex_t __collector_sample_guard = COLLECTOR_MUTEX_INITIALIZER;
+static collector_mutex_t __collector_suspend_guard = COLLECTOR_MUTEX_INITIALIZER;
+static collector_mutex_t __collector_resume_guard = COLLECTOR_MUTEX_INITIALIZER;
+char __collector_exp_dir_name[MAXPATHLEN + 1] = ""; /* experiment directory */
+int __collector_size_limit = 0;
+
+static char *archive_mode = NULL;
+
+volatile sp_state_t __collector_expstate = EXP_INIT;
+static int exp_origin = SP_ORIGIN_LIBCOL_INIT;
+static int exp_open = 0;
+int __collector_exp_active = 0;
+static int paused_when_suspended = 0;
+static int exp_initted = 0;
+static char exp_progspec[_POSIX_ARG_MAX + 1]; /* program cmdline. includes args */
+static char exp_progname[_POSIX_ARG_MAX + 1]; /* program name == argv[0] */
+
+hrtime_t __collector_start_time = 0;
+static time_t start_sec_time = 0;
+
+/* Sample related data */
+static int sample_installed = 0; /* 1 if the sample signal handler installed */
+static int sample_mode = 0; /* dynamically turns sample record writing on/off */
+static int sample_number = 0; /* index of the current sample record */
+static struct sigaction old_sample_handler;
+int __collector_sample_sig = -1; /* user-specified sample signal */
+int __collector_sample_sig_warn = 0; /* non-zero if warning already given */
+
+/* Pause/resume related data */
+static struct sigaction old_pause_handler;
+int __collector_pause_sig = -1; /* user-specified pause signal */
+int __collector_pause_sig_warn = 0; /* non-zero if warning already given */
+
+static struct sigaction old_close_handler;
+static struct sigaction old_exit_handler;
+
+/* Experiment files */
+static char ovw_name[MAXPATHLEN]; /* Overview data file name */
+
+/* macro to convert a timestruc to hrtime_t */
+#define ts2hrt(x) ((hrtime_t)(x).tv_sec*NANOSEC + (hrtime_t)(x).tv_nsec)
+
+static void
+init_tracelevel ()
+{
+#if DEBUG
+ char *s = CALL_UTIL (getenv)("SP_COLLECTOR_TRACELEVEL");
+ if (s != NULL)
+ __collector_tracelevel = CALL_UTIL (atoi)(s);
+ TprintfT (DBG_LT0, "collector: SP_COLLECTOR_TRACELEVEL=%d\n", __collector_tracelevel);
+ s = CALL_UTIL (getenv)("SP_COLLECTOR_DEBUG");
+ if (s != NULL)
+ collector_debug_opt = CALL_UTIL (atoi)(s) & ~(SP_DUMP_TIME | SP_DUMP_FLAG);
+#endif
+}
+
+static CollectorInterface *
+get_collector_interface ()
+{
+ if (collector_interface.getHiResTime == NULL)
+ collector_interface.getHiResTime = __collector_gethrtime;
+ return &collector_interface;
+}
+
+/*
+ * __collector_module_init is an alternate method to initialize
+ * dynamic collector modules (er_heap, er_sync, er_iotrace, er_mpi, tha).
+ * Every module that needs to register itself with libcollector
+ * before the experiment is open implements its own global
+ * __collector_module_init and makes sure the next one is called.
+ */
+static void
+collector_module_init (CollectorInterface *col_intf)
+{
+ int nmodules = 0;
+
+ ModuleInitFunc next_init = (ModuleInitFunc) dlsym (RTLD_DEFAULT, "__collector_module_init");
+ if (next_init != NULL)
+ {
+ nmodules++;
+ next_init (col_intf);
+ }
+ TprintfT (DBG_LT1, "collector_module_init: %d modules\n", nmodules);
+}
+
+/* Routines concerned with general experiment start and stop */
+
+/* initialization -- init section routine -- called when libcollector loaded */
+static void collector_init () __attribute__ ((constructor));
+
+static void
+collector_init ()
+{
+ if (__collector_util_init () != 0)
+ /* we can't do anything without various utility functions */
+ abort ();
+ init_tracelevel ();
+
+ /*
+ * Unconditionally install the SIGPROF handler
+ * to process signals originated in dtracelets.
+ */
+ __collector_sigprof_install ();
+
+ /* Initialize all preloaded modules */
+ collector_module_init (get_collector_interface ());
+
+ /* determine experiment name */
+ char *exp = CALL_UTIL (getenv)("SP_COLLECTOR_EXPNAME");
+ if ((exp == NULL) || (CALL_UTIL (strlen)(exp) == 0))
+ {
+ TprintfT (DBG_LT0, "collector_init: SP_COLLECTOR_EXPNAME undefined - no experiment to start\n");
+ /* not set -- no experiment to run */
+ return;
+ }
+ else
+ TprintfT (DBG_LT1, "collector_init: found SP_COLLECTOR_EXPNAME = %s\n", exp);
+
+ /* determine the data descriptor for the experiment */
+ char *params = CALL_UTIL (getenv)("SP_COLLECTOR_PARAMS");
+ if (params == NULL)
+ {
+ TprintfT (0, "collector_init: SP_COLLECTOR_PARAMS undefined - no experiment to start\n");
+ return;
+ }
+
+ /* now do the real open of the experiment */
+ if (__collector_open_experiment (exp, params, SP_ORIGIN_LIBCOL_INIT))
+ {
+ TprintfT (0, "collector_init: __collector_open_experiment failed\n");
+ /* experiment open failed, close it */
+ __collector_close_experiment ();
+ return;
+ }
+ return;
+}
+
+CollectorModule
+__collector_register_module (ModuleInterface *modint)
+{
+ TprintfT (DBG_LT1, "collector: module %s calls for registration.\n",
+ modint->description == NULL ? "(null)" : modint->description);
+ if (modint == NULL)
+ return COLLECTOR_MODULE_ERR;
+ if (nmodules >= MAX_MODULES)
+ return COLLECTOR_MODULE_ERR;
+ if (modint->initInterface &&
+ modint->initInterface (get_collector_interface ()))
+ return COLLECTOR_MODULE_ERR;
+ int idx = nmodules++;
+ modules[idx] = modint;
+ modules_st[idx] = 0;
+
+ if (exp_open && modint->openExperiment)
+ {
+ modules_st[idx] = modint->openExperiment (__collector_exp_dir_name);
+ if (modules_st[idx] == COL_ERROR_NONE && modules[idx]->description != NULL)
+ {
+ modules_hndl[idx] = __collector_create_handle (modules[idx]->description);
+ if (modules_hndl[idx] == NULL)
+ modules_st[idx] = -1;
+ }
+ }
+ if (__collector_exp_active && collector_paused == 0 &&
+ modint->startDataCollection && modules_st[idx] == 0)
+ modint->startDataCollection ();
+ TprintfT (DBG_LT1, "collector: module %s (%d) registered.\n",
+ modint->description == NULL ? "(null)" : modint->description, idx);
+ return (CollectorModule) idx;
+}
+
+static const char *
+__collector_get_params ()
+{
+ return collector_params;
+}
+
+static const char *
+__collector_get_expdir ()
+{
+ return __collector_exp_dir_name;
+}
+
+static FrameInfo
+__collector_getUserCtx (CollectorModule modl, HiResTime ts, int mode, void *arg)
+{
+ return __collector_get_frame_info (ts, mode, arg);
+}
+
+static FrameInfo
+__collector_getUID1 (CM_Array *arg)
+{
+ return __collector_getUID (arg, (FrameInfo) 0);
+}
+
+static int
+__collector_writeMetaData (CollectorModule modl, char *format, ...)
+{
+ if (modl < 0 || modl >= nmodules || modules[modl]->description == NULL)
+ {
+ TprintfT (DBG_LT0, "__collector_writeMetaData(): bad module: %d\n", modl);
+ return 1;
+ }
+ char fname[MAXPATHLEN + 1];
+ CALL_UTIL (strlcpy)(fname, __collector_exp_dir_name, sizeof (fname));
+ CALL_UTIL (strlcat)(fname, "/metadata.", sizeof (fname));
+ CALL_UTIL (strlcat)(fname, modules[modl]->description, sizeof (fname));
+ CALL_UTIL (strlcat)(fname, ".xml", sizeof (fname));
+ int fd = CALL_UTIL (open)(fname, O_CREAT | O_WRONLY | O_APPEND,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0)
+ {
+ TprintfT (DBG_LT0, "__collector_writeMetaData(): can't open file: %s\n", fname);
+ return 1;
+ }
+ char buf[1024];
+ char *bufptr = buf;
+ va_list va;
+ va_start (va, format);
+ int sz = __collector_xml_vsnprintf (bufptr, sizeof (buf), format, va);
+ va_end (va);
+
+ if (sz >= sizeof (buf))
+ {
+ /* Allocate a new buffer */
+ sz += 1; /* add the terminating null byte */
+ bufptr = (char*) alloca (sz);
+
+ va_start (va, format);
+ sz = __collector_xml_vsnprintf (bufptr, sz, format, va);
+ va_end (va);
+ }
+ CALL_UTIL (write)(fd, bufptr, sz);
+ CALL_UTIL (close)(fd);
+ return COL_ERROR_NONE;
+}
+
+/* check that the header fields are filled-in, and then call __collector_writeDataPacket */
+static int
+__collector_writeDataRecord (CollectorModule modl, struct Common_packet *pckt)
+{
+ return __collector_write_record (modules_hndl[modl], pckt);
+}
+
+static int
+__collector_writeDataPacket (CollectorModule modl, struct CM_Packet *pckt)
+{
+ return __collector_write_packet (modules_hndl[modl], pckt);
+}
+
+static void *
+allocCSize (struct Heap *heap, unsigned sz, int log)
+{
+ return __collector_allocCSize (heap ? heap : __collector_heap, sz, log);
+}
+
+static void
+freeCSize (struct Heap *heap, void *ptr, unsigned sz)
+{
+ __collector_freeCSize (heap ? heap : __collector_heap, ptr, sz);
+}
+
+static void *
+allocVSize (struct Heap *heap, unsigned sz)
+{
+ return __collector_allocVSize (heap ? heap : __collector_heap, sz);
+}
+
+static void *
+reallocVSize (struct Heap *heap, void *ptr, unsigned sz)
+{
+ return __collector_reallocVSize (heap ? heap : __collector_heap, ptr, sz);
+}
+
+static time_t
+get_gm_time (struct tm *tp)
+{
+ /*
+ Note that glibc contains a function of the same purpose named `timegm'.
+ But obviously, it is not universally available.
+
+ Some implementations of mktime return -1 for the nonexistent localtime hour
+ at the beginning of DST. In this event, use 'mktime(tm - 1hr) + 3600'.
+ nonexistent
+ tm_isdst is set to 0 to force mktime to introduce a consistent offset
+ (the non DST offset) since tm and tm+o might be on opposite sides of a DST change.
+
+ Schematically:
+ mktime(tm) --> t+o
+ gmtime_r(t+o) --> tm+o
+ mktime(tm+o) --> t+2o
+ t = t+o - (t+2o - t+o)
+ */
+ struct tm stm;
+ time_t tl = CALL_UTIL (mktime)(tp);
+ if (tl == -1)
+ {
+ stm = *tp;
+ stm.tm_hour--;
+ tl = CALL_UTIL (mktime)(&stm);
+ if (tl == -1)
+ return -1;
+ tl += 3600;
+ }
+
+ (void) (CALL_UTIL (gmtime_r)(&tl, &stm));
+ stm.tm_isdst = 0;
+ time_t tb = CALL_UTIL (mktime)(&stm);
+ if (tb == -1)
+ {
+ stm.tm_hour--;
+ tb = CALL_UTIL (mktime)(&stm);
+ if (tb == -1)
+ return -1;
+ tb += 3600;
+ }
+ return (tl - (tb - tl));
+}
+
+static void
+log_write_event_run ()
+{
+ /* get the gm and local time */
+ struct tm start_stm;
+ CALL_UTIL (gmtime_r)(&start_sec_time, &start_stm);
+ time_t start_gm_time = get_gm_time (&start_stm);
+ time_t lcl_time = CALL_UTIL (mktime)(&start_stm);
+ __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" time=\"%lld\" tm_zone=\"%lld\"/>\n",
+ SP_JCMD_RUN,
+ (unsigned) (__collector_start_time / NANOSEC),
+ (unsigned) (__collector_start_time % NANOSEC),
+ (long long) start_gm_time,
+ (long long) (lcl_time - start_gm_time));
+}
+
+static void *
+m_dlopen (const char *filename, int flag)
+{
+ void *p = dlopen (filename, flag);
+ TprintfT (DBG_LT1, "collector.c: dlopen(%s, %d) returns %p\n", filename, flag, p);
+ return p;
+}
+/* real routine to open an experiment
+ * called by collector_init from libcollector init section
+ * called by __collector_start_experiment when a child is forked */
+int
+__collector_open_experiment (const char *exp, const char *params, sp_origin_t origin)
+{
+ char *s;
+ char *buf = NULL;
+ char *duration_string = NULL;
+ int err;
+ int is_founder = 1;
+ int record_this_experiment = 1;
+ int seen_F_flag = 0;
+ static char buffer[32];
+ if (exp_open)
+ {
+ /* experiment already opened */
+ TprintfT (0, "collector: ERROR: Attempt to open opened experiment\n");
+ return COL_ERROR_EXPOPEN;
+ }
+ __collector_start_time = collector_interface.getHiResTime ();
+ TprintfT (DBG_LT1, "\n\t\t__collector_open_experiment(SP_COLLECTOR_EXPNAME=%s, params=%s, origin=%d); setting start_time\n",
+ exp, params, origin);
+ if (environ)
+ __collector_env_printall ("__collector_open_experiment", environ);
+ else
+ TprintfT (DBG_LT1, "collector_open_experiment found environ == NULL)\n");
+
+ /*
+ * Recheck sigprof handler
+ * XXXX Bug 18177509 - additional sigprof signal kills target program
+ */
+ __collector_sigprof_install ();
+ exp_origin = origin;
+ collector_params = params;
+
+ /* Determine which of the three possible threading models:
+ * singlethreaded
+ * multi-LWP (no threads)
+ * multithreaded
+ * is the one the target is actually using.
+ *
+ * we really only need to distinguish between first two
+ * and the third. The thr_main() trick does exactly that.
+ * is the one the target is actually using.
+ *
+ * __collector_no_threads applies to all signal handlers,
+ * and must be set before signal handlers are installed.
+ */
+ __collector_no_threads = 0;
+ __collector_exp_dir_name[0] = 0;
+ sample_mode = 0;
+ sample_number = 0;
+
+ /* create global heap */
+ if (__collector_heap == NULL)
+ {
+ __collector_heap = __collector_newHeap ();
+ if (__collector_heap == NULL)
+ {
+ CALL_UTIL (fprintf)(stderr, "__collector_open_experiment COLERROR_NOZMEM 1\n");
+ return COL_ERROR_NOZMEM;
+ }
+ }
+ //check whether is origin is collect
+ char * envar = CALL_UTIL (getenv)("SP_COLLECTOR_ORIGIN_COLLECT");
+ TprintfT (DBG_LT1, "__collector_open_experiment SP_COLLECTOR_ORIGIN_COLLECT = '%s'\n",
+ (envar == NULL) ? "NULL" : envar);
+ if (envar)
+ exp_origin = SP_ORIGIN_COLLECT;
+
+ //check if this is the founder process
+ is_founder = getpid ();
+ if (origin != SP_ORIGIN_DBX_ATTACH)
+ {
+ envar = CALL_UTIL (getenv)("SP_COLLECTOR_FOUNDER");
+ if (envar)
+ is_founder = CALL_UTIL (atoi)(envar);
+ if (is_founder != 0)
+ {
+ if (is_founder != getpid ())
+ {
+ TprintfT (0, "__collector_open_experiment SP_COLLECTOR_FOUNDER=%d != pid(%d)\n",
+ is_founder, getpid ());
+ //CALL_UTIL(fprintf)(stderr, "__collector_open_experiment SP_COLLECTOR_FOUNDER=%d != pid(%d); not recording experiment\n",
+ //is_founder, getpid() );
+ //return COL_ERROR_UNEXP_FOUNDER;
+ is_founder = 0; // Special case (CR 22917352)
+ }
+ /* clear FOUNDER for descendant experiments */
+ TprintfT (0, "__collector_open_experiment setting SP_COLLECTOR_FOUNDER=0\n");
+ CALL_UTIL (strlcpy)(buffer, "SP_COLLECTOR_FOUNDER=0", sizeof (buffer));
+ CALL_UTIL (putenv)(buffer);
+ }
+ }
+
+ /* Set up fork/exec interposition (requires __collector_heap). */
+ /* Determine if "collect -F" specification enables this subexperiment */
+ get_progspec (exp_progspec, sizeof (exp_progspec), exp_progname, sizeof (exp_progname));
+
+ /* convert the returned exp_progname to a basename */
+ const char * base_name = __collector_strrchr (exp_progname, '/');
+ if (base_name == NULL)
+ base_name = exp_progname;
+ else
+ base_name = base_name + 1;
+ err = __collector_ext_line_init (&record_this_experiment, exp_progspec, base_name);
+ if (err != COL_ERROR_NONE)
+ {
+ CALL_UTIL (fprintf)(stderr, "__collector_open_experiment COLERROR: %d\n", err);
+ return err;
+ }
+
+ /* Due to the fix of bug 15691122, we need to initialize unwind to make
+ * the function __collector_ext_return_address() work for dlopen interposition.
+ * */
+ if (!record_this_experiment && !is_founder)
+ {
+ TprintfT (DBG_LT0, "__collector_open_experiment: NOT creating experiment. (is_founder=%d, record=%d)\n",
+ is_founder, record_this_experiment);
+ return collector_tail_init (exp);
+ }
+ TprintfT (DBG_LT0, "__collector_open_experiment: is_founder=%d, record=%d\n",
+ is_founder, record_this_experiment);
+ if (is_founder || origin == SP_ORIGIN_FORK)
+ {
+ CALL_UTIL (strlcpy)(__collector_exp_dir_name, exp, sizeof (__collector_exp_dir_name));
+ if (origin == SP_ORIGIN_FORK)
+ { /*create exp dir for fork-child*/
+ if (collector_create_expr_dir (__collector_exp_dir_name))
+ {
+ CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_BADDIR 1: `%s'\n", exp);
+ return COL_ERROR_BADDIR;
+ }
+ }
+ }
+ else
+ {/* founder/fork-child will already have created experiment dir, but exec/combo descendants must do so now */
+ if (collector_create_expr_dir_lineage (exp))
+ {
+ CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_BADDIR 2: `%s'\n", exp);
+ return COL_ERROR_BADDIR;
+ }
+ static char exp_name_env[MAXPATHLEN + 1];
+ TprintfT (DBG_LT1, "collector_open_experiment: setting SP_COLLECTOR_EXPNAME to %s\n", __collector_exp_dir_name);
+ CALL_UTIL (snprintf)(exp_name_env, sizeof (exp_name_env), "SP_COLLECTOR_EXPNAME=%s", __collector_exp_dir_name);
+ CALL_UTIL (putenv)(exp_name_env);
+ }
+ /* Check that the name is that of a directory (new structure) */
+ DIR *expDir = CALL_UTIL (opendir)(__collector_exp_dir_name);
+ if (expDir == NULL)
+ {
+ /* can't open it */
+ CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_BADDIR 3: `%s'\n", exp);
+ return COL_ERROR_BADDIR;
+ }
+ CALL_UTIL (closedir)(expDir);
+
+ if (CALL_UTIL (access)(__collector_exp_dir_name, W_OK))
+ {
+ TprintfT (0, "collector: ERROR: access error: errno=%d\n", errno);
+ if ((errno == EACCES) || (errno == EROFS))
+ {
+ CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_DIRPERM: `%s'\n", exp);
+ TprintfT (DBG_LT0, "collector: ERROR: experiment directory `%s' is not writeable\n",
+ __collector_exp_dir_name);
+ return COL_ERROR_DIRPERM;
+ }
+ else
+ {
+ CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_BADDIR 4: `%s'\n", exp);
+ return COL_ERROR_BADDIR;
+ }
+ }
+
+ /* reset the paused flag */
+ collector_paused = (origin == SP_ORIGIN_FORK ? paused_when_suspended : 0);
+
+ /* mark the experiment as opened */
+ __collector_expstate = EXP_OPEN;
+ TprintfT (DBG_LT1, "collector: __collector_expstate->EXP_OPEN\n");
+
+ /* open the log file */
+ err = log_open ();
+ if (err != COL_ERROR_NONE)
+ {
+ CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_LOG_OPEN\n");
+ return COL_ERROR_LOG_OPEN;
+ }
+ if (origin != SP_ORIGIN_GENEXP && origin != SP_ORIGIN_KERNEL)
+ log_header_write (origin);
+
+ /* Make a copy of params so that we can modify the string */
+ int paramsz = CALL_UTIL (strlen)(params) + 1;
+ buf = (char*) alloca (paramsz);
+ if (buf == NULL)
+ {
+ CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_ARGS2BIG: %s\n", params);
+ TprintfT (DBG_LT0, "collector: ERROR: experiment parameter `%s' is too long\n", params);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\"/></event>\n",
+ SP_JCMD_CERROR, COL_ERROR_ARGS2BIG);
+ return COL_ERROR_ARGS2BIG;
+ }
+ CALL_UTIL (strlcpy)(buf, params, paramsz);
+
+ /* create directory for archives (if founder) */
+ char archives[MAXPATHLEN];
+ CALL_UTIL (snprintf)(archives, MAXPATHLEN, "%s/%s", __collector_exp_dir_name,
+ SP_ARCHIVES_DIR);
+ if (is_founder)
+ {
+ mode_t dmode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+ if ((CALL_UTIL (mkdir)(archives, dmode) != 0) && (errno != EEXIST))
+ {
+ CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_MKDIR: %s: errno = %d\n", archives, errno);
+ TprintfT (0, "collector: ERROR: mkdir(%s) failed: errno = %d\n", archives, errno);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">mkdir(%s): errno=%d</event>\n",
+ SP_JCMD_COMMENT, COL_COMMENT_NONE, archives, errno);
+ /* this is not a fatal error currently */
+ }
+ else
+ TprintfT (DBG_LT1, "collector: archive mkdir(%s) succeeded\n", archives);
+ }
+
+ /* initialize the segments map and mmap interposition */
+ if (origin != SP_ORIGIN_GENEXP && origin != SP_ORIGIN_KERNEL)
+ {
+ if ((err = __collector_ext_mmap_install (1)) != COL_ERROR_NONE)
+ {
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\"/></event>\n", SP_JCMD_CERROR, err);
+ return err;
+ }
+ }
+
+ /* open the overview file for sample data */
+ if (origin != SP_ORIGIN_GENEXP)
+ ovw_open ();
+
+ /* initialize TSD module (note: relies on __collector_heap) */
+ if (__collector_tsd_init () != 0)
+ {
+ CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_TSD_INIT\n");
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">TSD could not be initialized</event>\n", SP_JCMD_CERROR, COL_ERROR_TSD_INIT);
+ return COL_ERROR_TSD_INIT;
+ }
+
+ /* experiment is initialized; allow pause/resume/close */
+ exp_initted = 1;
+
+ // 24935305 should not use SIGPROF if collect -p -t and -S are all off
+ /* (check here if -t or -S is on; -p is checked later) */
+ if (((params[0] == 't' || params[0] == 'S') && params[1] == ':')
+ || CALL_UTIL (strstr)(params, ";t:")
+ || CALL_UTIL (strstr)(params, ";S:"))
+ {
+ /* set a default time to 100 ms.; use negative value to force setting */
+ TprintfT (DBG_LT1, "collector: open_experiment setting timer to 100000\n");
+ __collector_ext_itimer_set (-100000);
+ }
+
+ /* call open for all dynamic modules */
+ int i;
+ for (i = 0; i < nmodules; i++)
+ {
+ if (modules[i]->openExperiment != NULL)
+ {
+ modules_st[i] = modules[i]->openExperiment (__collector_exp_dir_name);
+ if (modules_st[i] == COL_ERROR_NONE && modules[i]->description != NULL)
+ {
+ modules_hndl[i] = __collector_create_handle (modules[i]->description);
+ if (modules_hndl[i] == NULL)
+ modules_st[i] = -1;
+ }
+ }
+ /* check to see if anyone closed the experiment */
+ if (!exp_initted)
+ {
+ CALL_UTIL (fprintf)(stderr, "__collector_open_experiment: COL_ERROR_EXP_OPEN\n");
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">Experiment closed prematurely</event>\n", SP_JCMD_CERROR, COL_ERROR_EXPOPEN);
+ return COL_ERROR_EXPOPEN;
+ }
+ }
+
+ /* initialize for subsequent stack unwinds */
+ __collector_ext_unwind_init (1);
+ TprintfT (DBG_LT0, "__collector_open_experiment(); module init done, params=%s\n",
+ buf);
+
+ /* now parse the data descriptor */
+ /* The parameter string is a series of specifiers,
+ * each of which is of the form:
+ * <key>:<param>;
+ * key is a single letter, the : and ; are mandatory,
+ * and param is a string which may be zero-length, and
+ * which contains any character except a null-byte or ;
+ * param is interpreted by the handler for the particular key
+ */
+
+ s = buf;
+
+ while (*s)
+ {
+ char *par;
+ char key = *s++;
+ /* ensure that it's followed by a colon */
+ if (*s++ != ':')
+ {
+ TprintfT (0, "collector: ERROR: parameter %c is not followed by a colon\n", key);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, COL_ERROR_ARGS, params);
+ return COL_ERROR_ARGS;
+ }
+ /* find the semicolon terminator */
+ par = s;
+ while (*s && (*s != ';'))
+ s++;
+ if (*s != ';')
+ {
+ /* not followed by semicolon */
+ TprintfT (0, "collector: ERROR: parameter %c:%s is not terminated by a semicolon\n", key, par);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, COL_ERROR_ARGS, params);
+ return COL_ERROR_ARGS;
+ }
+ /* terminate par, and position for next descriptor */
+ *s++ = 0;
+
+ /* now process that element of the data descriptor */
+ switch (key)
+ {
+ case 'g': /* g<sig>; */
+ if ((err = sample_set_user_sig (par)) != COL_ERROR_NONE)
+ {
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par);
+ return err;
+ }
+ break;
+ case 'd': /* d<sig>; -or- d<sig>p; */
+ if ((err = pause_set_user_sig (par)) != COL_ERROR_NONE)
+ {
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par);
+ return err;
+ }
+ break;
+ case 'H':
+ m_dlopen ("libgp-heap.so", RTLD_LAZY); /* hack to force .so's constructor to be called (?) */
+ break;
+ case 's':
+ m_dlopen ("libgp-sync.so", RTLD_LAZY); /* hack to force .so's constructor to be called (?) */
+ break;
+ case 'i':
+ m_dlopen ("libgp-iotrace.so", RTLD_LAZY); /* hack to force .so's constructor to be called (?) */
+ break;
+ case 'F': /* F; */
+ seen_F_flag = 1;
+ TprintfT (DBG_LT0, "__collector_open_experiment: calling __collector_ext_line_install (%s, %s)\n",
+ par, __collector_exp_dir_name);
+ if ((err = __collector_ext_line_install (par, __collector_exp_dir_name)) != COL_ERROR_NONE)
+ {
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par);
+ return err;
+ }
+ break;
+ case 'a': /* a; */
+ archive_mode = __collector_strdup (par);
+ break;
+ case 't': /* t:<expt-duration>; */
+ duration_string = par;
+ break;
+ case 'S': /* S:<sample-interval>; */
+ if ((err = sample_set_interval (par)) != COL_ERROR_NONE)
+ {
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par);
+ return err;
+ }
+ break;
+ case 'L': /* L:<experiment-size-limit>; */
+ if ((err = __collector_set_size_limit (par)) != COL_ERROR_NONE)
+ {
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par);
+ return err;
+ }
+ break;
+ case 'P': /* P:PROJECT_HOME; */
+ project_home = __collector_strdup (par);
+ break;
+ case 'h':
+ case 'p':
+ fs_matters = 1;
+ break;
+ case 'Y':
+ err = set_user_sig_action (par);
+ if (err != COL_ERROR_NONE)
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par);
+ break;
+ default:
+ /* Ignore unknown parameters; allow them to be handled by modules */
+ break;
+ }
+ }
+ /* end of data descriptor parsing */
+
+ if (!seen_F_flag)
+ {
+ char * par = "0"; // This will not happen when collect has no -F option
+ if ((err = __collector_ext_line_install (par, __collector_exp_dir_name)) != COL_ERROR_NONE)
+ {
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, par);
+ return err;
+ }
+ }
+
+ /* now that we know what data is being collected, we can set the filesystem warning */
+ fs_warn ();
+
+ // We have to create all tsd keys before __collector_tsd_allocate().
+ // With the pthreads-based implementation, this might no longer be necessary.
+ // In any case, we still have to create the key before a thread can use it.
+ __collector_ext_gettid_tsd_create_key ();
+ __collector_ext_dispatcher_tsd_create_key ();
+
+ /* allocate tsd for the current thread */
+ if (__collector_tsd_allocate () != 0)
+ {
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">TSD allocate failed</event>\n", SP_JCMD_CERROR, COL_ERROR_EXPOPEN);
+ return COL_ERROR_EXPOPEN;
+ }
+ /* init tsd for unwind, called right after __collector_tsd_allocate()*/
+ __collector_ext_unwind_key_init (1, NULL);
+
+ /* start java attach if suitable */
+ if (exp_origin == SP_ORIGIN_DBX_ATTACH)
+ __collector_jprofile_start_attach ();
+ start_sec_time = CALL_UTIL (time)(NULL);
+ __collector_start_time = collector_interface.getHiResTime ();
+ TprintfT (DBG_LT0, "\t__collector_open_experiment; resetting start_time\n");
+ if (duration_string != NULL && (err = set_duration (duration_string)) != COL_ERROR_NONE)
+ {
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CERROR, err, duration_string);
+ return err;
+ }
+
+ /* install the common SIGPROF dispatcher (requires TSD) */
+ if ((err = __collector_ext_dispatcher_install ()) != COL_ERROR_NONE)
+ {
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\"/></event>\n", SP_JCMD_CERROR, err);
+ return err;
+ }
+
+ /* mark the experiment open complete */
+ exp_open = 1;
+ if (exp_origin == SP_ORIGIN_DBX_ATTACH)
+ __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" time=\"%lld\" tm_zone=\"%lld\"/>\n",
+ SP_JCMD_RUN,
+ (unsigned) (__collector_start_time / NANOSEC), (unsigned) (__collector_start_time % NANOSEC),
+ (long long) start_sec_time, (long long) 0);
+ else
+ log_write_event_run ();
+
+ /* schedule the first sample */
+ __collector_next_sample = __collector_start_time + ((hrtime_t) NANOSEC) * __collector_sample_period;
+ __collector_ext_usage_sample (MASTER_SMPL, "collector_open_experiment");
+
+ /* start data collection in dynamic modules */
+ if (collector_paused == 0)
+ {
+ for (i = 0; i < nmodules; i++)
+ if (modules[i]->startDataCollection != NULL && modules_st[i] == 0)
+ modules[i]->startDataCollection ();
+ }
+ else
+ {
+ hrtime_t ts = GETRELTIME ();
+ (void) __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n",
+ SP_JCMD_PAUSE, (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC));
+ }
+
+ /* mark the experiment active */
+ __collector_exp_active = 1;
+ return COL_ERROR_NONE;
+}
+
+/* prepare directory for new experiment of fork-child */
+
+/* return 0 if successful */
+static int
+collector_create_expr_dir (const char *new_exp_name)
+{
+ int ret = -1;
+ mode_t dmode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+ TprintfT (DBG_LT1, "collector: __collector_create_expr_dir(%s)\n", new_exp_name);
+ if (CALL_UTIL (mkdir)(new_exp_name, dmode) < 0)
+ TprintfT (0, "__collector_create_expr_dir(%s) ERROR: errno=%d\n", new_exp_name, errno);
+ else
+ ret = 0;
+ return (ret);
+}
+
+/* append _xN to __collector_exp_dir_name*/
+/* return 0 if successful */
+static int
+collector_exp_dir_append_x (int linenum, const char *parent_exp_name)
+{
+ char buffer[MAXPATHLEN + 1];
+ char * p = __collector_strrchr (parent_exp_name, '/');
+ if (p == NULL || (*(p + 1) != '_'))
+ {
+ size_t sz = CALL_UTIL (strlen)(parent_exp_name);
+ const char * q = parent_exp_name + sz - 3;
+ if (sz < 3 || __collector_strncmp (q, ".er", CALL_UTIL (strlen)(q)) != 0
+ || CALL_UTIL (access)(parent_exp_name, F_OK) != 0)
+ {
+ TprintfT (0, "collector_exp_dir_append_x() ERROR: invalid parent_exp_name %s\n", parent_exp_name);
+ return -1;
+ }
+ CALL_UTIL (strlcpy)(buffer, parent_exp_name, sizeof (buffer));
+ CALL_UTIL (snprintf)(__collector_exp_dir_name, sizeof (__collector_exp_dir_name),
+ "%s/_x%d.er", buffer, linenum);
+ }
+ else
+ {
+ p = __collector_strrchr (parent_exp_name, '.');
+ if (p == NULL || *(p + 1) != 'e' || *(p + 2) != 'r')
+ {
+ TprintfT (0, "collector_exp_dir_append_x() ERROR: invalid parent_exp_name %s\n", parent_exp_name);
+ return -1;
+ }
+ CALL_UTIL (strlcpy)(buffer, parent_exp_name,
+ ((p - parent_exp_name + 1)<sizeof (buffer)) ? (p - parent_exp_name + 1) : sizeof (buffer));
+ CALL_UTIL (snprintf)(__collector_exp_dir_name, sizeof (__collector_exp_dir_name),
+ "%s_x%d.er", buffer, linenum);
+ }
+ return 0;
+}
+
+/* prepare directory for new experiment of exec/combo child*/
+
+/* return 0 if successful */
+static int
+collector_create_expr_dir_lineage (const char *parent_exp_name)
+{
+ int ret = -1;
+ mode_t dmode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+ int linenum = 1;
+ while (linenum < INT_MAX)
+ {
+ if (collector_exp_dir_append_x (linenum, parent_exp_name) != 0)
+ return -1;
+ if (CALL_UTIL (access)(__collector_exp_dir_name, F_OK) != 0)
+ {
+ if (CALL_UTIL (mkdir)(__collector_exp_dir_name, dmode) == 0)
+ return 0;
+ }
+ linenum++;
+ TprintfT (DBG_LT0, "collector: collector_create_expr_dir_lineage(%s -> %s)\n", parent_exp_name, __collector_exp_dir_name);
+ }
+ return (ret);
+}
+
+/* Finish the initializing work if we don't collect data while libcollector.so is preloaded. */
+/* return COL_ERROR_NONE if successful */
+static int
+collector_tail_init (const char *parent_exp_name)
+{
+ int err = COL_ERROR_NONE;
+ if (exp_origin != SP_ORIGIN_FORK)
+ {
+ /* For exec/combo descendants. Don't create dir for this subexp, but update lineage by appending "_x0". */
+ /* Different children can have the same _x0 if their name don't match -F exp.
+ * Assume their fork children inherit the program name, there will be no _x0_fN.er to create.
+ * So we don't need to worry about the lineage messed up by _x0.
+ */
+ int linenum = 0;
+ if (collector_exp_dir_append_x (linenum, parent_exp_name) != 0)
+ return COL_ERROR_BADDIR;
+ static char exp_name_env[MAXPATHLEN + 1];
+ CALL_UTIL (snprintf)(exp_name_env, sizeof (exp_name_env), "SP_COLLECTOR_EXPNAME=%s", __collector_exp_dir_name);
+ TprintfT (DBG_LT1, "collector_tail_init: setting SP_COLLECTOR_EXPNAME to %s\n", __collector_exp_dir_name);
+ CALL_UTIL (putenv)(exp_name_env);
+ }
+ /* initialize the segments map and mmap interposition */
+ if (exp_origin != SP_ORIGIN_GENEXP && exp_origin != SP_ORIGIN_KERNEL)
+ if ((err = __collector_ext_mmap_install (0)) != COL_ERROR_NONE)
+ return err;
+
+ /* initialize TSD module (note: relies on __collector_heap) */
+ if (__collector_tsd_init () != 0)
+ return COL_ERROR_EXPOPEN;
+
+ /* initialize for subsequent stack unwinds */
+ __collector_ext_unwind_init (0);
+
+ char * buf = NULL;
+ /* Make a copy of params so that we can modify the string */
+ int paramsz = CALL_UTIL (strlen)(collector_params) + 1;
+ buf = (char*) alloca (paramsz);
+ CALL_UTIL (strlcpy)(buf, collector_params, paramsz);
+
+ char *par_F = "0";
+ char *s;
+ for (s = buf; *s;)
+ {
+ char key = *s++;
+ /* ensure that it's followed by a colon */
+ if (*s++ != ':')
+ {
+ TprintfT (DBG_LT0, "collector_tail_init: ERROR: parameter %c is not followed by a colon\n", key);
+ return COL_ERROR_ARGS;
+ }
+
+ /* find the semicolon terminator */
+ char *par = s;
+ while (*s && (*s != ';'))
+ s++;
+ if (*s != ';')
+ {
+ /* not followed by semicolon */
+ TprintfT (0, "collector_tail_init: ERROR: parameter %c:%s is not terminated by a semicolon\n", key, par);
+ return COL_ERROR_ARGS;
+ }
+ /* terminate par, and position for next descriptor */
+ *s++ = 0;
+ /* now process that element of the data descriptor */
+ if (key == 'F')
+ {
+ par_F = par;
+ break;
+ }
+ }
+ if ((err = __collector_ext_line_install (par_F, __collector_exp_dir_name)) != COL_ERROR_NONE)
+ return err;
+
+ /* allocate tsd for the current thread */
+ if (__collector_tsd_allocate () != 0)
+ return COL_ERROR_EXPOPEN;
+ return COL_ERROR_NONE;
+}
+
+/* routines concerning closing the experiment */
+/* close down -- fini section routine */
+static void collector_fini () __attribute__ ((destructor));
+static void
+collector_fini ()
+{
+ TprintfT (DBG_LT0, "collector_fini: closing experiment\n");
+ __collector_close_experiment ();
+
+}
+
+void collector_terminate_expt () __attribute__ ((weak, alias ("__collector_terminate_expt")));
+
+/* __collector_terminate_expt called by user, or from dbx */
+void
+__collector_terminate_expt ()
+{
+ TprintfT (DBG_LT0, "__collector_terminate_expt: %s; calling close\n", __collector_exp_dir_name);
+ __collector_close_experiment ();
+ TprintfT (DBG_LT0, "__collector_terminate_expt done\n\n");
+}
+
+/*
+ * We manage the SIGCHLD handler with sigaction and don't worry about signal or sigset().
+ * This is in line with the comments in dispatcher.c
+ * immediately preceding the wrapper function for (Linux) signal().
+ */
+static struct sigaction original_sigchld_sigaction;
+static pid_t mychild_pid = -1;
+
+/* __collector_SIGCHLD_signal_handler called when er_archive exits */
+static void
+__collector_SIGCHLD_signal_handler (int sig, siginfo_t *si, void *context)
+{
+ pid_t calling_pid = si->si_pid;
+ /* Potential race.
+ * We get mychild_pid from the vfork() return value.
+ * So there is an outside chance that the child completes and sends SIGCHLD
+ * before the handler knows the value of mychild_pid.
+ */
+ if (calling_pid == mychild_pid)
+ // er_archive has exited; so restore the user handler
+ __collector_sigaction (SIGCHLD, &original_sigchld_sigaction, NULL);
+ else
+ {
+ // if we can't identify the pid, the signal must be for the user's handler
+ if (original_sigchld_sigaction.sa_handler != SIG_DFL
+ && original_sigchld_sigaction.sa_handler != SIG_IGN)
+ original_sigchld_sigaction.sa_sigaction (sig, si, context);
+ }
+ TprintfT (DBG_LT1, "__collector_SIGCHLD_signal_handler done\n\n");
+}
+
+int
+collector_sigchld_sigaction (const struct sigaction *nact,
+ struct sigaction *oact)
+{
+ // get the current SIGCHLD handler
+ struct sigaction cur_handler;
+ __collector_sigaction (SIGCHLD, NULL, &cur_handler);
+
+ // if we have NOT installed our own handler, return an error
+ // (force the caller to deal with this case)
+ if (cur_handler.sa_sigaction != __collector_SIGCHLD_signal_handler)
+ return -1;
+
+ // if we HAVE installed our own handler, act on the user's handler
+ if (oact)
+ __collector_memcpy (oact, &original_sigchld_sigaction, sizeof (struct sigaction));
+ if (nact)
+ __collector_memcpy (&original_sigchld_sigaction, nact, sizeof (struct sigaction));
+ return 0;
+}
+
+/*
+ * __collector_close_experiment may be called either from
+ * __collector_terminate_expt() or the .fini section
+ */
+void
+__collector_close_experiment ()
+{
+ hrtime_t ts;
+ char *argv[10];
+ int status;
+ TprintfT (DBG_LT1, "collector: __collector_close_experiment(): %s\n", __collector_exp_dir_name);
+ if (!exp_initted)
+ return;
+ /* The experiment may have been previously closed */
+ if (!exp_open)
+ return;
+
+ if (__collector_mutex_trylock (&__collector_close_guard))
+ /* someone else is in the middle of closing the experiment */
+ return;
+
+ /* record the termination of the experiment */
+ ts = GETRELTIME ();
+ collector_params = NULL;
+
+ /* tell all dynamic modules to stop data collection */
+ int i;
+ for (i = 0; i < nmodules; i++)
+ if (modules[i]->stopDataCollection != NULL)
+ modules[i]->stopDataCollection ();
+
+ /* notify all dynamic modules the experiment is being closed */
+ for (i = 0; i < nmodules; i++)
+ {
+ if (modules[i]->closeExperiment != NULL)
+ modules[i]->closeExperiment ();
+ __collector_delete_handle (modules_hndl[i]);
+ modules_hndl[i] = NULL;
+ }
+
+ /* acquire the global lock -- only one close at a time */
+ __collector_mutex_lock (&__collector_glob_lock);
+ /* deinstall mmap tracing (with final update) */
+ __collector_ext_mmap_deinstall (1);
+
+ /* deinstall common SIGPROF dispatcher */
+ __collector_ext_dispatcher_deinstall ();
+
+ /* disable line interposition */
+ __collector_ext_line_close ();
+
+ /* Other threads may be reading tsd now. */
+ //__collector_tsd_fini();
+
+ /* delete global heap */
+ /* omazur: do not delete the global heap
+ * to avoid crashes in TSD. Need a better solution.
+ __collector_deleteHeap( __collector_heap );
+ __collector_heap = NULL;
+ */
+ __collector_mutex_unlock (&__collector_glob_lock);
+
+ /* take a final sample */
+ __collector_ext_usage_sample (MASTER_SMPL, "collector_close_experiment");
+ sample_mode = 0;
+
+ /* close the frameinfo file */
+ __collector_ext_unwind_close ();
+ if (exp_origin != SP_ORIGIN_DBX_ATTACH)
+ log_write_event_run ();
+
+ /* mark the experiment as closed */
+ __collector_expstate = EXP_CLOSED;
+ TprintfT (DBG_LT1, "collector: __collector_expstate->EXP_CLOSED: project_home=%s\n",
+ STR (project_home));
+ __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n",
+ SP_JCMD_EXIT,
+ (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC));
+
+ /* derive er_archive's absolute path from that of libcollector */
+ argv[0] = NULL;
+ if (project_home && archive_mode && __collector_strcmp (archive_mode, "off"))
+ {
+ /* construct a command to launch it */
+ char *er_archive_name = "/bin/gp-archive";
+ size_t cmdlen = CALL_UTIL (strlen)(project_home) + CALL_UTIL (strlen)(er_archive_name) + 1;
+ char *command = (char*) alloca (cmdlen);
+ CALL_UTIL (snprintf)(command, cmdlen, "%s%s", project_home, er_archive_name);
+ if (CALL_UTIL (access)(command, F_OK) == 0)
+ {
+ // build the argument list
+ int nargs = 0;
+ argv[nargs++] = command;
+ argv[nargs++] = "-n";
+ argv[nargs++] = "-a";
+ argv[nargs++] = archive_mode;
+ size_t len = CALL_UTIL (strlen)(__collector_exp_dir_name) + 1;
+ size_t len1 = CALL_UTIL (strlen)(SP_ARCHIVE_LOG_FILE) + 1;
+ char *str = (char*) alloca (len + len1);
+ CALL_UTIL (snprintf)(str, len + 15, "%s/%s", __collector_exp_dir_name, SP_ARCHIVE_LOG_FILE);
+ argv[nargs++] = "--outfile";
+ argv[nargs++] = str;
+ str = (char*) alloca (len);
+ CALL_UTIL (snprintf)(str, len, "%s", __collector_exp_dir_name);
+ argv[nargs++] = str;
+ argv[nargs] = NULL;
+ }
+ }
+
+ /* log the archive command to be run */
+ if (argv[0] == NULL)
+ {
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
+ SP_JCMD_COMMENT, COL_COMMENT_NONE, "No archive command run");
+ TprintfT (DBG_LT1, "collector: No archive command run\n");
+ }
+ else
+ {
+ char cmdbuf[4096];
+ int bufoffset = 0;
+ int i;
+ for (i = 0; argv[i] != NULL; i++)
+ {
+ bufoffset += CALL_UTIL (snprintf)(&cmdbuf[bufoffset], (sizeof (cmdbuf) - bufoffset),
+ " %s", argv[i]);
+ }
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">Archive command `%s'</event>\n",
+ SP_JCMD_COMMENT, COL_COMMENT_NONE, cmdbuf);
+ TprintfT (DBG_LT1, "collector: running `%s'\n", cmdbuf);
+ }
+ log_close ();
+ TprintfT (DBG_LT1, "__collector_close_experiment(%s) done\n", __collector_exp_dir_name);
+ exp_open = 0; /* mark the experiment as closed */
+ __collector_exp_active = 0; /* mark the experiment as inactive */
+
+ /* reset all experiment parameters */
+ sample_mode = 0;
+ collector_paused = 0;
+ __collector_pause_sig = -1;
+ __collector_pause_sig_warn = 0;
+ __collector_sample_sig = -1;
+ __collector_sample_sig_warn = 0;
+ __collector_sample_period = 0;
+ __collector_exp_dir_name[0] = 0;
+
+ /* uninstall the pause and sample signal handlers */
+ /* XXXX -- not yet, because of potential race conditions in libthread */
+ if (argv[0] == NULL)
+ {
+ /* er_archive command will not be run */
+ __collector_mutex_unlock (&__collector_close_guard);
+ return;
+ }
+
+ struct sigaction sa;
+ CALL_UTIL (memset)(&sa, 0, sizeof (struct sigaction));
+ sa.sa_sigaction = __collector_SIGCHLD_signal_handler;
+ sa.sa_flags = SA_SIGINFO;
+ __collector_sigaction (SIGCHLD, &sa, &original_sigchld_sigaction);
+
+ /* linetrace interposition takes care of unsetting Environment variables */
+ /* create a child process to invoke er_archive */
+ pid_t pid = CALL_UTIL (vfork)();
+ if (pid == 0)
+ {
+ /* pid is zero == child process -- invoke er_archive */
+ /* Unset LD_PRELOAD environment variables */
+ CALL_UTIL (unsetenv)("LD_PRELOAD_32");
+ CALL_UTIL (unsetenv)("LD_PRELOAD_64");
+ CALL_UTIL (unsetenv)("LD_PRELOAD");
+ /* Invoke er_archive */
+ CALL_UTIL (execv)(argv[0], argv);
+ CALL_UTIL (exit)(1); /* exec failed -- child exits with an error */
+ }
+ else if (pid != -1)
+ {
+ mychild_pid = pid; // notify our signal handler who the child is
+ pid_t w;
+ /* copied from system.c */
+ do
+ {
+ w = CALL_UTIL (waitpid)(pid, &status, 0);
+ }
+ while (w == -1 && errno == EINTR);
+ TprintfT (DBG_LT1, "collector: creating archive done\n");
+ // __collector_SIGCHLD_signal_handler should now be de-installed, but it does so itself
+ }
+ else
+ /* child-process creation failed */
+ TprintfT (DBG_LT0, "collector: creating archive process failed\n");
+
+ __collector_mutex_unlock (&__collector_close_guard);
+ TprintfT (DBG_LT1, "collector: __collector_close_experiment done\n");
+ return;
+}
+
+/*
+ * void __collector_clean_state()
+ * Perform all necessary cleanup steps in child process after fork().
+ */
+void
+__collector_clean_state ()
+{
+ TprintfT (DBG_LT1, "collector: collector_clean_state()\n");
+ int i;
+ /*
+ * We are in child process after fork().
+ * First of all we have to reset all mutex locks in collector's subsystems.
+ * After that we can reinitialize modules.
+ */
+ __collector_mmgr_init_mutex_locks (__collector_heap);
+ __collector_mutex_init (&__collector_glob_lock);
+ __collector_mutex_init (&__collector_open_guard);
+ __collector_mutex_init (&__collector_close_guard);
+ __collector_mutex_init (&__collector_sample_guard);
+ __collector_mutex_init (&__collector_suspend_guard);
+ __collector_mutex_init (&__collector_resume_guard);
+
+ if (__collector_mutex_trylock (&__collector_close_guard))
+ /* someone else is in the middle of closing the experiment */
+ return;
+
+ /* Stop data collection in all dynamic modules */
+ for (i = 0; i < nmodules; i++)
+ if (modules[i]->stopDataCollection != NULL)
+ modules[i]->stopDataCollection ();
+
+ // Now we can reset modules
+ for (i = 0; i < nmodules; i++)
+ {
+ if (modules[i]->detachExperiment != NULL && modules_st[i] == 0)
+ modules[i]->detachExperiment ();
+ __collector_delete_handle (modules_hndl[i]);
+ modules_hndl[i] = NULL;
+ }
+
+ /* acquire the global lock -- only one suspend at a time */
+ __collector_mutex_lock (&__collector_glob_lock);
+ {
+
+ /* stop any profile data writing */
+ paused_when_suspended = collector_paused;
+ collector_paused = 1;
+
+ /* deinstall common SIGPROF dispatcher */
+ __collector_ext_dispatcher_suspend ();
+
+ /* mark the experiment as suspended */
+ __collector_exp_active = 0;
+
+ /* XXXX mark the experiment as closed! */
+ exp_open = 0; /* This is a hack to allow fork child to call__collector_open_experiment() */
+
+ /* mark the experiment log closed! */
+ log_close ();
+ }
+ __collector_mutex_unlock (&__collector_glob_lock);
+
+ // Now we can reset subsystems.
+ __collector_ext_dispatcher_fork_child_cleanup ();
+ __collector_mmap_fork_child_cleanup ();
+ __collector_tsd_fork_child_cleanup ();
+ paused_when_suspended = 0;
+ collector_paused = 0;
+ __collector_expstate = EXP_INIT;
+ TprintfT (DBG_LT1, "__collector_clean_slate: __collector_expstate->EXP_INIT\n");
+ exp_origin = SP_ORIGIN_LIBCOL_INIT;
+ exp_initted = 0;
+ __collector_start_time = collector_interface.getHiResTime ();
+ TprintfT (DBG_LT1, " -->__collector_clean_slate; resetting start_time\n");
+ start_sec_time = 0;
+
+ /* Sample related data */
+ sample_installed = 0; // 1 if the sample signal handler installed
+ sample_mode = 0; // dynamically turns sample record writing on/off
+ sample_number = 0; // index of the current sample record
+ __collector_sample_sig = -1; // user-specified sample signal
+ __collector_sample_sig_warn = 0; // non-zero if warning already given
+
+ /* Pause/resume related data */
+ __collector_pause_sig = -1; // user-specified pause signal
+ __collector_pause_sig_warn = 0; // non-zero if warning already given
+ __collector_mutex_unlock (&__collector_close_guard);
+ return;
+}
+
+/* modelled on __collector_close_experiment */
+void
+__collector_suspend_experiment (char *why)
+{
+ if (!exp_initted)
+ return;
+ /* The experiment may have been previously closed */
+ if (!exp_open)
+ return;
+ /* The experiment may have been previously suspended */
+ if (!__collector_exp_active)
+ return;
+ if (__collector_mutex_trylock (&__collector_suspend_guard))
+ /* someone else is in the middle of suspending the experiment */
+ return;
+
+ /* Stop data collection in all dynamic modules */
+ int i;
+ for (i = 0; i < nmodules; i++)
+ if (modules[i]->stopDataCollection != NULL)
+ modules[i]->stopDataCollection ();
+
+ /* take a pre-suspension sample */
+ __collector_ext_usage_sample (MASTER_SMPL, why);
+
+ /* acquire the global lock -- only one suspend at a time */
+ __collector_mutex_lock (&__collector_glob_lock);
+ /* stop any profile data writing */
+ paused_when_suspended = collector_paused;
+ collector_paused = 1;
+
+ /* deinstall common SIGPROF dispatcher */
+ __collector_ext_dispatcher_suspend ();
+
+ /* mark the experiment as suspended */
+ __collector_exp_active = 0;
+
+ /* XXXX mark the experiment as closed! */
+ exp_open = 0; // This is a hack to allow fork child to call __collector_open_experiment()
+ log_pause (); // mark the experiment log closed!
+ TprintfT (DBG_LT0, "collector: collector_suspend_experiment(%s, %d)\n\n", why, collector_paused);
+ __collector_mutex_unlock (&__collector_glob_lock);
+ __collector_mutex_unlock (&__collector_suspend_guard);
+ return;
+}
+
+void
+__collector_resume_experiment ()
+{
+ if (!exp_initted)
+ return;
+
+ /* The experiment may have been previously resumed */
+ if (__collector_exp_active)
+ return;
+ if (__collector_mutex_trylock (&__collector_resume_guard))
+ /* someone else is in the middle of resuming the experiment */
+ return;
+
+ /* acquire the global lock -- only one resume at a time */
+ __collector_mutex_lock (&__collector_glob_lock);
+ /* mark the experiment as re-activated */
+ __collector_exp_active = 1;
+ /* XXXX mark the experiment as open! */
+ exp_open = 1; // This is a hack to allow fork child to call__collector_open_experiment()
+ log_resume (); // mark the experiment log re-opened!
+ TprintfT (DBG_LT0, "collector: collector_resume_experiment(%d)\n", paused_when_suspended);
+ /* resume any profile data writing */
+ collector_paused = paused_when_suspended;
+ /* restart common SIGPROF dispatcher */
+ __collector_ext_dispatcher_restart ();
+ __collector_mutex_unlock (&__collector_glob_lock);
+
+ /* take a post-suspension sample */
+ __collector_ext_usage_sample (MASTER_SMPL, "collector_resume_experiment");
+
+ /* Resume data collection in all dynamic modules */
+ if (collector_paused == 0)
+ {
+ int i;
+ for (i = 0; i < nmodules; i++)
+ if (modules[i]->startDataCollection != NULL && modules_st[i] == 0)
+ modules[i]->startDataCollection ();
+ }
+
+ if (__collector_sample_period != 0)
+ {
+ hrtime_t now = collector_interface.getHiResTime ();
+ while (__collector_next_sample < now)
+ __collector_next_sample += ((hrtime_t) NANOSEC) * __collector_sample_period;
+ }
+
+ /* check for experiment past termination time */
+ if (__collector_terminate_time != 0)
+ {
+ hrtime_t now = collector_interface.getHiResTime ();
+ if (__collector_terminate_time < now)
+ {
+ TprintfT (DBG_LT0, "__collector_resume_experiment: now (%lld) > terminate_time (%lld); closing experiment\n",
+ (now - __collector_start_time), (__collector_terminate_time - __collector_start_time));
+ __collector_close_experiment ();
+ }
+ }
+ __collector_mutex_unlock (&__collector_resume_guard);
+ return;
+}
+
+/* Code to support Samples and Pause/Resume */
+void collector_sample () __attribute__ ((weak, alias ("__collector_sample")));
+void
+__collector_sample (char *name)
+{
+ __collector_ext_usage_sample (PROGRAM_SMPL, name);
+}
+
+static void
+write_sample (char *name)
+{
+ if (sample_mode == 0)
+ return;
+ /* make the sample timestamp relative to the start */
+ hrtime_t ts, now = collector_interface.getHiResTime ();
+
+ /* update time for next periodic sample */
+ /* since this is common to all LWPs, and only one (the first!) will
+ update it to the next period, doing the update early will avoid
+ the overhead/frustration of the other LWPs
+ */
+ if (__collector_sample_period != 0)
+ {
+ /* this update should only be done for periodic samples */
+ while (__collector_next_sample < now)
+ __collector_next_sample += ((hrtime_t) NANOSEC) * __collector_sample_period;
+ }
+
+ /* take the sample and record it; use (return - __collector_start_time) for timestamp */
+ now = ovw_write ();
+ ts = now - __collector_start_time;
+
+ /* write sample records to log file */
+ __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" id=\"%d\" label=\"%s\"/>\n",
+ SP_JCMD_SAMPLE,
+ (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
+ sample_number,
+ name);
+ /* increment the sample number */
+ sample_number++;
+}
+
+/*
+ * __collector_ext_usage_sample
+ *
+ * Handle taking a process usage sample and recording it.
+ * Common to all different types of sample:
+ * libcollector master samples at initiation and close,
+ * programmatic samples via libcollector API calls,
+ * periodic samples originating in the dispatcher,
+ * manual samples originating in the signal sample handler,
+ * manual samples originating from the debugger
+ * Differentiating type and name information is currently not recorded.
+ */
+void
+__collector_ext_usage_sample (Smpl_type type, char *name)
+{
+ /* name is optional */
+ if (name == NULL)
+ name = "";
+ TprintfT (DBG_LT3, "collector: __collector_ext_usage_sample(%d,%s)\n", type, name);
+ if (!exp_initted)
+ return;
+
+ /* if paused, don't record periodic samples */
+ if ((type == PERIOD_SMPL) && (collector_paused == 1))
+ return;
+
+ /* There is a possibility of entering this function
+ * from sample_handler, dbx direct call to __collector_sample,
+ * and user called collector_sample. Since we are making a
+ * new sample anyway just return.
+ */
+ if (__collector_mutex_trylock (&__collector_sample_guard))
+ return;
+ if (type != PERIOD_SMPL || __collector_sample_period != 0)
+ write_sample (name);
+ __collector_mutex_unlock (&__collector_sample_guard);
+}
+
+/* set the sample period from the parameter */
+static int
+sample_set_interval (char *param)
+{
+ if (!exp_initted)
+ return COL_ERROR_SMPLINIT;
+ __collector_sample_period = CALL_UTIL (strtol)(param, NULL, 0); /* seconds */
+ TprintfT (DBG_LT1, "collector: collector_sample period set to %d seconds.\n",
+ __collector_sample_period);
+ if (__collector_sample_period > 0)
+ (void) __collector_log_write ("<setting %s=\"%d\"/>\n",
+ SP_JCMD_SAMPLE_PERIOD, __collector_sample_period);
+ return COL_ERROR_NONE;
+}
+
+/* set the experiment duration from the parameter */
+
+/* parameter is of the form nnn:mmm, where nnn is the start delay in seconds,
+ * and mmm is the terminate time in seconds; if nnn is zero,
+ * data collection starts when the run starts. If mmm is zero,
+ * data collection terminates when the run terminates. Otherwise,
+ * nnn must be less than mmm
+ */
+static int
+set_duration (char *param)
+{
+ if (!exp_initted)
+ return COL_ERROR_DURATION_INIT;
+ int delay_start = CALL_UTIL (strtol)(param, &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
index 0000000..c54568d
--- /dev/null
+++ b/gprofng/libcollector/collector.h
@@ -0,0 +1,236 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#ifndef _COLLECTOR_H
+#define _COLLECTOR_H
+
+#include <ucontext.h>
+#include <signal.h>
+
+#include "gp-defs.h"
+#include "data_pckts.h"
+#include "libcol_util.h"
+#include "collector_module.h"
+
+#define GETRELTIME() (__collector_gethrtime() - __collector_start_time)
+
+extern hrtime_t __collector_start_time;
+
+/* ========================================================== */
+/* ------- internal function prototypes ----------------- */
+/* These will not be exported from libcollector.so */
+struct DataHandle;
+struct Heap;
+extern struct DataHandle *__collector_create_handle (char*);
+extern void __collector_delete_handle (struct DataHandle*);
+extern int __collector_write_record (struct DataHandle*, Common_packet*);
+extern int __collector_write_packet (struct DataHandle*, CM_Packet*);
+extern int __collector_write_string (struct DataHandle*, char*, int);
+extern FrameInfo __collector_get_frame_info (hrtime_t, int, void *);
+extern FrameInfo __collector_getUID (CM_Array *arg, FrameInfo uid);
+extern int __collector_getStackTrace (void *buf, int size, void *bptr, void *eptr, void *arg);
+extern void *__collector_ext_return_address (unsigned level);
+extern void __collector_mmap_fork_child_cleanup ();
+
+extern int __collector_ext_mmap_install (int);
+extern int __collector_ext_mmap_deinstall (int);
+extern int __collector_ext_update_map_segments (void);
+extern int __collector_check_segment (unsigned long addr,
+ unsigned long *base,
+ unsigned long *end, int maxnretries);
+extern int __collector_check_readable_segment (unsigned long addr,
+ unsigned long *base,
+ unsigned long *end, int maxnretries);
+extern int __collector_ext_line_init (int * pfollow_this_experiment,
+ const char * progspec,
+ const char *progname);
+extern int __collector_ext_line_install (char *, const char *);
+extern void __collector_ext_line_close ();
+extern void __collector_ext_unwind_init (int);
+extern void __collector_ext_unwind_close ();
+extern int __collector_ext_jstack_unwind (char*, int, ucontext_t *);
+extern void __collector_ext_dispatcher_fork_child_cleanup ();
+extern void __collector_ext_unwind_key_init (int isPthread, void * stack);
+extern void __collector_ext_dispatcher_tsd_create_key ();
+extern void __collector_ext_dispatcher_thread_timer_suspend ();
+extern int __collector_ext_dispatcher_thread_timer_resume ();
+extern int __collector_ext_dispatcher_install ();
+extern void __collector_ext_dispatcher_suspend ();
+extern void __collector_ext_dispatcher_restart ();
+extern void __collector_ext_dispatcher_deinstall ();
+extern void __collector_ext_usage_sample (Smpl_type type, char *name);
+extern void __collector_ext_profile_handler (siginfo_t *, ucontext_t *);
+extern int __collector_ext_clone_pthread (int (*fn)(void *), void *child_stack, int flags, void *arg,
+ va_list va /* pid_t *ptid, struct user_desc *tlspid_t *" ctid" */);
+
+/* D-light related functions */
+extern int __collector_sigprof_install ();
+extern int __collector_ext_hwc_active ();
+extern void __collector_ext_hwc_check (siginfo_t *, ucontext_t *);
+extern int __collector_ext_hwc_lwp_init ();
+extern void __collector_ext_hwc_lwp_fini ();
+extern int __collector_ext_hwc_lwp_suspend ();
+extern int __collector_ext_hwc_lwp_resume ();
+extern int (*__collector_VM_ReadByteInstruction)(unsigned char *);
+extern int (*__collector_omp_stack_trace)(char*, int, hrtime_t, void*);
+extern hrtime_t (*__collector_gethrtime)();
+extern int (*__collector_mpi_stack_trace)(char*, int, hrtime_t);
+extern int __collector_open_experiment (const char *exp, const char *par, sp_origin_t origin);
+extern void __collector_suspend_experiment (char *why);
+extern void __collector_resume_experiment ();
+extern void __collector_clean_state ();
+extern void __collector_close_experiment ();
+extern void __collector_terminate_expt ();
+extern void __collector_terminate_hook ();
+extern void __collector_sample (char *name);
+extern void __collector_pause ();
+extern void __collector_pause_m ();
+extern void __collector_resume ();
+extern int collector_sigemt_sigaction (const struct sigaction*,
+ struct sigaction*);
+extern int collector_sigchld_sigaction (const struct sigaction*,
+ struct sigaction*);
+
+extern int
+__collector_log_write (char *format, ...) __attribute__ ((format (printf, 1, 2)));
+
+/* ------- internal global data ----------------- */
+/* These will not be exported from libcollector.so */
+extern struct Heap *__collector_heap;
+
+/* experiment state flag */
+typedef enum
+{
+ EXP_INIT, EXP_OPEN, EXP_PAUSED, EXP_CLOSED
+} sp_state_t;
+extern volatile sp_state_t __collector_expstate;
+
+/* global flag, defines whether target is threaded or not
+ * if set, put _lwp_self() for thread id instead of thr_self()
+ * in output packets; should be set before any data packets
+ * are written, i.e., before signal handlers are installed.
+ */
+extern int __collector_no_threads;
+extern int __collector_libthread_T1; /* T1 or not T1 */
+extern int __collector_sample_sig; /* set to signal used to trigger a sample */
+extern int __collector_sample_sig_warn; /* if 1, warning given on target use */
+extern int __collector_pause_sig; /* set to signal used to toggle pause-resume */
+extern int __collector_pause_sig_warn; /* if 1, warning given on target use */
+extern hrtime_t __collector_delay_start;
+extern int __collector_exp_active;
+
+/* global hrtime_t for next periodic sample */
+extern hrtime_t __collector_next_sample;
+extern int __collector_sample_period;
+
+/* global hrtime_t for experiment termination (-t) */
+extern hrtime_t __collector_terminate_time;
+extern int __collector_terminate_duration;
+extern char __collector_exp_dir_name[];
+extern int __collector_java_mode;
+extern int __collector_java_asyncgetcalltrace_loaded;
+extern int __collector_jprofile_start_attach ();
+
+/* --------- information controlling debug tracing ------------- */
+
+/* global flag, defines level of trace information */
+extern void __collector_dlog (int, int, char *, ...) __attribute__ ((format (printf, 3, 4)));
+
+#define STR(x) ((x) ? (x) : "NULL")
+
+// To set collector_debug_opt use:
+// SP_COLLECTOR_DEBUG=4 ; export SP_COLLECTOR_DEBUG ; collect ...
+enum
+{
+ SP_DUMP_TIME = 1,
+ SP_DUMP_FLAG = 2,
+ SP_DUMP_JAVA = 4,
+ SP_DUMP_NOHEADER = 8,
+ SP_DUMP_UNWIND = 16,
+ SP_DUMP_STACK = 32,
+};
+
+#ifndef DEBUG
+#define DprintfT(flag, ...)
+#define tprintf(...)
+#define Tprintf(...)
+#define TprintfT(...)
+
+#else
+#define DprintfT(flag, ...) __collector_dlog(SP_DUMP_FLAG | (flag), 0, __VA_ARGS__ )
+#define tprintf(...) __collector_dlog( SP_DUMP_NOHEADER, __VA_ARGS__ )
+#define Tprintf(...) __collector_dlog( 0, __VA_ARGS__ )
+#define TprintfT(...) __collector_dlog( SP_DUMP_TIME, __VA_ARGS__ )
+
+#endif /* DEBUG */
+
+// To find the glibc version:
+// objdump -T /lib*/*so /lib*/*/*.so | grep popen
+// IMPORTANT: The GLIBC_* versions below must match those in mapfile.<variant>
+ #if ARCH(Aarch64)
+ #define SYS_LIBC_NAME "libc.so.6"
+ #define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.17"
+ #define SYS_DLOPEN_VERSION "GLIBC_2.17"
+ #define SYS_POPEN_VERSION "GLIBC_2.17"
+ #define SYS_FOPEN_X_VERSION "GLIBC_2.17"
+ #define SYS_FGETPOS_X_VERSION "GLIBC_2.17"
+
+#elif ARCH(Intel)
+ #define SYS_LIBC_NAME "libc.so.6"
+ #define SYS_POSIX_SPAWN_VERSION "GLIBC_2.15"
+ #if WSIZE(32)
+ #define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.1"
+ #define SYS_DLOPEN_VERSION "GLIBC_2.1"
+ #define SYS_POPEN_VERSION "GLIBC_2.1"
+ #define SYS_TIMER_X_VERSION "GLIBC_2.2"
+ #define SYS_FOPEN_X_VERSION "GLIBC_2.1"
+ #define SYS_FGETPOS_X_VERSION "GLIBC_2.2"
+ #define SYS_FGETPOS64_X_VERSION "GLIBC_2.2"
+ #define SYS_OPEN64_X_VERSION "GLIBC_2.2"
+ #define SYS_PREAD_X_VERSION "GLIBC_2.2"
+ #define SYS_PWRITE_X_VERSION "GLIBC_2.2"
+ #define SYS_PWRITE64_X_VERSION "GLIBC_2.2"
+ #else /* WSIZE(64) */
+ #define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.2.5"
+ #define SYS_DLOPEN_VERSION "GLIBC_2.2.5"
+ #define SYS_POPEN_VERSION "GLIBC_2.2.5"
+ #define SYS_TIMER_X_VERSION "GLIBC_2.3.3"
+ #define SYS_FOPEN_X_VERSION "GLIBC_2.2.5"
+ #define SYS_FGETPOS_X_VERSION "GLIBC_2.2.5"
+ #endif
+
+ #elif ARCH(SPARC)
+ #define SYS_LIBC_NAME "libc.so.6"
+ #define SYS_DLOPEN_VERSION "GLIBC_2.1"
+ #if WSIZE(32)
+ #define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.1"
+ #define SYS_POPEN_VERSION "GLIBC_2.1"
+ #define SYS_FOPEN_X_VERSION "GLIBC_2.1"
+ #define SYS_FGETPOS_X_VERSION "GLIBC_2.2"
+ #else /* WSIZE(64) */
+ #define SYS_PTHREAD_CREATE_VERSION "GLIBC_2.2"
+ #define SYS_POPEN_VERSION "GLIBC_2.2"
+ #define SYS_TIMER_X_VERSION "GLIBC_2.3.3"
+ #define SYS_FOPEN_X_VERSION "GLIBC_2.2"
+ #define SYS_FGETPOS_X_VERSION "GLIBC_2.2"
+ #endif
+ #endif
+
+#endif
diff --git a/gprofng/libcollector/collectorAPI.c b/gprofng/libcollector/collectorAPI.c
new file mode 100644
index 0000000..8c9b920
--- /dev/null
+++ b/gprofng/libcollector/collectorAPI.c
@@ -0,0 +1,140 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/* C and Fortran stubs for collector API */
+
+#include "config.h"
+#include <dlfcn.h>
+#include "gp-defs.h"
+#include "collectorAPI.h"
+#include "gp-experiment.h"
+
+static void *__real_collector_sample = NULL;
+static void *__real_collector_pause = NULL;
+static void *__real_collector_resume = NULL;
+static void *__real_collector_terminate_expt = NULL;
+static void *__real_collector_func_load = NULL;
+static void *__real_collector_func_unload = NULL;
+
+#define INIT_API if (init_API == 0) collectorAPI_initAPI()
+#define NULL_PTR(x) (__real_##x == NULL)
+#define CALL_REAL(x) (*(void(*)())__real_##x)
+#define CALL_IF_REAL(x) INIT_API; if (!NULL_PTR(x)) CALL_REAL(x)
+
+static int init_API = 0;
+
+void
+collectorAPI_initAPI (void)
+{
+ void *libcollector = dlopen (SP_LIBCOLLECTOR_NAME, RTLD_NOLOAD);
+ if (libcollector == NULL)
+ libcollector = RTLD_DEFAULT;
+ __real_collector_sample = dlsym (libcollector, "__collector_sample");
+ __real_collector_pause = dlsym (libcollector, "__collector_pause");
+ __real_collector_resume = dlsym (libcollector, "__collector_resume");
+ __real_collector_terminate_expt = dlsym (libcollector, "__collector_terminate_expt");
+ __real_collector_func_load = dlsym (libcollector, "__collector_func_load");
+ __real_collector_func_unload = dlsym (libcollector, "__collector_func_unload");
+ init_API = 1;
+}
+
+/* initialization -- init section routine */
+static void collectorAPI_init () __attribute__ ((constructor));
+
+static void
+collectorAPI_init (void)
+{
+ collectorAPI_initAPI ();
+}
+
+/* C API */
+void
+collector_pause (void)
+{
+ CALL_IF_REAL (collector_pause)();
+}
+
+void
+collector_resume (void)
+{
+ CALL_IF_REAL (collector_resume)();
+}
+
+void
+collector_sample (const char *name)
+{
+ CALL_IF_REAL (collector_sample)(name);
+}
+
+void
+collector_terminate_expt (void)
+{
+ CALL_IF_REAL (collector_terminate_expt)();
+}
+
+void
+collector_func_load (const char *name, const char *alias, const char *sourcename,
+ void *vaddr, int size, int lntsize, Lineno *lntable)
+{
+ CALL_IF_REAL (collector_func_load)(name, alias, sourcename,
+ vaddr, size, lntsize, lntable);
+}
+
+void
+collector_func_unload (void *vaddr)
+{
+ CALL_IF_REAL (collector_func_unload)(vaddr);
+}
+
+/* Fortran API */
+void
+collector_pause_ (void)
+{
+ CALL_IF_REAL (collector_pause)();
+}
+
+void
+collector_resume_ (void)
+{
+ CALL_IF_REAL (collector_resume)();
+}
+
+void
+collector_terminate_expt_ (void)
+{
+ CALL_IF_REAL (collector_terminate_expt)();
+}
+
+void
+collector_sample_ (char *name, long name_length)
+{
+ INIT_API;
+ if (!NULL_PTR (collector_sample))
+ {
+ char name_string[256];
+ long length = sizeof (name_string) - 1;
+ if (name_length < length)
+ length = name_length;
+ for (long i = 0; i < length; i++)
+ name_string[i] = name[i];
+ name_string[length] = '\0';
+ CALL_REAL (collector_sample)(name_string);
+ }
+}
diff --git a/gprofng/libcollector/configure b/gprofng/libcollector/configure
new file mode 100755
index 0000000..ed23350
--- /dev/null
+++ b/gprofng/libcollector/configure
@@ -0,0 +1,18081 @@
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for gprofng 2.38.50.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1
+
+ test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='gprofng'
+PACKAGE_TARNAME='gprofng'
+PACKAGE_VERSION='2.38.50'
+PACKAGE_STRING='gprofng 2.38.50'
+PACKAGE_BUGREPORT=''
+PACKAGE_URL=''
+
+ac_unique_file="libcol_util.c"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+GPROFNG_VARIANT
+CXXCPP
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+OBJDUMP
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+SED
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+LIBTOOL
+ac_ct_AR
+AR
+RANLIB
+am__fastdepCXX_FALSE
+am__fastdepCXX_TRUE
+CXXDEPMODE
+ac_ct_CXX
+CXXFLAGS
+CXX
+EGREP
+GREP
+CPP
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+MAINT
+MAINTAINER_MODE_FALSE
+MAINTAINER_MODE_TRUE
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_maintainer_mode
+enable_dependency_tracking
+enable_shared
+enable_static
+with_pic
+enable_fast_install
+with_gnu_ld
+enable_libtool_lock
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+CPP
+CXX
+CXXFLAGS
+CCC
+CXXCPP'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures gprofng 2.38.50 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/gprofng]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of gprofng 2.38.50:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-silent-rules less verbose build output (undo: "make V=1")
+ --disable-silent-rules verbose build output (undo: "make V=0")
+ --enable-maintainer-mode
+ enable make rules and dependencies not useful (and
+ sometimes confusing) to the casual installer
+ --enable-dependency-tracking
+ do not reject slow dependency extractors
+ --disable-dependency-tracking
+ speeds up one-time build
+ --enable-shared[=PKGS] build shared libraries [default=yes]
+ --enable-static[=PKGS] build static libraries [default=yes]
+ --enable-fast-install[=PKGS]
+ optimize for fast installation [default=yes]
+ --disable-libtool-lock avoid locking (might break parallel builds)
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-pic try to use only PIC/non-PIC objects [default=use
+ both]
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ CPP C preprocessor
+ CXX C++ compiler command
+ CXXFLAGS C++ compiler flags
+ CXXCPP C++ preprocessor
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+gprofng configure 2.38.50
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_cpp
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_mongrel
+
+# ac_fn_c_try_run LINENO
+# ----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_c_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_run
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_cxx_try_cpp LINENO
+# ------------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_cpp
+
+# ac_fn_cxx_try_link LINENO
+# -------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_link
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by gprofng $as_me 2.38.50, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+ac_aux_dir=
+for ac_dir in ../.. "$srcdir"/../..; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in ../.. \"$srcdir\"/../.." "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+am__api_version='1.15'
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
+ done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[\\\"\#\$\&\'\`$am_lf]*)
+ as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
+ as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ as_fn_error $? "ls -t appears to fail. Make sure there is not a broken
+ alias in your environment" "$LINENO" 5
+ fi
+ if test "$2" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+ program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+ if ${ac_cv_path_mkdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in mkdir gmkdir; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+ 'mkdir (GNU coreutils) '* | \
+ 'mkdir (coreutils) '* | \
+ 'mkdir (fileutils) '4.1*)
+ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ break 3;;
+ esac
+ done
+ done
+ done
+IFS=$as_save_IFS
+
+fi
+
+ test -d ./--version && rmdir ./--version
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ MKDIR_P="$ac_cv_path_mkdir -p"
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for MKDIR_P within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ MKDIR_P="$ac_install_sh -d"
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+ enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ am__isrc=' -I$(srcdir)'
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='gprofng'
+ VERSION='2.38.50'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+mkdir_p='$(MKDIR_P)'
+
+# We need awk for the "check" target (and possibly the TAP driver). The
+# system "awk" is bad on some platforms.
+# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar pax cpio none'
+
+am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
+
+
+
+
+
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes. So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+ cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present. This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message. This
+can help us improve future automake versions.
+
+END
+ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+ echo 'Configuration will proceed anyway, since you have set the' >&2
+ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+ echo >&2
+ else
+ cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+ as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
+ fi
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5
+$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; }
+ # Check whether --enable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then :
+ enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
+else
+ USE_MAINTAINER_MODE=no
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5
+$as_echo "$USE_MAINTAINER_MODE" >&6; }
+ if test $USE_MAINTAINER_MODE = yes; then
+ MAINTAINER_MODE_TRUE=
+ MAINTAINER_MODE_FALSE='#'
+else
+ MAINTAINER_MODE_TRUE='#'
+ MAINTAINER_MODE_FALSE=
+fi
+
+ MAINT=$MAINTAINER_MODE_TRUE
+
+
+
+
+
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+ ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+ if ${ac_cv_prog_CPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CPP needs to be expanded
+ for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CPP=$CPP
+
+fi
+ CPP=$ac_cv_prog_CPP
+else
+ ac_cv_prog_CPP=$CPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+ ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
+if test "x$ac_cv_header_minix_config_h" = xyes; then :
+ MINIX=yes
+else
+ MINIX=
+fi
+
+
+ if test "$MINIX" = yes; then
+
+$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h
+
+
+$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h
+
+
+$as_echo "#define _MINIX 1" >>confdefs.h
+
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
+$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
+if ${ac_cv_safe_to_define___extensions__+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+# define __EXTENSIONS__ 1
+ $ac_includes_default
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_safe_to_define___extensions__=yes
+else
+ ac_cv_safe_to_define___extensions__=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5
+$as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
+ test $ac_cv_safe_to_define___extensions__ = yes &&
+ $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h
+
+ $as_echo "#define _ALL_SOURCE 1" >>confdefs.h
+
+ $as_echo "#define _GNU_SOURCE 1" >>confdefs.h
+
+ $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
+
+ $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+ ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+ if test -n "$CCC"; then
+ CXX=$CCC
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CXX"; then
+ ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CXX" && break
+ done
+fi
+if test -z "$CXX"; then
+ ac_ct_CXX=$CXX
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CXX"; then
+ ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CXX="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CXX" && break
+done
+
+ if test "x$ac_ct_CXX" = x; then
+ CXX="g++"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CXX=$ac_ct_CXX
+ fi
+fi
+
+ fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if ${ac_cv_cxx_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GXX=yes
+else
+ GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if ${ac_cv_prog_cxx_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+ ac_cxx_werror_flag=yes
+ ac_cv_prog_cxx_g=no
+ CXXFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_prog_cxx_g=yes
+else
+ CXXFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+ CXXFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_prog_cxx_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+ CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+ if test "$GXX" = yes; then
+ CXXFLAGS="-g -O2"
+ else
+ CXXFLAGS="-g"
+ fi
+else
+ if test "$GXX" = yes; then
+ CXXFLAGS="-O2"
+ else
+ CXXFLAGS=
+ fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CXX" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CXX_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CXX_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CXX_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CXX_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; }
+CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
+ am__fastdepCXX_TRUE=
+ am__fastdepCXX_FALSE='#'
+else
+ am__fastdepCXX_TRUE='#'
+ am__fastdepCXX_FALSE=
+fi
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in ar lib "link -lib"
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AR" && break
+ done
+fi
+if test -z "$AR"; then
+ ac_ct_AR=$AR
+ for ac_prog in ar lib "link -lib"
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_AR" && break
+done
+
+ if test "x$ac_ct_AR" = x; then
+ AR="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+fi
+
+: ${AR=ar}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the archiver ($AR) interface" >&5
+$as_echo_n "checking the archiver ($AR) interface... " >&6; }
+if ${am_cv_ar_interface+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ am_cv_ar_interface=ar
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int some_variable = 0;
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ am_ar_try='$AR cru libconftest.a conftest.$ac_objext >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+ (eval $am_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test "$ac_status" -eq 0; then
+ am_cv_ar_interface=ar
+ else
+ am_ar_try='$AR -NOLOGO -OUT:conftest.lib conftest.$ac_objext >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$am_ar_try\""; } >&5
+ (eval $am_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test "$ac_status" -eq 0; then
+ am_cv_ar_interface=lib
+ else
+ am_cv_ar_interface=unknown
+ fi
+ fi
+ rm -f conftest.lib libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_ar_interface" >&5
+$as_echo "$am_cv_ar_interface" >&6; }
+
+case $am_cv_ar_interface in
+ar)
+ ;;
+lib)
+ # Microsoft lib, so override with the ar-lib wrapper script.
+ # FIXME: It is wrong to rewrite AR.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__AR in this case,
+ # and then we could set am__AR="$am_aux_dir/ar-lib \$(AR)" or something
+ # similar.
+ AR="$am_aux_dir/ar-lib $AR"
+ ;;
+unknown)
+ as_fn_error $? "could not determine $AR interface" "$LINENO" 5
+ ;;
+esac
+
+
+case `pwd` in
+ *\ * | *\ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.2.7a'
+macro_revision='1.3134'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`print -r -- -n 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO ""
+}
+
+case "$ECHO" in
+ printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+ print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+ *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+ { ac_script=; unset ac_script;}
+ if test -z "$SED"; then
+ ac_path_SED_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+ # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo '' >> "conftest.nl"
+ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_SED_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_SED="$ac_path_SED"
+ ac_path_SED_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_SED_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_SED"; then
+ as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ fi
+else
+ ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+ rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+ then ac_cv_path_FGREP="$GREP -F"
+ else
+ if test -z "$FGREP"; then
+ ac_path_FGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in fgrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_FGREP" || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+ # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'FGREP' >> "conftest.nl"
+ "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_FGREP="$ac_path_FGREP"
+ ac_path_FGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_FGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_FGREP"; then
+ as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_FGREP=$FGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NM"; then
+ # Let the user override the nm to test.
+ lt_nm_to_check="$NM"
+ else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ case "$lt_tmp_nm" in
+ */*|*\\*) tmp_nm="$lt_tmp_nm";;
+ *) tmp_nm="$ac_dir/$lt_tmp_nm";;
+ esac
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ case `"$tmp_nm" -B "$tmp_nm" 2>&1 | grep -v '^ *$' | sed '1q'` in
+ *$tmp_nm*) lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p "$tmp_nm" 2>&1 | grep -v '^ *$' | sed '1q'` in
+ *$tmp_nm*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in dumpbin "link -dump"
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DUMPBIN"; then
+ ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$DUMPBIN" && break
+ done
+fi
+if test -z "$DUMPBIN"; then
+ ac_ct_DUMPBIN=$DUMPBIN
+ for ac_prog in dumpbin "link -dump"
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DUMPBIN"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_DUMPBIN" && break
+done
+
+ if test "x$ac_ct_DUMPBIN" = x; then
+ DUMPBIN=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DUMPBIN=$ac_ct_DUMPBIN
+ fi
+fi
+
+ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+ cat conftest.out >&5
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if ${lt_cv_sys_max_cmd_len+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if ${lt_cv_ld_reload_flag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJDUMP"; then
+ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+ ac_ct_OBJDUMP=$OBJDUMP
+ # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJDUMP"; then
+ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OBJDUMP="objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJDUMP" = x; then
+ OBJDUMP="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OBJDUMP=$ac_ct_OBJDUMP
+ fi
+else
+ OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if ${lt_cv_deplibs_check_method+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[45]*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[3-9]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+plugin_option=
+plugin_names="liblto_plugin.so liblto_plugin-0.dll cyglto_plugin-0.dll"
+for plugin in $plugin_names; do
+ plugin_so=`${CC} ${CFLAGS} --print-prog-name $plugin`
+ if test x$plugin_so = x$plugin; then
+ plugin_so=`${CC} ${CFLAGS} --print-file-name $plugin`
+ fi
+ if test x$plugin_so != x$plugin; then
+ plugin_option="--plugin $plugin_so"
+ break
+ fi
+done
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_AR"; then
+ ac_ct_AR=$AR
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="ar"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_AR" = x; then
+ AR="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+else
+ AR="$ac_cv_prog_AR"
+fi
+
+test -z "$AR" && AR=ar
+if test -n "$plugin_option"; then
+ if $AR --help 2>&1 | grep -q "\--plugin"; then
+ touch conftest.c
+ $AR $plugin_option rc conftest.a conftest.c
+ if test "$?" != 0; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Failed: $AR $plugin_option rc" >&5
+$as_echo "$as_me: WARNING: Failed: $AR $plugin_option rc" >&2;}
+ else
+ AR="$AR $plugin_option"
+ fi
+ rm -f conftest.*
+ fi
+fi
+test -z "$AR_FLAGS" && AR_FLAGS=cru
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+if test -n "$plugin_option" && test "$RANLIB" != ":"; then
+ if $RANLIB --help 2>&1 | grep -q "\--plugin"; then
+ RANLIB="$RANLIB $plugin_option"
+ fi
+fi
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if ${lt_cv_sys_global_symbol_pipe+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDEGRST]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[BCDEGRST]'
+ ;;
+osf*)
+ symcode='[BCDEGQRST]'
+ ;;
+solaris*)
+ symcode='[BCDRT]'
+ ;;
+sco3.2v5*)
+ symcode='[DT]'
+ ;;
+sysv4.2uw2*)
+ symcode='[DT]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[ABDT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK '"\
+" {last_section=section; section=\$ 3};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+ (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+const struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_save_LIBS="$LIBS"
+ lt_save_CFLAGS="$CFLAGS"
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS="$lt_save_LIBS"
+ CFLAGS="$lt_save_CFLAGS"
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+ enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ case `/usr/bin/file conftest.o` in
+ *x86-64*)
+ LD="${LD-ld} -m elf32_x86_64"
+ ;;
+ *)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ esac
+ ;;
+ powerpc64le-*linux*)
+ LD="${LD-ld} -m elf32lppclinux"
+ ;;
+ powerpc64-*linux*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ powerpcle-*linux*)
+ LD="${LD-ld} -m elf64lppc"
+ ;;
+ powerpc-*linux*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if ${lt_cv_cc_needs_belf+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_cc_needs_belf=yes
+else
+ lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+sparc*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*) LD="${LD-ld} -m elf64_sparc" ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+
+ case $host_os in
+ rhapsody* | darwin*)
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DSYMUTIL"; then
+ ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+ ac_ct_DSYMUTIL=$DSYMUTIL
+ # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DSYMUTIL"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DSYMUTIL" = x; then
+ DSYMUTIL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DSYMUTIL=$ac_ct_DSYMUTIL
+ fi
+else
+ DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NMEDIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NMEDIT"; then
+ ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+ ac_ct_NMEDIT=$NMEDIT
+ # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_NMEDIT"; then
+ ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_NMEDIT="nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_NMEDIT" = x; then
+ NMEDIT=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ NMEDIT=$ac_ct_NMEDIT
+ fi
+else
+ NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LIPO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$LIPO"; then
+ ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+ ac_ct_LIPO=$LIPO
+ # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_LIPO"; then
+ ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_LIPO="lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_LIPO" = x; then
+ LIPO=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ LIPO=$ac_ct_LIPO
+ fi
+else
+ LIPO="$ac_cv_prog_LIPO"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL"; then
+ ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+ ac_ct_OTOOL=$OTOOL
+ # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL"; then
+ ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OTOOL="otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL" = x; then
+ OTOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL=$ac_ct_OTOOL
+ fi
+else
+ OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL64"; then
+ ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+ ac_ct_OTOOL64=$OTOOL64
+ # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL64"; then
+ ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OTOOL64="otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL64" = x; then
+ OTOOL64=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL64=$ac_ct_OTOOL64
+ fi
+else
+ OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_ld_exported_symbols_list=yes
+else
+ lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+ echo "$AR cru libconftest.a conftest.o" >&5
+ $AR cru libconftest.a conftest.o 2>&5
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[012][,.]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+
+for ac_header in dlfcn.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+
+# Set options
+
+
+
+ enable_dlopen=no
+
+
+ enable_win32_dll=no
+
+
+ # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+ enableval=$enable_shared; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+ # Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+ enableval=$enable_static; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_static=yes
+fi
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+ withval=$with_pic; pic_mode="$withval"
+else
+ pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+ # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+ enableval=$enable_fast_install; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if ${lt_cv_objdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/${ac_tool_prefix}file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ else
+ MAGIC_CMD=:
+ fi
+fi
+
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+ case $cc_basename in
+ nvcc*)
+ lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+ *)
+ lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+
+
+
+
+
+ lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ lt_prog_compiler_static=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ lt_prog_compiler_wl='-Xlinker '
+ lt_prog_compiler_pic='-Xcompiler -fPIC'
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ else
+ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='--shared'
+ lt_prog_compiler_static='--static'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-qpic'
+ lt_prog_compiler_static='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ F* | *Sun*Fortran*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl=''
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ rdos*)
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95*)
+ lt_prog_compiler_wl='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl='-Qoption ld '
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic='-Kconform_pic'
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_can_build_shared=no
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic='-pic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic=
+ ;;
+ *)
+ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5
+$as_echo "$lt_prog_compiler_pic" >&6; }
+
+
+
+
+
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_works=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_pic_works=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+ case $lt_prog_compiler_pic in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+ esac
+else
+ lt_prog_compiler_pic=
+ lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_static_works=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ else
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+ if test "$hard_links" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+ runpath_var=
+ allow_undefined_flag=
+ always_export_symbols=no
+ archive_cmds=
+ archive_expsym_cmds=
+ compiler_needs_object=no
+ enable_shared_with_static_runtimes=no
+ export_dynamic_flag_spec=
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ hardcode_automatic=no
+ hardcode_direct=no
+ hardcode_direct_absolute=no
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_flag_spec_ld=
+ hardcode_libdir_separator=
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=unsupported
+ inherit_rpath=no
+ link_all_deplibs=unknown
+ module_cmds=
+ module_expsym_cmds=
+ old_archive_from_new_cmds=
+ old_archive_from_expsyms_cmds=
+ thread_safe_flag_spec=
+ whole_archive_flag_spec=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ esac
+
+ ld_shlibs=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test "$with_gnu_ld" = yes; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+ *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test "$lt_use_gnu_ld_interface" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[3-9]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ export_dynamic_flag_spec='${wl}--export-all-symbols'
+ allow_undefined_flag=unsupported
+ always_export_symbols=no
+ enable_shared_with_static_runtimes=yes
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ haiku*)
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ link_all_deplibs=yes
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=' $pic_flag'
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ whole_archive_flag_spec=
+ tmp_sharedflag='--shared' ;;
+ xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_flag_spec_ld='-rpath $libdir'
+ archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global
+ # defined symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ file_list_spec='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ export_dynamic_flag_spec='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag=' ${wl}-bernotok'
+ allow_undefined_flag=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec='$convenience'
+ fi
+ archive_cmds_need_lc=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ fix_srcfile_path='`cygpath -w "$srcfile"`'
+ enable_shared_with_static_runtimes=yes
+ ;;
+
+ darwin* | rhapsody*)
+
+
+ archive_cmds_need_lc=no
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ else
+ whole_archive_flag_spec=''
+ fi
+ link_all_deplibs=yes
+ allow_undefined_flag="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+ else
+ ld_shlibs=no
+ fi
+
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2.*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ export_dynamic_flag_spec='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_flag_spec_ld='+b $libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if ${lt_cv_prog_compiler__b+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler__b=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -b"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler__b=yes
+ fi
+ else
+ lt_cv_prog_compiler__b=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ ;;
+ *)
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foo(void) {}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ inherit_rpath=yes
+ link_all_deplibs=yes
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ hardcode_direct_absolute=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_separator=:
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds='$CC -r -o $output$reload_objs'
+ hardcode_direct=no
+ ;;
+ motorola)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag='${wl}-z,text'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag='${wl}-z,text'
+ allow_undefined_flag='${wl}-z,nodefs'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-R,$libdir'
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ export_dynamic_flag_spec='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl
+ pic_flag=$lt_prog_compiler_pic
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+ (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ then
+ lt_cv_archive_cmds_need_lc=no
+ else
+ lt_cv_archive_cmds_need_lc=yes
+ fi
+ allow_undefined_flag=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+ archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+ *) lt_sed_strip_eq="s,=/,/,g" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[lt_foo]++; }
+ if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[23].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+haiku*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[3-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+ lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+fi
+
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+ test -n "$runpath_var" ||
+ test "X$hardcode_automatic" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+ test "$hardcode_minus_L" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+ test "$inherit_rpath" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+ if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = xyes; then :
+ lt_cv_dlopen="shl_load"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if ${ac_cv_lib_dld_shl_load+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_shl_load=yes
+else
+ ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+ ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if ${ac_cv_lib_svld_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_svld_dlopen=yes
+else
+ ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if ${ac_cv_lib_dld_dld_link+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_dld_link=yes
+else
+ ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line 12016 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self_static+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line 12122 "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+void fnord () __attribute__((visibility("default")));
+#endif
+
+void fnord () { int i=42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+ # Report which library types will actually be built
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+CC="$lt_save_CC"
+
+ if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
+$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+if test -z "$CXXCPP"; then
+ if ${ac_cv_prog_CXXCPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CXXCPP needs to be expanded
+ for CXXCPP in "$CXX -E" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+ CXXCPP=$ac_cv_prog_CXXCPP
+else
+ ac_cv_prog_CXXCPP=$CXXCPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
+$as_echo "$CXXCPP" >&6; }
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+else
+ _lt_caught_CXX_error=yes
+fi
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+archive_cmds_need_lc_CXX=no
+allow_undefined_flag_CXX=
+always_export_symbols_CXX=no
+archive_expsym_cmds_CXX=
+compiler_needs_object_CXX=no
+export_dynamic_flag_spec_CXX=
+hardcode_direct_CXX=no
+hardcode_direct_absolute_CXX=no
+hardcode_libdir_flag_spec_CXX=
+hardcode_libdir_flag_spec_ld_CXX=
+hardcode_libdir_separator_CXX=
+hardcode_minus_L_CXX=no
+hardcode_shlibpath_var_CXX=unsupported
+hardcode_automatic_CXX=no
+inherit_rpath_CXX=no
+module_cmds_CXX=
+module_expsym_cmds_CXX=
+link_all_deplibs_CXX=unknown
+old_archive_cmds_CXX=$old_archive_cmds
+reload_flag_CXX=$reload_flag
+reload_cmds_CXX=$reload_cmds
+no_undefined_flag_CXX=
+whole_archive_flag_spec_CXX=
+enable_shared_with_static_runtimes_CXX=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+objext_CXX=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="int some_variable = 0;"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code='int main(int, char *[]) { return(0); }'
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+ # save warnings/boilerplate of simple test code
+ ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_LD=$LD
+ lt_save_GCC=$GCC
+ GCC=$GXX
+ lt_save_with_gnu_ld=$with_gnu_ld
+ lt_save_path_LD=$lt_cv_path_LD
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+ $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+ $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+ compiler=$CC
+ compiler_CXX=$CC
+ for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+ if test -n "$compiler"; then
+ # We don't want -fno-exception when compiling C++ code, so set the
+ # no_builtin_flag separately
+ if test "$GXX" = yes; then
+ lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
+ else
+ lt_prog_compiler_no_builtin_flag_CXX=
+ fi
+
+ if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+ $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec_CXX=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+ fi
+
+ # PORTME: fill in a description of your system's C++ link characteristics
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+ ld_shlibs_CXX=yes
+ case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds_CXX=''
+ hardcode_direct_CXX=yes
+ hardcode_direct_absolute_CXX=yes
+ hardcode_libdir_separator_CXX=':'
+ link_all_deplibs_CXX=yes
+ file_list_spec_CXX='${wl}-f,'
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct_CXX=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L_CXX=yes
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ hardcode_libdir_separator_CXX=
+ fi
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ export_dynamic_flag_spec_CXX='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to
+ # export.
+ always_export_symbols_CXX=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag_CXX='-berok'
+ # Determine the default libpath from the value encoded in an empty
+ # executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag_CXX="-z nodefs"
+ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\(.*\)$/\1/
+ p
+ }
+ }'
+aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+# Check for a 64-bit object if we didn't find anything.
+if test -z "$aix_libpath"; then
+ aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag_CXX=' ${wl}-bernotok'
+ allow_undefined_flag_CXX=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec_CXX='$convenience'
+ fi
+ archive_cmds_need_lc_CXX=yes
+ # This is similar to how AIX traditionally builds its shared
+ # libraries.
+ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag_CXX=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs_CXX=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-all-symbols'
+ allow_undefined_flag_CXX=unsupported
+ always_export_symbols_CXX=no
+ enable_shared_with_static_runtimes_CXX=yes
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ darwin* | rhapsody*)
+
+
+ archive_cmds_need_lc_CXX=no
+ hardcode_direct_CXX=no
+ hardcode_automatic_CXX=yes
+ hardcode_shlibpath_var_CXX=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ else
+ whole_archive_flag_spec_CXX=''
+ fi
+ link_all_deplibs_CXX=yes
+ allow_undefined_flag_CXX="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+ fi
+
+ else
+ ld_shlibs_CXX=no
+ fi
+
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ freebsd2.*)
+ # C++ shared libraries reported to be fairly broken before
+ # switch to ELF
+ ld_shlibs_CXX=no
+ ;;
+
+ freebsd-elf*)
+ archive_cmds_need_lc_CXX=no
+ ;;
+
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ ld_shlibs_CXX=yes
+ ;;
+
+ gnu*)
+ ;;
+
+ haiku*)
+ archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ link_all_deplibs_CXX=yes
+ ;;
+
+ hpux9*)
+ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ hardcode_direct_CXX=yes
+ hardcode_minus_L_CXX=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aCC*)
+ archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ ;;
+ *)
+ hardcode_direct_CXX=yes
+ hardcode_direct_absolute_CXX=yes
+ hardcode_minus_L_CXX=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+ fi
+ fi
+ link_all_deplibs_CXX=yes
+ ;;
+ esac
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+ inherit_rpath_CXX=yes
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc* | ecpc* )
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ archive_cmds_need_lc_CXX=no
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ case `$CC -V` in
+ *pgCC\ [1-5].* | *pgcpp\ [1-5].*)
+ prelink_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | $NL2SP`"'
+ old_archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | $NL2SP`~
+ $RANLIB $oldlib'
+ archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ esac
+
+ hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ ;;
+ xl* | mpixl* | bgxl*)
+ # IBM XL 8.0 on PPC, with GNU ld
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ no_undefined_flag_CXX=' -zdefs'
+ archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ hardcode_libdir_flag_spec_CXX='-R$libdir'
+ whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object_CXX=yes
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+
+ m88k*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ hardcode_libdir_flag_spec_CXX='-R$libdir'
+ hardcode_direct_CXX=yes
+ hardcode_shlibpath_var_CXX=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+
+ *nto* | *qnx*)
+ ld_shlibs_CXX=yes
+ ;;
+
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ ld_shlibs_CXX=no
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct_CXX=yes
+ hardcode_shlibpath_var_CXX=no
+ hardcode_direct_absolute_CXX=yes
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd=func_echo_all
+ else
+ ld_shlibs_CXX=no
+ fi
+ ;;
+
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ case $host in
+ osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;;
+ *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;;
+ esac
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ cxx*)
+ case $host in
+ osf3*)
+ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ ;;
+ *)
+ allow_undefined_flag_CXX=' -expect_unresolved \*'
+ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+ $RM $lib.exp'
+ hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+ ;;
+ esac
+
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+ case $host in
+ osf3*)
+ archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ esac
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+
+ psos*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ archive_cmds_need_lc_CXX=yes
+ no_undefined_flag_CXX=' -zdefs'
+ archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ hardcode_libdir_flag_spec_CXX='-R$libdir'
+ hardcode_shlibpath_var_CXX=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ link_all_deplibs_CXX=yes
+
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ no_undefined_flag_CXX=' ${wl}-z ${wl}defs'
+ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+ archive_cmds_CXX='$CC -shared -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir'
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag_CXX='${wl}-z,text'
+ archive_cmds_need_lc_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag_CXX='${wl}-z,text'
+ allow_undefined_flag_CXX='${wl}-z,nodefs'
+ archive_cmds_need_lc_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir'
+ hardcode_libdir_separator_CXX=':'
+ link_all_deplibs_CXX=yes
+ export_dynamic_flag_spec_CXX='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~
+ '"$old_archive_cmds_CXX"
+ reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~
+ '"$reload_cmds_CXX"
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+ test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+ GCC_CXX="$GXX"
+ LD_CXX="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ # Dependencies to place before and after the object being linked:
+predep_objects_CXX=
+postdep_objects_CXX=
+predeps_CXX=
+postdeps_CXX=
+compiler_lib_search_path_CXX=
+
+cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+_LT_EOF
+
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval "$output_verbose_link_cmd"`; do
+ case $p in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" ||
+ test $p = "-R"; then
+ prev=$p
+ continue
+ else
+ prev=
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ case $p in
+ -L* | -R*)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$compiler_lib_search_path_CXX"; then
+ compiler_lib_search_path_CXX="${prev}${p}"
+ else
+ compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$postdeps_CXX"; then
+ postdeps_CXX="${prev}${p}"
+ else
+ postdeps_CXX="${postdeps_CXX} ${prev}${p}"
+ fi
+ fi
+ ;;
+
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$predep_objects_CXX"; then
+ predep_objects_CXX="$p"
+ else
+ predep_objects_CXX="$predep_objects_CXX $p"
+ fi
+ else
+ if test -z "$postdep_objects_CXX"; then
+ postdep_objects_CXX="$p"
+ else
+ postdep_objects_CXX="$postdep_objects_CXX $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling CXX test program"
+fi
+
+$RM -f confest.$objext
+
+# PORTME: override above test on systems where it is broken
+case $host_os in
+interix[3-9]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ predep_objects_CXX=
+ postdep_objects_CXX=
+ postdeps_CXX=
+ ;;
+
+linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ if test "$solaris_use_stlport4" != yes; then
+ postdeps_CXX='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+solaris*)
+ case $cc_basename in
+ CC*)
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ # Adding this requires a known-good setup of shared libraries for
+ # Sun compiler versions before 5.6, else PIC objects from an old
+ # archive will be linked into the output, leading to subtle bugs.
+ if test "$solaris_use_stlport4" != yes; then
+ postdeps_CXX='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+esac
+
+
+case " $postdeps_CXX " in
+*" -lc "*) archive_cmds_need_lc_CXX=no ;;
+esac
+ compiler_lib_search_dirs_CXX=
+if test -n "${compiler_lib_search_path_CXX}"; then
+ compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ lt_prog_compiler_wl_CXX=
+lt_prog_compiler_pic_CXX=
+lt_prog_compiler_static_CXX=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_CXX='-Bstatic'
+ fi
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic_CXX='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ lt_prog_compiler_pic_CXX=
+ ;;
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ lt_prog_compiler_static_CXX=
+ ;;
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic_CXX=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ esac
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic_CXX='-fPIC -shared'
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix[4-9]*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_CXX='-Bstatic'
+ else
+ lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ lt_prog_compiler_pic_CXX='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
+ if test "$host_cpu" != ia64; then
+ lt_prog_compiler_pic_CXX='+Z'
+ fi
+ ;;
+ aCC*)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ lt_prog_compiler_wl_CXX='--backend -Wl,'
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ ecpc* )
+ # old Intel C++ for x86_64 which still supported -KPIC.
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-static'
+ ;;
+ icpc* )
+ # Intel C++, used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-fPIC'
+ lt_prog_compiler_static_CXX='-static'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-fpic'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_static_CXX='-non_shared'
+ ;;
+ xlc* | xlC* | bgxl[cC]* | mpixl[cC]*)
+ # IBM XL 8.0, 9.0 on PPC and BlueGene
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-qpic'
+ lt_prog_compiler_static_CXX='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ lt_prog_compiler_wl_CXX='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ lt_prog_compiler_pic_CXX='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd*)
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic_CXX='-fPIC -shared'
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ lt_prog_compiler_wl_CXX='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ lt_prog_compiler_wl_CXX='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_static_CXX='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ lt_prog_compiler_wl_CXX='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ lt_prog_compiler_pic_CXX='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ lt_prog_compiler_pic_CXX='-pic'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ lt_prog_compiler_pic_CXX='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ lt_prog_compiler_can_build_shared_CXX=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic_CXX=
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC"
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic_CXX" >&5
+$as_echo "$lt_prog_compiler_pic_CXX" >&6; }
+
+
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_CXX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_works_CXX=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_pic_works_CXX=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then
+ case $lt_prog_compiler_pic_CXX in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;;
+ esac
+else
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_can_build_shared_CXX=no
+fi
+
+fi
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_static_works_CXX=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_static_works_CXX=yes
+ fi
+ else
+ lt_cv_prog_compiler_static_works_CXX=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then
+ :
+else
+ lt_prog_compiler_static_CXX=
+fi
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o_CXX=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o_CXX=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o_CXX=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o_CXX=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+ if test "$hard_links" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ case $host_os in
+ aix[4-9]*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global defined
+ # symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ export_symbols_cmds_CXX="$ltdll_cmds"
+ ;;
+ cygwin* | mingw* | cegcc*)
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;/^.*[ ]__nm__/s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ *)
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+ exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+with_gnu_ld_CXX=$with_gnu_ld
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_CXX" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc_CXX=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds_CXX in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl_CXX
+ pic_flag=$lt_prog_compiler_pic_CXX
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag_CXX
+ allow_undefined_flag_CXX=
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+ (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ then
+ lt_cv_archive_cmds_need_lc_CXX=no
+ else
+ lt_cv_archive_cmds_need_lc_CXX=yes
+ fi
+ allow_undefined_flag_CXX=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; }
+ archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$host_os in
+ yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*)
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ ;;
+
+ *)
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[23].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+haiku*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[3-9]*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be Linux ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+ lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+fi
+
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action_CXX=
+if test -n "$hardcode_libdir_flag_spec_CXX" ||
+ test -n "$runpath_var_CXX" ||
+ test "X$hardcode_automatic_CXX" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$hardcode_direct_CXX" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no &&
+ test "$hardcode_minus_L_CXX" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action_CXX=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action_CXX=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action_CXX=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5
+$as_echo "$hardcode_action_CXX" >&6; }
+
+if test "$hardcode_action_CXX" = relink ||
+ test "$inherit_rpath_CXX" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+
+ fi # test -n "$compiler"
+
+ CC=$lt_save_CC
+ LDCXX=$LD
+ LD=$lt_save_LD
+ GCC=$lt_save_GCC
+ with_gnu_ld=$lt_save_with_gnu_ld
+ lt_cv_path_LDCXX=$lt_cv_path_LD
+ lt_cv_path_LD=$lt_save_path_LD
+ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+# Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+ enableval=$enable_shared; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_shared=yes
+fi
+
+
+
+
+
+
+# Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+ enableval=$enable_static; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_static=no
+fi
+
+
+
+
+
+
+
+if test "$enable_shared" != "yes"; then
+ as_fn_error $? "Cannot set --enable-shared for gprofng/libcollector." "$LINENO" 5
+fi
+
+GPROFNG_VARIANT=unknown
+case "${target}" in
+ x86_64-*-linux*)
+ GPROFNG_VARIANT=amd64-Linux
+ ;;
+ i?86-*-linux*)
+ GPROFNG_VARIANT=intel-Linux
+ ;;
+ aarch64-*-linux*)
+ GPROFNG_VARIANT=aarch64-Linux
+ ;;
+esac
+
+
+ac_config_files="$ac_config_files Makefile"
+
+ac_config_headers="$ac_config_headers lib-config.h:../common/config.h.in"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+ if test -n "$EXEEXT"; then
+ am__EXEEXT_TRUE=
+ am__EXEEXT_FALSE='#'
+else
+ am__EXEEXT_TRUE='#'
+ am__EXEEXT_FALSE=
+fi
+
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+ as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by gprofng $as_me 2.38.50, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+gprofng config.status 2.38.50
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`'
+predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`'
+postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`'
+predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`'
+postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`'
+LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`'
+reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`'
+reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`'
+GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_ld_CXX='`$ECHO "$hardcode_libdir_flag_spec_ld_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`'
+inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`'
+fix_srcfile_path_CXX='`$ECHO "$fix_srcfile_path_CXX" | $SED "$delay_single_quote_subst"`'
+always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`'
+predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`'
+postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in SHELL \
+ECHO \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+OBJDUMP \
+deplibs_check_method \
+file_magic_cmd \
+AR \
+AR_FLAGS \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_wl \
+lt_prog_compiler_pic \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_flag_spec_ld \
+hardcode_libdir_separator \
+fix_srcfile_path \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib \
+compiler_lib_search_dirs \
+predep_objects \
+postdep_objects \
+predeps \
+postdeps \
+compiler_lib_search_path \
+LD_CXX \
+reload_flag_CXX \
+compiler_CXX \
+lt_prog_compiler_no_builtin_flag_CXX \
+lt_prog_compiler_wl_CXX \
+lt_prog_compiler_pic_CXX \
+lt_prog_compiler_static_CXX \
+lt_cv_prog_compiler_c_o_CXX \
+export_dynamic_flag_spec_CXX \
+whole_archive_flag_spec_CXX \
+compiler_needs_object_CXX \
+with_gnu_ld_CXX \
+allow_undefined_flag_CXX \
+no_undefined_flag_CXX \
+hardcode_libdir_flag_spec_CXX \
+hardcode_libdir_flag_spec_ld_CXX \
+hardcode_libdir_separator_CXX \
+fix_srcfile_path_CXX \
+exclude_expsyms_CXX \
+include_expsyms_CXX \
+file_list_spec_CXX \
+compiler_lib_search_dirs_CXX \
+predep_objects_CXX \
+postdep_objects_CXX \
+predeps_CXX \
+postdeps_CXX \
+compiler_lib_search_path_CXX; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec \
+reload_cmds_CXX \
+old_archive_cmds_CXX \
+old_archive_from_new_cmds_CXX \
+old_archive_from_expsyms_cmds_CXX \
+archive_cmds_CXX \
+archive_expsym_cmds_CXX \
+module_cmds_CXX \
+module_expsym_cmds_CXX \
+export_symbols_cmds_CXX \
+prelink_cmds_CXX; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'
+
+
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "lib-config.h") CONFIG_HEADERS="$CONFIG_HEADERS lib-config.h:../common/config.h.in" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = ""
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = ""
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named 'Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running 'make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "$am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir=$dirpart/$fdir; as_fn_mkdir_p
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+ ;;
+ "libtool":C)
+
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags="CXX "
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# An object symbol dumper.
+OBJDUMP=$lt_OBJDUMP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method == "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# The archiver.
+AR=$lt_AR
+AR_FLAGS=$lt_AR_FLAGS
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking. This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects
+postdep_objects=$lt_postdep_objects
+predeps=$lt_predeps
+postdeps=$lt_postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ case $xsi_shell in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result="${1##*/}"
+}
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+ func_basename_result="${1##*/}"
+}
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+func_stripname ()
+{
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary parameter first.
+ func_stripname_result=${3}
+ func_stripname_result=${func_stripname_result#"${1}"}
+ func_stripname_result=${func_stripname_result%"${2}"}
+}
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=${1%%=*}
+ func_opt_split_arg=${1#*=}
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ case ${1} in
+ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+ *) func_lo2o_result=${1} ;;
+ esac
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=${1%.*}.lo
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=$(( $* ))
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=${#1}
+}
+
+_LT_EOF
+ ;;
+ *) # Bourne compatible functions.
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+}
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+}
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ esac
+}
+
+# sed scripts:
+my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q'
+my_sed_long_arg='1s/^-[^=]*=//'
+
+# func_opt_split
+func_opt_split ()
+{
+ func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"`
+ func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"`
+}
+
+# func_lo2o object
+func_lo2o ()
+{
+ func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+}
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
+}
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=`expr "$@"`
+}
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len`
+}
+
+_LT_EOF
+esac
+
+case $lt_shell_append in
+ yes)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$1+=\$2"
+}
+_LT_EOF
+ ;;
+ *)
+ cat << \_LT_EOF >> "$cfgfile"
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "$1=\$$1\$2"
+}
+
+_LT_EOF
+ ;;
+ esac
+
+
+ sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+
+ cat <<_LT_EOF >> "$ofile"
+
+# ### BEGIN LIBTOOL TAG CONFIG: CXX
+
+# The linker used to build libraries.
+LD=$lt_LD_CXX
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag_CXX
+reload_cmds=$lt_reload_cmds_CXX
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds_CXX
+
+# A language specific compiler.
+CC=$lt_compiler_CXX
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC_CXX
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_CXX
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_CXX
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_CXX
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_CXX
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object_CXX
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds_CXX
+archive_expsym_cmds=$lt_archive_expsym_cmds_CXX
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds_CXX
+module_expsym_cmds=$lt_module_expsym_cmds_CXX
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld_CXX
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_CXX
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_CXX
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
+
+# If ld is used when linking, flag to hardcode \$libdir into a binary
+# during linking. This must work even if \$libdir does not exist.
+hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld_CXX
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct_CXX
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute_CXX
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L_CXX
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic_CXX
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath_CXX
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_CXX
+
+# Fix the shell variable \$srcfile for the compiler.
+fix_srcfile_path=$lt_fix_srcfile_path_CXX
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols_CXX
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_CXX
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_CXX
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_CXX
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds_CXX
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec_CXX
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_CXX
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects_CXX
+postdep_objects=$lt_postdep_objects_CXX
+predeps=$lt_predeps_CXX
+postdeps=$lt_postdeps_CXX
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
+
+# ### END LIBTOOL TAG CONFIG: CXX
+_LT_EOF
+
+ ;;
+
+ esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
diff --git a/gprofng/libcollector/configure.ac b/gprofng/libcollector/configure.ac
new file mode 100644
index 0000000..8acd66f
--- /dev/null
+++ b/gprofng/libcollector/configure.ac
@@ -0,0 +1,60 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl
+dnl Copyright (C) 2021 Free Software Foundation, Inc.
+dnl
+dnl This file is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 3 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with this program; see the file COPYING3. If not see
+dnl <http://www.gnu.org/licenses/>.
+
+m4_include([../../bfd/version.m4])
+AC_INIT([gprofng], BFD_VERSION)
+AC_CONFIG_MACRO_DIRS([../../config ../..])
+AC_CONFIG_AUX_DIR(../..)
+AM_INIT_AUTOMAKE
+AM_MAINTAINER_MODE
+
+AC_CONFIG_SRCDIR(libcol_util.c)
+
+AC_USE_SYSTEM_EXTENSIONS
+AC_PROG_CC
+AC_PROG_CXX
+AC_PROG_INSTALL
+AC_PROG_RANLIB
+AM_PROG_AR
+
+LT_INIT
+AC_ENABLE_SHARED
+AC_DISABLE_STATIC
+
+if test "$enable_shared" != "yes"; then
+ AC_MSG_ERROR([Cannot set --enable-shared for gprofng/libcollector.])
+fi
+
+GPROFNG_VARIANT=unknown
+case "${target}" in
+ x86_64-*-linux*)
+ GPROFNG_VARIANT=amd64-Linux
+ ;;
+ i?86-*-linux*)
+ GPROFNG_VARIANT=intel-Linux
+ ;;
+ aarch64-*-linux*)
+ GPROFNG_VARIANT=aarch64-Linux
+ ;;
+esac
+AC_SUBST(GPROFNG_VARIANT)
+
+AC_CONFIG_FILES([Makefile])
+AC_CONFIG_HEADERS([lib-config.h:../common/config.h.in])
+AC_OUTPUT
+
diff --git a/gprofng/libcollector/descendants.h b/gprofng/libcollector/descendants.h
new file mode 100644
index 0000000..8fa18c8
--- /dev/null
+++ b/gprofng/libcollector/descendants.h
@@ -0,0 +1,81 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/* Lineage events for process fork, exec, etc. */
+
+#ifndef DESCENDANTS_H
+#define DESCENDANTS_H
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <alloca.h>
+#include <assert.h>
+
+#include "gp-defs.h"
+#include "gp-experiment.h"
+#include "collector.h"
+#include "memmgr.h"
+#include "cc_libcollector.h"
+#include "tsd.h"
+
+/* configuration, not changed after init. */
+typedef enum
+{
+ LM_DORMANT = -2, /* env vars preserved, not recording */
+ LM_CLOSED = -1, /* env vars cleared, not recording */
+ LM_TRACK_LINEAGE = 1, /* env vars preserved, recording */
+} line_mode_t;
+
+extern line_mode_t line_mode;
+extern int user_follow_mode;
+extern int java_mode;
+extern int dbg_current_mode; /* for debug only */
+extern unsigned line_key;
+extern char **sp_env_backup;
+
+#define INIT_REENTRANCE(x) ((x) = __collector_tsd_get_by_key (line_key))
+#define CHCK_REENTRANCE(x) (((INIT_REENTRANCE(x)) == NULL) || (*(x) != 0))
+#define PUSH_REENTRANCE(x) ((*(x))++)
+#define POP_REENTRANCE(x) ((*(x))--)
+
+/* environment variables that must be forwarded to descendents */
+#define SP_COLLECTOR_PARAMS "SP_COLLECTOR_PARAMS"
+#define SP_COLLECTOR_EXPNAME "SP_COLLECTOR_EXPNAME"
+#define SP_COLLECTOR_FOLLOW_SPEC "SP_COLLECTOR_FOLLOW_SPEC"
+#define SP_COLLECTOR_FOUNDER "SP_COLLECTOR_FOUNDER"
+#define SP_PRELOAD_STRINGS "SP_COLLECTOR_PRELOAD"
+#define LD_PRELOAD_STRINGS "LD_PRELOAD"
+#define SP_LIBPATH_STRINGS "SP_COLLECTOR_LIBRARY_PATH"
+#define LD_LIBPATH_STRINGS "LD_LIBRARY_PATH"
+#define JAVA_TOOL_OPTIONS "JAVA_TOOL_OPTIONS"
+#define COLLECTOR_JVMTI_OPTION "-agentlib:gp-collector"
+
+extern int __collector_linetrace_shutdown_hwcs_6830763_XXXX;
+extern void __collector_env_unset (char *envp[]);
+extern void __collector_env_save_preloads ();
+extern char ** __collector_env_backup ();
+extern void __collector_env_backup_free ();
+extern void __collector_env_update (char *envp[]);
+extern void __collector_env_print (char *label);
+extern void __collector_env_printall (char *label, char *envp[]);
+extern char ** __collector_env_allocate (char *const old_env[], int allocate_env);
+
+#endif
diff --git a/gprofng/libcollector/dispatcher.c b/gprofng/libcollector/dispatcher.c
new file mode 100644
index 0000000..f9a7de1
--- /dev/null
+++ b/gprofng/libcollector/dispatcher.c
@@ -0,0 +1,1263 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/*
+ * Central SIGPROF dispatcher to various module event handlers
+ * (REALPROF profile, HWC check, overview sample, manual sample)
+ */
+
+#include "config.h"
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+#include <sys/param.h>
+#include <sys/signal.h>
+#include <sys/syscall.h>
+#include <time.h>
+#include <signal.h>
+
+#include "gp-defs.h"
+#include "gp-experiment.h"
+#include "collector.h"
+#include "collector_module.h"
+#include "tsd.h"
+#include "hwcdrv.h"
+
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LTT 0 // for interposition on GLIBC functions
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+
+static void collector_sigprof_dispatcher (int, siginfo_t*, void*);
+static int init_interposition_intf ();
+#include "memmgr.h"
+static int collector_timer_create (timer_t * ptimerid);
+static int collector_timer_settime (int period, timer_t timerid);
+static int collector_timer_gettime (timer_t timerid);
+static volatile int collector_sigprof_entries = 0; /* counter for SIGPROF signals in DISPATCH_TST mode */
+static timer_t collector_master_thread_timerid = NULL;
+static collector_mutex_t collector_clone_libc_lock = COLLECTOR_MUTEX_INITIALIZER;
+static unsigned dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
+
+static void *__real_clone = NULL;
+static void *__real_timer_create = NULL;
+static void *__real_timer_settime = NULL;
+static void *__real_timer_delete = NULL;
+static void *__real_timer_gettime = NULL;
+#if ARCH(Intel) && WSIZE(32)
+static void *__real_pthread_create_2_1 = NULL;
+static void *__real_pthread_create_2_0 = NULL;
+#elif ARCH(Intel) && WSIZE(64)
+static void *__real_timer_create_2_3_3 = NULL;
+static void *__real_timer_create_2_2_5 = NULL;
+#elif ARCH(SPARC) && WSIZE(64)
+static void *__real_timer_create_2_3_3 = NULL;
+static void *__real_timer_create_2_2 = NULL;
+#endif
+
+/* Original SIGPROF handler which will be replaced with the dispatcher. Used
+ * to properly interact with libaio, which uses SIGPROF as its SIGAIOCANCEL. */
+static struct sigaction original_sigprof_handler;
+
+enum
+{
+ DISPATCH_NYI = -1, /* dispatcher not yet installed */
+ DISPATCH_OFF = 0, /* dispatcher installed, but disabled */
+ DISPATCH_ON = 1, /* dispatcher installed, and enabled */
+ DISPATCH_TST = 2 /* dispatcher installed, and enabled in testing mode */
+};
+
+static int dispatch_mode = DISPATCH_NYI; /* controls SIGPROF dispatching */
+static int itimer_period_requested = 0; /* dispatcher itimer period */
+static int itimer_period_actual = 0; /* actual dispatcher itimer period */
+
+#define CALL_REAL(x) (*(int(*)())__real_##x)
+#define NULL_PTR(x) ( __real_##x == NULL )
+
+static void *__real_sigaction = NULL;
+static void *__real_setitimer = NULL;
+static void *__real_libc_setitimer = NULL;
+static void *__real_sigprocmask = NULL;
+static void *__real_thr_sigsetmask = NULL;
+static void *__real_pthread_sigmask = NULL;
+static void *__real_pthread_create = NULL;
+
+/*
+ * void collector_sigprof_dispatcher()
+ *
+ * Common SIGPROF event handler which dispatches events to appropriate
+ * module handlers, if they are active for this collection and due.
+ * Dispatch sequence, logic and handlers currently hardcoded in dispatcher.
+ */
+static void
+collector_sigprof_dispatcher (int sig, siginfo_t *info, void *context)
+{
+ if (info == NULL || (info->si_code <= 0 && info->si_code != SI_TIMER))
+ {
+ TprintfT (DBG_LT2, "collector_sigprof_dispatcher signal for %p\n",
+ original_sigprof_handler.sa_handler);
+ /* pass signal to previous handler */
+ /* watch for recursion, SIG_IGN, and SIG_DFL */
+ if (original_sigprof_handler.sa_handler == SIG_DFL)
+ __collector_SIGDFL_handler (SIGPROF);
+ else if (original_sigprof_handler.sa_handler != SIG_IGN &&
+ original_sigprof_handler.sa_sigaction != &collector_sigprof_dispatcher)
+ {
+ (original_sigprof_handler.sa_sigaction)(sig, info, context);
+ TprintfT (DBG_LT2, "collector_sigprof_dispatcher handled\n");
+ }
+ }
+ else if (dispatch_mode == DISPATCH_ON)
+ {
+#if ARCH(SPARC)
+ ucontext_t uctxmem;
+ ucontext_t *uctx = &uctxmem;
+ uctx->uc_link = NULL;
+ /* 23340823 signal handler third argument should point to a ucontext_t */
+ /* Convert sigcontext to ucontext_t on sparc-Linux */
+ struct sigcontext *sctx = (struct sigcontext*) context;
+#if WSIZE(32)
+ uctx->uc_mcontext.gregs[REG_PC] = sctx->si_regs.pc;
+ __collector_memcpy (&uctx->uc_mcontext.gregs[3],
+ sctx->si_regs.u_regs,
+ sizeof (sctx->si_regs.u_regs));
+#else
+ uctx->uc_mcontext.mc_gregs[MC_PC] = sctx->sigc_regs.tpc;
+ __collector_memcpy (&uctx->uc_mcontext.mc_gregs[3],
+ sctx->sigc_regs.u_regs,
+ sizeof (sctx->sigc_regs.u_regs));
+#endif /* WSIZE() */
+
+#else /* not sparc-Linux */
+ ucontext_t *uctx = (ucontext_t*) context;
+#endif /* ARCH() */
+ TprintfT (DBG_LT3, "collector_sigprof_dispatcher dispatching signal\n");
+
+ /* XXXX the order of these checks/activities may need adjustment */
+ /* XXXX should also check (first) for a "cached" manual sample */
+ /* HWC check for each LWP: required even if collection is paused */
+ /* This should be first, otherwise it's likely to find the counters
+ * stopped due to an event/overflow during some of the other activities.
+ */
+ /* XXXX HWC check performed every time (skipping if HWC profiling inactive)
+ * to avoid complexity of maintaining separate check times for each LWP
+ */
+ __collector_ext_hwc_check (info, uctx);
+
+ /* XXXX if sigemtpending, should perhaps skip __collector_ext_usage_sample
+ * (and get it next time through)
+ */
+
+ /* check for experiment past delay start */
+ if (__collector_delay_start != 0)
+ {
+ hrtime_t now = __collector_gethrtime ();
+ if (__collector_delay_start < now)
+ {
+ TprintfT (0, "__collector_ext_usage_sample: now (%lld) > delay_start (%lld)\n",
+ (now - __collector_start_time), (__collector_delay_start - __collector_start_time));
+
+ /* resume the data collection */
+ __collector_delay_start = 0;
+ __collector_resume ();
+
+ /* don't take a periodic sample, just let the resume sample cover it */
+ if (__collector_sample_period != 0)
+ {
+ /* this update should only be done for periodic samples */
+ while (__collector_next_sample < now)
+ __collector_next_sample += ((hrtime_t) NANOSEC) * __collector_sample_period;
+ }
+ /* return; */
+ }
+ }
+ /* check for periodic sampling */
+ if (__collector_gethrtime () > __collector_next_sample)
+ __collector_ext_usage_sample (PERIOD_SMPL, "periodic");
+
+ /* check for experiment past termination time */
+ if (__collector_exp_active && __collector_terminate_time != 0)
+ {
+ hrtime_t now = __collector_gethrtime ();
+ if (__collector_terminate_time < now)
+ {
+ TprintfT (0, "__collector_ext_usage_sample: now (%lld) > terminate_time (%lld); closing experiment\n",
+ (now - __collector_start_time), (__collector_terminate_time - __collector_start_time));
+ /* close the experiment */
+ __collector_close_experiment ();
+ }
+ }
+
+ /* call the code to process the profile data, and generate the packet */
+ /* (must always be called, otherwise profile data must be aggregated,
+ * but can be left till last, as already have the required data)
+ */
+ __collector_ext_profile_handler (info, uctx);
+ }
+ else if (dispatch_mode == DISPATCH_TST)
+ {
+ collector_sigprof_entries++;
+ return;
+ }
+}
+
+/*
+ * __collector_sigprof_install
+ */
+int
+__collector_sigprof_install ()
+{
+ TprintfT (DBG_LT2, "__collector_sigprof_install\n");
+ struct sigaction oact;
+ if (__collector_sigaction (SIGPROF, NULL, &oact) != 0)
+ return COL_ERROR_DISPINIT;
+ if (oact.sa_sigaction == collector_sigprof_dispatcher)
+ /* signal handler is already in place; we are probably in a fork-child */
+ TprintfT (DBG_LT1, "dispatcher: __collector_ext_dispatcher_install() collector_sigprof_dispatcher already installed\n");
+ else
+ {
+ struct sigaction c_act;
+ CALL_UTIL (memset)(&c_act, 0, sizeof c_act);
+ sigemptyset (&c_act.sa_mask);
+ sigaddset (&c_act.sa_mask, HWCFUNCS_SIGNAL); /* block SIGEMT delivery in handler */
+ c_act.sa_sigaction = collector_sigprof_dispatcher;
+ c_act.sa_flags = SA_RESTART | SA_SIGINFO;
+ if (__collector_sigaction (SIGPROF, &c_act, &original_sigprof_handler))
+ return COL_ERROR_DISPINIT;
+ }
+ dispatch_mode = DISPATCH_OFF; /* don't dispatch yet */
+ TprintfT (DBG_LT2, "__collector_sigprof_install done\n");
+ return COL_ERROR_NONE;
+}
+
+/*
+ * void __collector_ext_dispatcher_tsd_create_key()
+ *
+ * create tsd key for dispatcher
+ */
+void
+__collector_ext_dispatcher_tsd_create_key ()
+{
+ dispatcher_key = __collector_tsd_create_key (sizeof (timer_t), NULL, NULL);
+}
+/*
+ * int __collector_ext_dispatcher_install()
+ *
+ * installs a common handler/dispatcher (and itimer) for SIGPROF events
+ */
+int
+__collector_ext_dispatcher_install ()
+{
+ int timer_period;
+ TprintfT (DBG_LT2, "__collector_ext_dispatcher_install\n");
+
+ /* check period set for interval timer, which will be used as the basis
+ * for all timed activities: if not set, no role for SIGPROF dispatcher
+ */
+ if (itimer_period_requested <= 0)
+ {
+ TprintfT (DBG_LT1, "No interval timer set: skipping dispatcher install!\n");
+ return COL_ERROR_NONE; /* no itimer/dispatcher required */
+ }
+
+ /* check for an existing interval timer */
+ if (collector_master_thread_timerid == NULL)
+ if (collector_timer_create (&collector_master_thread_timerid) < 0)
+ return COL_ERROR_ITMRINIT;
+ timer_t *timeridptr = __collector_tsd_get_by_key (dispatcher_key);
+ if (timeridptr != NULL)
+ *timeridptr = collector_master_thread_timerid; // store for per thread timer stop/start
+ TprintfT (DBG_LT3, "__collector_ext_dispatcher_install: collector_master_thread_timerid=%p\n",
+ collector_master_thread_timerid);
+ timer_period = collector_timer_gettime (collector_master_thread_timerid);
+ if (timer_period > 0)
+ {
+ TprintfT (DBG_LT1, "Overriding app-set interval timer with period %d\n", timer_period);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d->%d</event>\n",
+ SP_JCMD_CWARN, COL_WARN_ITMRPOVR, timer_period, itimer_period_requested);
+ }
+ /* install the interval timer used for all timed activities */
+ if (collector_timer_settime (itimer_period_requested, collector_master_thread_timerid) < 0)
+ return COL_ERROR_ITMRINIT;
+ TprintfT (DBG_LT2, "__collector_ext_dispatcher_install done\n");
+ dispatch_mode = DISPATCH_ON; /* activate SIGPROF dispatch to event handlers */
+ return COL_ERROR_NONE;
+}
+
+int
+__collector_sigaction (int sig, const struct sigaction *nact, struct sigaction *oact)
+{
+ TprintfT (DBG_LT1, "__collector_sigaction: %d, %p\n", sig, nact ? nact->sa_sigaction : NULL);
+ if (NULL_PTR (sigaction))
+ init_interposition_intf ();
+
+ /* Whether we change the signal handler in the kernel
+ * or not make sure the real sigaction is aware about
+ * our new handler (6227565)
+ */
+ return CALL_REAL (sigaction)(sig, nact, oact);
+}
+
+/*
+ * We have special dispatchers for SIGPROF and HWCFUNCS_SIGNAL to
+ * decide whether the signal was intended for us or for the user.
+ * One special case is SIGDFL, in which case we don't have a
+ * user-function address to call. If the user did indeed set
+ * default disposition for one of these signals and sent that
+ * signal, we honor that action, even though it will lead to
+ * termination.
+ */
+void
+__collector_SIGDFL_handler (int sig)
+{
+ /* remove our dispatcher, replacing it with the default disposition */
+ struct sigaction act;
+ CALL_UTIL (memset)(&act, 0, sizeof (act));
+ act.sa_handler = SIG_DFL;
+ if (__collector_sigaction (sig, &act, NULL))
+ {
+ /* XXXXXX what are we supposed to do here? we're committing suicide anyhow */
+ }
+ /* resend the signal we intercepted earlier */
+ // XXXX Bug 18177509 - additional sigprof signal kills target program
+ kill (getpid (), sig);
+}
+
+/*
+ * suspend/resume timer per thread
+ */
+void
+__collector_ext_dispatcher_thread_timer_suspend ()
+{
+ timer_t * timeridptr = __collector_tsd_get_by_key (dispatcher_key);
+ if (timeridptr != NULL && *timeridptr != NULL)
+ (void) collector_timer_settime (0, *timeridptr);
+ return;
+}
+
+int
+__collector_ext_dispatcher_thread_timer_resume ()
+{
+ timer_t * timeridptr = __collector_tsd_get_by_key (dispatcher_key);
+ if (timeridptr == NULL)
+ return -1;
+ if (*timeridptr == NULL)
+ { // timer id not initialized yet
+ TprintfT (DBG_LT2, "__collector_ext_dispatcher_thread_timer_resume: timer not initialized yet, create it\n");
+ if (collector_timer_create (timeridptr) == -1)
+ {
+ TprintfT (0, "__collector_ext_dispatcher_thread_timer_resume(): WARNING: No timer created\n");
+ return -1;
+ }
+ }
+ return collector_timer_settime (itimer_period_requested, *timeridptr);
+}
+
+void
+__collector_ext_dispatcher_suspend ()
+{
+ TprintfT (DBG_LT2, "__collector_ext_dispatcher_suspend\n");
+ if (dispatch_mode == DISPATCH_NYI)
+ {
+ TprintfT (0, "__collector_ext_dispatcher_suspend(): WARNING: No dispatcher installed\n");
+ return;
+ }
+
+ /* disable SIGPROF dispatching */
+ dispatch_mode = DISPATCH_OFF;
+
+ /* disable the interval timer; ignore any failures */
+ __collector_ext_dispatcher_thread_timer_suspend ();
+ return;
+}
+
+void
+__collector_ext_dispatcher_restart ()
+{
+ TprintfT (DBG_LT2, "__collector_ext_dispatcher_restart(ip=%d)\n", itimer_period_requested);
+ if (dispatch_mode == DISPATCH_NYI)
+ {
+ TprintfT (0, "__collector_ext_dispatcher_restart(): WARNING: No dispatcher installed\n");
+ return;
+ }
+
+ /* restart the interval timer used for all timed activities */
+ if (__collector_ext_dispatcher_thread_timer_resume () == 0)
+ dispatch_mode = DISPATCH_ON; /* re-activate SIGPROF dispatch to handlers */
+ return;
+}
+/*
+ * void __collector_ext_dispatcher_deinstall()
+ *
+ * If installed, disables SIGPROF dispatch and interval timer.
+ * Includes checks for last SIGPROF dispatch time, interval timer period,
+ * and currently installed SIGPROF handler, with appropriate warnings logged.
+ * The dispatcher remains installed to handle pending collector SIGPROFs and
+ * forward non-collector SIGPROFs to the application's handler(s).
+ * If the decision is ever made actually to deinstall the dispatcher,
+ * consider bug 4183714 and what to do about any possible pending
+ * SIGPROFs.
+ */
+
+void
+__collector_ext_dispatcher_deinstall ()
+{
+ TprintfT (DBG_LT1, "__collector_ext_dispatcher_deinstall()\n");
+ if (dispatch_mode == DISPATCH_NYI)
+ {
+ TprintfT (0, "__collector_ext_dispatcher_deinstall(): WARNING: No dispatcher installed\n");
+ return;
+ }
+ dispatch_mode = DISPATCH_OFF; /* disable SIGPROF dispatching */
+
+ /* verify that interval timer is still installed with expected period */
+ int timer_period = collector_timer_gettime (collector_master_thread_timerid);
+ if (timer_period != itimer_period_actual)
+ {
+ TprintfT (DBG_LT2, "dispatcher: Collector interval timer period changed %d -> %d\n",
+ itimer_period_actual, timer_period);
+ if ((itimer_period_actual >= (timer_period + timer_period / 10)) ||
+ (itimer_period_actual <= (timer_period - timer_period / 10)))
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
+ SP_JCMD_CWARN, COL_WARN_ITMRREP,
+ itimer_period_actual, timer_period);
+ else
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
+ SP_JCMD_COMMENT, COL_WARN_PROFRND,
+ itimer_period_actual, timer_period);
+ }
+
+ /* Verify that SIGPROF dispatcher is still installed.
+ * (still required with sigaction interposition and management,
+ * since interposition is not done for attach experiments)
+ */
+ struct sigaction curr;
+ if (__collector_sigaction (SIGPROF, NULL, &curr) == -1)
+ TprintfT (0, "ERROR: dispatcher sigaction check failed: errno=%d\n", errno);
+ else if (curr.sa_sigaction != collector_sigprof_dispatcher)
+ {
+ TprintfT (0, "ERROR: collector dispatcher replaced by %p!\n", curr.sa_handler);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%p</event>\n",
+ SP_JCMD_CWARN, COL_WARN_SIGPROF, curr.sa_handler);
+ }
+ else
+ TprintfT (DBG_LT2, "collector dispatcher integrity verified!\n");
+
+ /* disable the interval timer; ignore any failures */
+ if (collector_master_thread_timerid != NULL)
+ {
+ (void) CALL_REAL (timer_delete)(collector_master_thread_timerid);
+ collector_master_thread_timerid = NULL;
+ }
+ dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
+ itimer_period_requested = 0;
+ itimer_period_actual = 0;
+}
+
+/*
+ * void __collector_ext_dispatcher_fork_child_cleanup()
+ *
+ * delete timer, clear timer interval
+ */
+void
+__collector_ext_dispatcher_fork_child_cleanup ()
+{
+ if (collector_master_thread_timerid != NULL)
+ {
+ (void) CALL_REAL (timer_delete)(collector_master_thread_timerid);
+ collector_master_thread_timerid = NULL;
+ }
+ __collector_mutex_init (&collector_clone_libc_lock);
+ dispatcher_key = COLLECTOR_TSD_INVALID_KEY;
+ itimer_period_requested = 0;
+ itimer_period_actual = 0;
+}
+/*
+ * int __collector_ext_itimer_set (int rperiod)
+ *
+ * set itimer period, if not yet set to a positive number of microseconds,
+ * (after rounding to sys_resolution if necessary) and return its value
+ */
+int
+__collector_ext_itimer_set (int rperiod)
+{
+ int period;
+ /* if rperiod is negative, force setting */
+ if (rperiod < 0)
+ {
+ itimer_period_actual = 0;
+ period = -rperiod;
+ }
+ else
+ period = rperiod;
+
+ // ignore SIGPROF while testing itimer interval setting
+ int saved = dispatch_mode;
+ dispatch_mode = DISPATCH_OFF;
+ if (collector_timer_create (&collector_master_thread_timerid) == -1)
+ {
+ TprintfT (0, "__collector_ext_itimer_set(): WARNING: No timer created\n");
+ return itimer_period_actual;
+ }
+ if (collector_timer_settime (period, collector_master_thread_timerid) == 0)
+ {
+ itimer_period_actual = collector_timer_gettime (collector_master_thread_timerid);
+ (void) collector_timer_settime (0, collector_master_thread_timerid); /* XXXX unset for now */
+ itimer_period_requested = period;
+ if (itimer_period_requested != itimer_period_actual)
+ {
+ TprintfT (DBG_LT2, " itimer period %d adjusted to %d\n",
+ itimer_period_requested, itimer_period_actual);
+ // (void) __collector_log_write("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n",
+ // SP_JCMD_CWARN, COL_WARN_PROFRND, itimer_period_requested, itimer_period_actual);
+ }
+ else
+ TprintfT (DBG_LT2, " itimer period %d accepted\n", period);
+ }
+
+ // restore dispatching SIGPROF handler
+ dispatch_mode = saved;
+ TprintfT (0, "__collector_ext_itimer_set(%d), requested=%d, actual=%d)\n",
+ rperiod, itimer_period_requested, itimer_period_actual);
+ return (itimer_period_actual);
+}
+
+static int
+collector_timer_gettime (timer_t timerid)
+{
+ int timer_period;
+ struct itimerspec itimer;
+ if (timerid == NULL)
+ return (0); // timer was not initialized
+ if (CALL_REAL (timer_gettime)(timerid, &itimer) == -1)
+ {
+ /* this should never reasonably fail, so not worth logging */
+ TprintfT (DBG_LT1, "WARNING: timer_gettime failed: errno=%d\n", errno);
+ return (-1);
+ }
+ timer_period = ((itimer.it_interval.tv_sec * NANOSEC) +
+ itimer.it_interval.tv_nsec) / 1000;
+ TprintfT (DBG_LT2, "collector_timer_gettime (period=%d)\n", timer_period);
+ return (timer_period);
+}
+
+static int
+collector_timer_create (timer_t * ptimerid)
+{
+ struct sigevent sigev;
+ if (NULL_PTR (timer_create))
+ init_interposition_intf ();
+ TprintfT (DBG_LT2, "collector_timer_settime(): timer_create is %p\n", __real_timer_create);
+ sigev.sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL;
+ sigev.sigev_signo = SIGPROF;
+ sigev.sigev_value.sival_ptr = ptimerid;
+ sigev._sigev_un._tid = __collector_gettid ();
+ if (CALL_REAL (timer_create)(CLOCK_THREAD_CPUTIME_ID, &sigev, ptimerid) == -1)
+ {
+ TprintfT (DBG_LT2, "collector_timer_settime() failed! errno=%d\n", errno);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+collector_timer_settime (int period, timer_t timerid)
+{
+ struct itimerspec itimer;
+ if (NULL_PTR (timer_settime))
+ init_interposition_intf ();
+ TprintfT (DBG_LT2, "collector_timer_settime(period=%d)\n", period);
+ time_t NPM = 1000;
+ itimer.it_interval.tv_sec = NPM * period / NANOSEC;
+ itimer.it_interval.tv_nsec = (NPM * period) % NANOSEC;
+ itimer.it_value = itimer.it_interval;
+ if (CALL_REAL (timer_settime)(timerid, 0, &itimer, NULL) == -1)
+ {
+ TprintfT (DBG_LT2, "collector_timer_settime(%d) failed! errno=%d\n", period, errno);
+ return -1;
+ }
+ return 0;
+}
+
+static void
+protect_profiling_signals (sigset_t* lset)
+{
+ static unsigned int protected_sigprof = 0;
+ static unsigned int protected_sigemt = 0;
+ // T1 relies on thread signal masking, so best not to mess with it:
+ // T1 users have already been warned about the dangers of its use
+ if (__collector_libthread_T1)
+ return;
+ if (sigismember (lset, SIGPROF) && (dispatch_mode == DISPATCH_ON))
+ {
+ TprintfT (0, "WARNING: ignoring %s block while profiling\n", "SIGPROF");
+ if (protected_sigprof == 0)
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
+ SP_JCMD_CWARN, COL_WARN_SIGMASK, "SIGPROF");
+ sigdelset (lset, SIGPROF);
+ protected_sigprof++;
+ }
+ if (sigismember (lset, HWCFUNCS_SIGNAL) && __collector_ext_hwc_active ())
+ {
+ TprintfT (0, "WARNING: ignoring %s block while profiling\n", "SIGEMT");
+ if (protected_sigemt == 0)
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
+ SP_JCMD_CWARN, COL_WARN_SIGMASK, HWCFUNCS_SIGNAL_STRING);
+ sigdelset (lset, HWCFUNCS_SIGNAL);
+ protected_sigemt++;
+ }
+}
+
+#define SYS_SETITIMER_NAME "setitimer"
+#define SYS_SIGACTION_NAME "sigaction"
+#define SYS_SIGPROCMASK_NAME "sigprocmask"
+#define SYS_PTHREAD_SIGMASK "pthread_sigmask"
+#define SYS_THR_SIGSETMASK "thr_sigsetmask"
+
+static int
+init_interposition_intf ()
+{
+ if (__collector_dlsym_guard)
+ return 1;
+ void *dlflag;
+ /* Linux requires RTLD_LAZY, Solaris can do just RTLD_NOLOAD */
+ void *handle = dlopen (SYS_LIBC_NAME, RTLD_LAZY | RTLD_NOLOAD);
+
+#if ARCH(SPARC) && WSIZE(64)
+ /* dlopen a bogus path to avoid CR 23608692 */
+ dlopen ("/bogus_path_for_23608692_workaround/", RTLD_LAZY | RTLD_NOLOAD);
+#endif
+ __real_setitimer = dlsym (RTLD_NEXT, SYS_SETITIMER_NAME);
+
+ if (__real_setitimer == NULL)
+ {
+ __real_setitimer = dlsym (RTLD_DEFAULT, SYS_SETITIMER_NAME);
+ if (__real_setitimer == NULL)
+ {
+ TprintfT (DBG_LT2, "init_interposition_intf() setitimer not found\n");
+ return 1;
+ }
+ dlflag = RTLD_DEFAULT;
+ }
+ else
+ dlflag = RTLD_NEXT;
+
+ TprintfT (DBG_LT2, "init_interposition_intf() using RTLD_%s\n",
+ (dlflag == RTLD_DEFAULT) ? "DEFAULT" : "NEXT");
+ TprintfT (DBG_LT2, "@%p __real_setitimer\n", __real_setitimer);
+
+ __real_sigaction = dlsym (dlflag, SYS_SIGACTION_NAME);
+ TprintfT (DBG_LT2, "@%p __real_sigaction\n", __real_sigaction);
+
+ /* also explicitly get libc.so/setitimer (as a backup) */
+ __real_libc_setitimer = dlsym (handle, SYS_SETITIMER_NAME);
+ TprintfT (DBG_LT2, "@%p __real_libc_setitimer\n", __real_libc_setitimer);
+
+ __real_sigprocmask = dlsym (dlflag, SYS_SIGPROCMASK_NAME);
+ TprintfT (DBG_LT2, "@%p __real_sigprocmask\n", __real_sigprocmask);
+
+ __real_thr_sigsetmask = dlsym (dlflag, SYS_THR_SIGSETMASK);
+ TprintfT (DBG_LT2, "@%p __real_thr_sigsetmask\n", __real_thr_sigsetmask);
+
+ __real_pthread_sigmask = dlsym (dlflag, SYS_PTHREAD_SIGMASK);
+ TprintfT (DBG_LT2, "@%p __real_pthread_sigmask\n", __real_pthread_sigmask);
+
+#if ARCH(Aarch64)
+ __real_pthread_create = dlvsym (dlflag, "pthread_create", SYS_PTHREAD_CREATE_VERSION);
+ __real_timer_create = dlsym (dlflag, "timer_create");
+ __real_timer_settime = dlsym (dlflag, "timer_settime");
+ __real_timer_delete = dlsym (dlflag, "timer_delete");
+ __real_timer_gettime = dlsym (dlflag, "timer_gettime");
+#else
+ __real_pthread_create = dlvsym (dlflag, "pthread_create", SYS_PTHREAD_CREATE_VERSION);
+ TprintfT (DBG_LT2, "[%s] @%p __real_pthread_create\n", SYS_PTHREAD_CREATE_VERSION, __real_pthread_create);
+ __real_timer_create = dlvsym (dlflag, "timer_create", SYS_TIMER_X_VERSION);
+ TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_create\n", SYS_TIMER_X_VERSION, __real_timer_create);
+ __real_timer_settime = dlvsym (dlflag, "timer_settime", SYS_TIMER_X_VERSION);
+ TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_settime\n", SYS_TIMER_X_VERSION, __real_timer_settime);
+ __real_timer_delete = dlvsym (dlflag, "timer_delete", SYS_TIMER_X_VERSION);
+ TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_delete\n", SYS_TIMER_X_VERSION, __real_timer_delete);
+ __real_timer_gettime = dlvsym (dlflag, "timer_gettime", SYS_TIMER_X_VERSION);
+ TprintfT (DBG_LT2, "init_lineage_intf() [%s] @0x%p __real_timer_gettime\n", SYS_TIMER_X_VERSION, __real_timer_gettime);
+ __real_clone = dlsym (dlflag, "clone");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_clone\n", __real_clone);
+#if ARCH(Intel) && WSIZE(32)
+ __real_pthread_create_2_1 = __real_pthread_create;
+ __real_pthread_create_2_0 = dlvsym (dlflag, "pthread_create", "GLIBC_2.0");
+#elif ARCH(Intel) && WSIZE(64)
+ __real_timer_create_2_3_3 = __real_timer_create;
+ __real_timer_create_2_2_5 = dlvsym (dlflag, "timer_create", "GLIBC_2.2.5");
+#elif ARCH(SPARC) && WSIZE(64)
+ __real_timer_create_2_3_3 = __real_timer_create;
+ __real_timer_create_2_2 = dlvsym (dlflag, "timer_create", "GLIBC_2.2");
+#endif /* ARCH() && SIZE() */
+#endif
+ return 0;
+}
+
+
+/*------------------------------------------------------------- sigaction */
+
+/* NB: need a global interposing function called "sigaction" */
+int
+sigaction (int sig, const struct sigaction *nact, struct sigaction *oact)
+{
+ int ret = 0;
+ int err = 0;
+ if (NULL_PTR (sigaction))
+ err = init_interposition_intf ();
+ if (err)
+ return -1;
+ TprintfT (DBG_LT3, "sigaction(sig=%02d, nact=%p) interposing\n", sig, nact);
+ if (sig == SIGPROF && dispatch_mode != DISPATCH_NYI)
+ {
+ if (oact != NULL)
+ {
+ oact->sa_handler = original_sigprof_handler.sa_handler;
+ oact->sa_mask = original_sigprof_handler.sa_mask;
+ oact->sa_flags = original_sigprof_handler.sa_flags;
+ }
+ if (nact != NULL)
+ {
+ original_sigprof_handler.sa_handler = nact->sa_handler;
+ original_sigprof_handler.sa_mask = nact->sa_mask;
+ original_sigprof_handler.sa_flags = nact->sa_flags;
+ TprintfT (DBG_LT1, "dispatcher: new sigaction(sig=%02d) set\n", sig);
+ }
+ }
+ else if (sig == HWCFUNCS_SIGNAL)
+ ret = collector_sigemt_sigaction (nact, oact);
+ else
+ {
+ if (sig != SIGCHLD || collector_sigchld_sigaction (nact, oact))
+ ret = CALL_REAL (sigaction)(sig, nact, oact);
+ TprintfT (DBG_LT3, "Real sigaction(sig=%02d) returned %d (oact=%p)\n",
+ sig, ret, oact);
+ /* but check for other important signals */
+ /* check for sample and pause/resume signals; give warning once, if need be */
+ if ((sig == __collector_sample_sig) && (__collector_sample_sig_warn == 0))
+ {
+ /* give user a warning */
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
+ SP_JCMD_CWARN, COL_WARN_SAMPSIGUSED, __collector_sample_sig);
+ __collector_sample_sig_warn = 1;
+ }
+ if ((sig == __collector_pause_sig) && (__collector_pause_sig_warn == 0))
+ {
+ /* give user a warning */
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
+ SP_JCMD_CWARN, COL_WARN_PAUSESIGUSED, __collector_pause_sig);
+ __collector_pause_sig_warn = 1;
+ }
+ }
+ TprintfT (DBG_LT3, "sigaction() returning %d (oact=%p)\n", ret, oact);
+ return ret;
+}
+
+/*
+ * In addition to interposing on sigaction(), should we also interpose
+ * on other important signal functions like signal() or sigset()?
+ * - On Solaris, those other functions apparently call sigaction().
+ * So, we only have to interpose on it.
+ * - On Linux, we should perhaps interpose on these other functions,
+ * but they are less portable than sigaction() and deprecated or even obsolete.
+ * So, we interpose, but don't overly worry about doing a good job.
+ */
+sighandler_t
+signal (int sig, sighandler_t handler)
+{
+ struct sigaction nact;
+ struct sigaction oact;
+ TprintfT (DBG_LT3, "signal(sig=%02d, handler=%p) interposing\n", sig, handler);
+ sigemptyset (&nact.sa_mask);
+ nact.sa_handler = handler;
+ nact.sa_flags = SA_RESTART;
+ if (sigaction (sig, &nact, &oact))
+ return SIG_ERR;
+ TprintfT (DBG_LT3, "signal() returning %p\n", oact.sa_handler);
+ return oact.sa_handler;
+}
+
+sighandler_t
+sigset (int sig, sighandler_t handler)
+{
+ TprintfT (DBG_LT3, "sigset(sig=%02d, handler=%p) interposing\n", sig, handler);
+ return signal (sig, handler);
+}
+
+/*------------------------------------------------------------- timer_create */
+
+// map interposed symbol versions
+#if WSIZE(64)
+#if ARCH(SPARC) || ARCH(Intel)
+static int
+__collector_timer_create_symver (int(real_timer_create) (), clockid_t clockid, struct sigevent *sevp,
+ timer_t *timerid);
+
+int
+__collector_timer_create_2_3_3 (clockid_t clockid, struct sigevent *sevp,
+ timer_t *timerid)
+{
+ if (NULL_PTR (timer_create))
+ init_interposition_intf ();
+ TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_3_3@%p\n", CALL_REAL (timer_create_2_3_3));
+ return __collector_timer_create_symver (CALL_REAL (timer_create_2_3_3), clockid, sevp, timerid);
+}
+__asm__(".symver __collector_timer_create_2_3_3,timer_create@@GLIBC_2.3.3");
+#endif /* ARCH(SPARC) || ARCH(Intel)*/
+
+#if ARCH(SPARC)
+
+int
+__collector_timer_create_2_2 (clockid_t clockid, struct sigevent *sevp,
+ timer_t *timerid)
+{
+ if (NULL_PTR (timer_create))
+ init_interposition_intf ();
+ TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_2@%p\n", CALL_REAL (timer_create_2_2));
+ return __collector_timer_create_symver (CALL_REAL (timer_create_2_2), clockid, sevp, timerid);
+}
+
+__asm__(".symver __collector_timer_create_2_2,timer_create@GLIBC_2.2");
+
+#elif ARCH(Intel)
+
+int
+__collector_timer_create_2_2_5 (clockid_t clockid, struct sigevent *sevp,
+ timer_t *timerid)
+{
+ if (NULL_PTR (timer_create))
+ init_interposition_intf ();
+ TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_timer_create_2_2_5@%p\n", CALL_REAL (timer_create_2_2_5));
+ return __collector_timer_create_symver (CALL_REAL (timer_create_2_2_5), clockid, sevp, timerid);
+}
+__asm__(".symver __collector_timer_create_2_2_5,timer_create@GLIBC_2.2.5");
+#endif /* ARCH() */
+#endif /* WSIZE(64) */
+
+#if ARCH(Aarch64) || (ARCH(Intel) && WSIZE(32))
+int timer_create (clockid_t clockid, struct sigevent *sevp, timer_t *timerid)
+#else
+static int
+__collector_timer_create_symver (int(real_timer_create) (), clockid_t clockid,
+ struct sigevent *sevp, timer_t *timerid)
+#endif
+{
+ int ret;
+
+ if (NULL_PTR (timer_create))
+ init_interposition_intf ();
+
+ /* collector reserves SIGPROF
+ */
+ if (sevp == NULL || sevp->sigev_notify != SIGEV_SIGNAL
+ || sevp->sigev_signo != SIGPROF)
+ {
+#if ARCH(Aarch64) || (ARCH(Intel) && WSIZE(32))
+ ret = CALL_REAL (timer_create)(clockid, sevp, timerid);
+#else
+ ret = (real_timer_create) (clockid, sevp, timerid);
+#endif
+ TprintfT (DBG_LT2, "Real timer_create(%d) returned %d\n",
+ clockid, ret);
+ return ret;
+ }
+
+ /* log that application's timer_create request is overridden */
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
+ SP_JCMD_CWARN, COL_WARN_ITMROVR, -1);
+ ret = -1;
+ errno = EBUSY;
+ TprintfT (DBG_LT2, "timer_create() returning %d\n", ret);
+ return ret;
+}
+/*------------------------------------------------------------- setitimer */
+int
+_setitimer (int which, const struct itimerval *nval,
+ struct itimerval *oval)
+{
+ int ret;
+ int period;
+
+ if (NULL_PTR (setitimer))
+ init_interposition_intf ();
+
+ if (nval == NULL)
+ period = -1;
+ else
+ period = (nval->it_interval.tv_sec * MICROSEC) +
+ nval->it_interval.tv_usec;
+ TprintfT (DBG_LT1, "setitimer(which=%d,nval=%dus) interposing\n", which, period);
+
+ /* collector reserves ITIMER_REALPROF for its own use, and ITIMER_PROF
+ * uses the same signal (SIGPROF) so it must also be reserved
+ */
+ if (((which != ITIMER_REALPROF) && (which != ITIMER_PROF)) || (nval == NULL))
+ {
+ ret = CALL_REAL (setitimer)(which, nval, oval);
+ if (oval == NULL)
+ period = -1;
+ else
+ period = (oval->it_interval.tv_sec * MICROSEC) +
+ oval->it_interval.tv_usec;
+ TprintfT (DBG_LT2, "Real setitimer(%d) returned %d (oval=%dus)\n",
+ which, ret, period);
+ return ret;
+ }
+ /* log that application's setitimer request is overridden */
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
+ SP_JCMD_CWARN, COL_WARN_ITMROVR, period);
+ if (oval == NULL)
+ period = -1;
+ else
+ {
+ getitimer (which, oval); /* return current itimer setting */
+ period = (oval->it_interval.tv_sec * MICROSEC) +
+ oval->it_interval.tv_usec;
+ }
+ ret = -1;
+ errno = EBUSY;
+ TprintfT (DBG_LT2, "setitimer() returning %d (oval=%dus)\n", ret, period);
+ return ret;
+}
+
+/*--------------------------------------------------------------- sigprocmask */
+int
+__collector_sigprocmask (int how, const sigset_t* iset, sigset_t* oset)
+{
+ int err = 0;
+ if (NULL_PTR (sigprocmask))
+ err = init_interposition_intf ();
+ if (err)
+ return -1;
+ TprintfT (DBG_LT2, "__collector_sigprocmask(%d) interposing\n", how);
+ sigset_t lsigset;
+ sigset_t* lset = NULL;
+ if (iset)
+ {
+ lsigset = *iset;
+ lset = &lsigset;
+ if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
+ protect_profiling_signals (lset);
+ }
+ int ret = CALL_REAL (sigprocmask)(how, lset, oset);
+ TprintfT (DBG_LT2, "__collector_sigprocmask(%d) returning %d\n", how, ret);
+ return ret;
+}
+
+/*------------------------------------------------------------ thr_sigsetmask */
+int
+__collector_thr_sigsetmask (int how, const sigset_t* iset, sigset_t* oset)
+{
+ if (NULL_PTR (thr_sigsetmask))
+ init_interposition_intf ();
+ TprintfT (DBG_LT1, "__collector_thr_sigsetmask(%d) interposing\n", how);
+ sigset_t lsigset;
+ sigset_t* lset = NULL;
+ if (iset)
+ {
+ lsigset = *iset;
+ lset = &lsigset;
+ if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
+ protect_profiling_signals (lset);
+ }
+ int ret = CALL_REAL (thr_sigsetmask)(how, lset, oset);
+ TprintfT (DBG_LT1, "__collector_thr_sigsetmask(%d) returning %d\n", how, ret);
+ return ret;
+}
+
+/*----------------------------------------------------------- pthread_sigmask */
+
+int
+pthread_sigmask (int how, const sigset_t* iset, sigset_t* oset)
+{
+ if (NULL_PTR (pthread_sigmask))
+ init_interposition_intf ();
+ TprintfT (DBG_LT1, "__collector_pthread_sigmask(%d) interposing\n", how);
+ sigset_t lsigset;
+ sigset_t* lset = NULL;
+ if (iset)
+ {
+ lsigset = *iset;
+ lset = &lsigset;
+ if ((how == SIG_BLOCK) || (how == SIG_SETMASK))
+ protect_profiling_signals (lset);
+ }
+ int ret = CALL_REAL (pthread_sigmask)(how, lset, oset);
+ TprintfT (DBG_LT1, "__collector_pthread_sigmask(%d) returning %d\n", how, ret);
+ return ret;
+}
+/*----------------------------------------------------------- pthread_create */
+typedef struct _CollectorArgs
+{
+ void *(*func)(void*);
+ void *arg;
+ void *stack;
+ int isPthread;
+} CollectorArgs;
+
+static void *
+collector_root (void *cargs)
+{
+ /* save the real arguments and free cargs */
+ void *(*func)(void*) = ((CollectorArgs*) cargs)->func;
+ void *arg = ((CollectorArgs*) cargs)->arg;
+ void *stack = ((CollectorArgs*) cargs)->stack;
+ int isPthread = ((CollectorArgs*) cargs)->isPthread;
+ __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
+
+ /* initialize tsd for this thread */
+ if (__collector_tsd_allocate () == 0)
+ /* init tsd for unwind, called right after __collector_tsd_allocate()*/
+ __collector_ext_unwind_key_init (isPthread, stack);
+
+ if (!isPthread)
+ __collector_mutex_lock (&collector_clone_libc_lock);
+
+ /* set the profile timer */
+ timer_t *timeridptr = __collector_tsd_get_by_key (dispatcher_key);
+ timer_t timerid = NULL;
+ if (timeridptr != NULL)
+ {
+ collector_timer_create (timeridptr);
+ if (*timeridptr != NULL)
+ collector_timer_settime (itimer_period_requested, *timeridptr);
+ timerid = *timeridptr;
+ }
+ int hwc_rc = __collector_ext_hwc_lwp_init ();
+
+ if (!isPthread)
+ __collector_mutex_unlock (&collector_clone_libc_lock);
+ /* call the real function */
+ void *ret = func (arg);
+ if (!isPthread)
+ __collector_mutex_lock (&collector_clone_libc_lock);
+ if (timerid != NULL)
+ CALL_REAL (timer_delete)(timerid);
+ if (!hwc_rc)
+ /* pthread_kill not handled here */
+ __collector_ext_hwc_lwp_fini ();
+
+ if (!isPthread)
+ __collector_mutex_unlock (&collector_clone_libc_lock);
+ /* if we have this chance, release tsd */
+ __collector_tsd_release ();
+
+ return ret;
+}
+
+// map interposed symbol versions
+#if ARCH(Intel) && WSIZE(32)
+static int
+__collector_pthread_create_symver (int(real_pthread_create) (),
+ pthread_t *thread,
+ const pthread_attr_t *attr,
+ void *(*func)(void*),
+ void *arg);
+
+int
+__collector_pthread_create_2_1 (pthread_t *thread,
+ const pthread_attr_t *attr,
+ void *(*func)(void*),
+ void *arg)
+{
+ if (NULL_PTR (pthread_create))
+ init_interposition_intf ();
+ TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_pthread_create_2_1@%p\n", CALL_REAL (pthread_create_2_1));
+ return __collector_pthread_create_symver (CALL_REAL (pthread_create_2_1), thread, attr, func, arg);
+}
+
+int
+__collector_pthread_create_2_0 (pthread_t *thread,
+ const pthread_attr_t *attr,
+ void *(*func)(void*),
+ void *arg)
+{
+ if (NULL_PTR (pthread_create))
+ init_interposition_intf ();
+ TprintfT (DBG_LTT, "dispatcher: GLIBC: __collector_pthread_create_2_0@%p\n", CALL_REAL (pthread_create_2_0));
+ return __collector_pthread_create_symver (CALL_REAL (pthread_create_2_0), thread, attr, func, arg);
+}
+
+__asm__(".symver __collector_pthread_create_2_1,pthread_create@@GLIBC_2.1");
+__asm__(".symver __collector_pthread_create_2_0,pthread_create@GLIBC_2.0");
+
+#endif
+
+#if ARCH(Intel) && WSIZE(32)
+static int
+__collector_pthread_create_symver (int(real_pthread_create) (),
+ pthread_t *thread,
+ const pthread_attr_t *attr,
+ void *(*func)(void*),
+ void *arg)
+#else
+int
+pthread_create (pthread_t *thread, const pthread_attr_t *attr,
+ void *(*func)(void*), void *arg)
+#endif
+{
+ if (NULL_PTR (pthread_create))
+ init_interposition_intf ();
+
+ TprintfT (DBG_LT1, "pthread_create interposition called\n");
+
+ if (dispatch_mode != DISPATCH_ON)
+ {
+#if ARCH(Intel) && WSIZE(32)
+ return (real_pthread_create) (thread, attr, func, arg);
+#else
+ return CALL_REAL (pthread_create)(thread, attr, func, arg);
+#endif
+ }
+ CollectorArgs *cargs = __collector_allocCSize (__collector_heap, sizeof (CollectorArgs), 1);
+
+ if (cargs == NULL)
+ {
+#if ARCH(Intel) && WSIZE(32)
+ return (real_pthread_create) (thread, attr, func, arg);
+#else
+ return CALL_REAL (pthread_create)(thread, attr, func, arg);
+#endif
+ }
+ cargs->func = func;
+ cargs->arg = arg;
+ cargs->stack = NULL;
+ cargs->isPthread = 1;
+ int ret = -1;
+#if ARCH(Intel) && WSIZE(32)
+ ret = (real_pthread_create) (thread, attr, &collector_root, cargs);
+#else
+ ret = CALL_REAL (pthread_create)(thread, attr, &collector_root, cargs);
+#endif
+ if (ret)
+ __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
+ TprintfT (DBG_LT1, "pthread_create returning %d\n", ret);
+ return ret;
+}
+
+int
+__collector_ext_clone_pthread (int (*fn)(void *), void *child_stack, int flags, void *arg,
+ va_list va /* pid_t *ptid, struct user_desc *tls, pid_t *" ctid" */)
+{
+ if (NULL_PTR (clone))
+ init_interposition_intf ();
+ TprintfT (0, "clone thread interposing\n");
+ pid_t * ptid = NULL;
+ struct user_desc * tls = NULL;
+ pid_t * ctid = NULL;
+ int num_args = 0;
+ if (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))
+ {
+ ptid = va_arg (va, pid_t *);
+ tls = va_arg (va, struct user_desc*);
+ ctid = va_arg (va, pid_t *);
+ num_args = 3;
+ }
+ else if (flags & CLONE_SETTLS)
+ {
+ ptid = va_arg (va, pid_t *);
+ tls = va_arg (va, struct user_desc*);
+ num_args = 2;
+ }
+ else if (flags & CLONE_PARENT_SETTID)
+ {
+ ptid = va_arg (va, pid_t *);
+ num_args = 1;
+ }
+ int ret = 0;
+ if (dispatch_mode != DISPATCH_ON)
+ {
+ switch (num_args)
+ {
+ case 3:
+ ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
+ break;
+ case 2:
+ ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
+ break;
+ case 1:
+ ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
+ break;
+ default:
+ ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
+ break;
+ }
+ return ret;
+ }
+ CollectorArgs *cargs = __collector_allocCSize (__collector_heap, sizeof (CollectorArgs), 1);
+ if (cargs == NULL)
+ {
+ switch (num_args)
+ {
+ case 3:
+ ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
+ break;
+ case 2:
+ ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
+ break;
+ case 1:
+ ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
+ break;
+ default:
+ ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
+ break;
+ }
+ return ret;
+ }
+
+ cargs->func = (void *(*)(void*))fn;
+ cargs->arg = arg;
+ cargs->stack = child_stack;
+ cargs->isPthread = 0;
+
+ switch (num_args)
+ {
+ case 3:
+ ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid, tls, ctid);
+ break;
+ case 2:
+ ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid, tls);
+ break;
+ case 1:
+ ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs, ptid);
+ break;
+ default:
+ ret = CALL_REAL (clone)((int(*)(void*))collector_root, child_stack, flags, cargs);
+ break;
+ }
+
+ if (ret < 0)
+ __collector_freeCSize (__collector_heap, cargs, sizeof (CollectorArgs));
+ TprintfT (DBG_LT1, "clone thread returning %d\n", ret);
+ return ret;
+}
+
+// weak symbols:
+int sigprocmask () __attribute__ ((weak, alias ("__collector_sigprocmask")));
+int thr_sigsetmask () __attribute__ ((weak, alias ("__collector_thr_sigsetmask")));
+int setitimer () __attribute__ ((weak, alias ("_setitimer")));
diff --git a/gprofng/libcollector/envmgmt.c b/gprofng/libcollector/envmgmt.c
new file mode 100644
index 0000000..b4418d6
--- /dev/null
+++ b/gprofng/libcollector/envmgmt.c
@@ -0,0 +1,840 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/*
+ * Routines for managing the target's environment array
+ */
+
+#include "config.h"
+#include "descendants.h"
+
+#define MAX_LD_PRELOADS 2
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+#define DBG_LT4 4
+
+/* original environment settings to be saved for later restoration */
+static char *sp_preloads[MAX_LD_PRELOADS];
+static char *sp_libpaths[MAX_LD_PRELOADS];
+char **sp_env_backup;
+
+static const char *SP_ENV[];
+static const char *LD_ENV[];
+static const char *SP_PRELOAD[];
+static const char *LD_PRELOAD[];
+static const char *SP_LIBRARY_PATH[];
+static const char *LD_LIBRARY_PATH[];
+static int NUM_SP_ENV_VARS;
+static int NUM_LD_ENV_VARS;
+static int NUM_SP_PRELOADS;
+static int NUM_LD_PRELOADS;
+static int NUM_SP_LIBPATHS;
+static int NUM_LD_LIBPATHS;
+
+static const char *SP_ENV[] = {
+ SP_COLLECTOR_PARAMS, /* data descriptor */
+ SP_COLLECTOR_EXPNAME, /* experiment name */
+ SP_COLLECTOR_FOLLOW_SPEC, /* linetrace */
+ SP_COLLECTOR_FOUNDER, /* determine founder exp */
+ SP_PRELOAD_STRINGS, /* LD_PRELOADs for data collection */
+ SP_LIBPATH_STRINGS, /* LD_LIBRARY_PATHs for data collection */
+ "SP_COLLECTOR_TRACELEVEL", /* tprintf */
+#if DEBUG
+ "SP_COLLECTOR_SIGACTION", /* dispatcher, hwprofile */
+#endif
+ /* JAVA* */
+ /* LD_DEBUG=audit,bindings,detail */
+ /* LD_ORIGIN=yes */
+ NULL
+};
+
+static const char *LD_ENV[] = {
+ LD_PRELOAD_STRINGS, /* LD_PRELOADs */
+ LD_LIBPATH_STRINGS, /* LD_LIBRARY_PATHs */
+ JAVA_TOOL_OPTIONS, /* enable -agentlib:collector for JVMTI */
+ NULL
+};
+
+static const char *SP_PRELOAD[] = {
+ SP_PRELOAD_STRINGS,
+ NULL
+};
+
+static const char *LD_PRELOAD[] = {
+ LD_PRELOAD_STRINGS,
+ NULL
+};
+
+static const char *SP_LIBRARY_PATH[] = {
+ SP_LIBPATH_STRINGS,
+ NULL
+};
+static const char *LD_LIBRARY_PATH[] = {
+ LD_LIBPATH_STRINGS,
+ NULL
+};
+
+void
+__collector_env_save_preloads ()
+{
+ /* save the list of SP_PRELOADs */
+ int v;
+ for (v = 0; SP_PRELOAD[v]; v++)
+ {
+ sp_preloads[v] = __collector_strdup (CALL_UTIL (getenv)(SP_PRELOAD[v]));
+ TprintfT (DBG_LT3, "__collector_env_save_preloads: %s=%s\n", SP_PRELOAD[v], sp_preloads[v]);
+ }
+ NUM_SP_PRELOADS = v;
+ for (v = 0; SP_LIBRARY_PATH[v]; v++)
+ {
+ sp_libpaths[v] = __collector_strdup (CALL_UTIL (getenv)(SP_LIBRARY_PATH[v]));
+ TprintfT (DBG_LT4, "__collector_env_save_preloads: %s=%s\n", SP_LIBRARY_PATH[v],
+ sp_libpaths[v] ? sp_libpaths[v] : "NULL");
+ }
+ NUM_SP_LIBPATHS = v;
+ for (v = 0; LD_PRELOAD[v]; v++)
+ ;
+ NUM_LD_PRELOADS = v;
+ for (v = 0; LD_LIBRARY_PATH[v]; v++)
+ ;
+ NUM_LD_LIBPATHS = v;
+ for (v = 0; SP_ENV[v]; v++)
+ ;
+ NUM_SP_ENV_VARS = v;
+ for (v = 0; LD_ENV[v]; v++)
+ ;
+ NUM_LD_ENV_VARS = v;
+}
+
+/* free the memory involved in backing up the environment */
+void
+__collector_env_backup_free ()
+{
+ int v = 0;
+ TprintfT (DBG_LT2, "env_backup_free()\n");
+ for (v = 0; sp_env_backup[v]; v++)
+ {
+ TprintfT (DBG_LT2, "env_backup_free():sp_env_backup[%d]=%s \n", v, sp_env_backup[v]);
+ __collector_freeCSize (__collector_heap, (char *) sp_env_backup[v], __collector_strlen (sp_env_backup[v]) + 1);
+ }
+ __collector_freeCSize (__collector_heap, (char**) sp_env_backup,
+ (NUM_SP_ENV_VARS + NUM_LD_ENV_VARS + 1) * sizeof (char*));
+}
+
+char **
+__collector_env_backup ()
+{
+ TprintfT (DBG_LT2, "env_backup_()\n");
+ char **backup = __collector_env_allocate (NULL, 1);
+ __collector_env_update (backup);
+ TprintfT (DBG_LT2, "env_backup_()\n");
+ return backup;
+}
+
+/*
+ function: env_prepend()
+ given an <old_str>, check to see if <str>
+ is already defined by it. If not, allocate
+ a new string and concat <envvar>=<str><separator><old_str>
+ params:
+ old_str: original string
+ str: substring to prepend
+ return: pointer to updated string or NULL if string was not updated.
+ */
+static char *
+env_prepend (const char *envvar, const char *str, const char *separator,
+ const char *old_str)
+{
+ if (!envvar || *envvar == 0 || !str || *str == 0)
+ {
+ /* nothing to do */
+ TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\") -- nothing to do\n",
+ envvar, str, separator, old_str);
+
+ return NULL;
+ }
+ TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\")\n",
+ envvar, str, separator, old_str);
+ char *ev;
+ size_t strsz;
+ if (!old_str || *old_str == 0)
+ {
+ strsz = __collector_strlen (envvar) + 1 + __collector_strlen (str) + 1;
+ ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1);
+ if (ev)
+ {
+ CALL_UTIL (snprintf)(ev, strsz, "%s=%s", envvar, str);
+ assert (__collector_strlen (ev) + 1 == strsz);
+ }
+ else
+ TprintfT (DBG_LT2, "env_prepend(): could not allocate memory\n");
+ }
+ else
+ {
+ char *p = CALL_UTIL (strstr)(old_str, str);
+ if (p)
+ {
+ TprintfT (DBG_LT2, "env_prepend(): %s=%s was already set\n",
+ envvar, old_str);
+ return NULL;
+ }
+ strsz = __collector_strlen (envvar) + 1 + __collector_strlen (str) +
+ __collector_strlen (separator) + __collector_strlen (old_str) + 1;
+ ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1);
+ if (ev)
+ {
+ CALL_UTIL (snprintf)(ev, strsz, "%s=%s%s%s", envvar, str, separator, old_str);
+ assert (__collector_strlen (ev) + 1 == strsz);
+ }
+ else
+ TprintfT (DBG_LT2, "env_prepend(): could not allocate memory\n");
+ }
+ TprintfT (DBG_LT2, "env_prepend(\"%s\", \"%s\", \"%s\", \"%s\") returns \"%s\"\n",
+ envvar, str, separator, old_str, (ev == NULL ? "NULL" : ev));
+ return ev;
+}
+
+/*
+ function: putenv_prepend()
+ get environment variable <envvar>, check to see if <str>
+ is already defined by it. If not prepend <str>
+ and put it back to environment.
+ params:
+ envvar: environment variable
+ str: substring to find
+ return: 0==success, nonzero on failure.
+ */
+int
+putenv_prepend (const char *envvar, const char *str, const char *separator)
+{
+ if (!envvar || *envvar == 0)
+ return 1;
+ const char * old_str = CALL_UTIL (getenv)(envvar);
+ char * newstr = env_prepend (envvar, str, separator, old_str);
+ if (newstr)
+ // now put the new variable into the environment
+ if (CALL_UTIL (putenv)(newstr) != 0)
+ {
+ TprintfT (DBG_LT2, "putenv_prepend(): ERROR %s is not set!\n", newstr);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ function: env_strip()
+ Finds substr in origstr; Removes
+ all characters from previous ':' or ' '
+ up to and including any trailing ':' or ' '.
+ params:
+ env: environment variable contents
+ str: substring to find
+ return: count of instances removed from env
+ */
+static int
+env_strip (char *origstr, const char *substr)
+{
+ int removed = 0;
+ char *p, *q;
+ if (origstr == NULL || substr == NULL || *substr == 0)
+ return 0;
+ while ((p = q = CALL_UTIL (strstr)(origstr, substr)))
+ {
+ p += __collector_strlen (substr);
+ while (*p == ':' || *p == ' ') /* strip trailing separator */
+ p++;
+ while (*q != ':' && *q != ' ' && *q != '=' && q != origstr) /* strip path */
+ q--;
+ if (q != origstr) /* restore leading separator (if any) */
+ q++;
+ __collector_strlcpy (q, p, __collector_strlen (p) + 1);
+ removed++;
+ }
+ return removed;
+}
+
+/*
+ function: env_ld_preload_strip()
+ Removes known libcollector shared objects from envv.
+ params:
+ var: shared object name (leading characters don't have to match)
+ return: 0 = so's removed, non-zero = so's not found.
+ */
+static int
+env_ld_preload_strip (char *envv)
+{
+ if (!envv || *envv == 0)
+ {
+ TprintfT (DBG_LT2, "env_ld_preload_strip(): WARNING - envv is NULL\n");
+ return -1;
+ }
+ for (int v = 0; SP_PRELOAD[v]; v++)
+ if (env_strip (envv, sp_preloads[v]))
+ return 0;
+ if (line_mode != LM_CLOSED)
+ TprintfT (DBG_LT2, "env_ld_preload_strip(): WARNING - could not strip SP_PRELOADS from '%s'\n",
+ envv);
+ return -2;
+}
+
+void
+__collector_env_print (char * label)
+{
+#if DEBUG
+ TprintfT (DBG_LT2, "__collector_env_print(%s)\n", label);
+ for (int v = 0; v < MAX_LD_PRELOADS; v++)
+ TprintfT (DBG_LT2, " %s sp_preloads[%d] (0x%p)=%s\n", label,
+ v, sp_preloads[v], (sp_preloads[v] == NULL ? "NULL" : sp_preloads[v]));
+ for (int v = 0; SP_ENV[v]; v++)
+ {
+ char *s = CALL_UTIL (getenv)(SP_ENV[v]);
+ if (s == NULL)
+ s = "<null>";
+ TprintfT (DBG_LT2, " %s SP_ENV[%d] (0x%p): %s=\"%s\"\n", label, v, SP_ENV[v], SP_ENV[v], s);
+ }
+ for (int v = 0; LD_ENV[v]; v++)
+ {
+ char *s = CALL_UTIL (getenv)(LD_ENV[v]);
+ if (s == NULL)
+ s = "<null>";
+ TprintfT (DBG_LT2, " %s LD_ENV[%d] (0x%p): %s=\"%s\"\n", label, v, LD_ENV[v], LD_ENV[v], s);
+ }
+#endif
+}
+
+void
+__collector_env_printall (char *label, char *envp[])
+{
+#if DEBUG
+ TprintfT (DBG_LT2, "__collector_env_printall(%s): environment @ 0x%p\n", label, envp);
+ for (int i = 0; envp[i]; i++)
+ Tprintf (DBG_LT2, "\tenv[%d]@0x%p == %s\n", i, envp[i], envp[i]);
+#endif
+}
+
+/* match collector environment variable */
+int
+env_match (char *envp[], const char *envvar)
+{
+ int match = -1;
+ if (envp == NULL)
+ TprintfT (DBG_LT1, "env_match(%s): NULL envp!\n", envvar);
+ else
+ {
+ int i = 0;
+ while ((envp[i] != NULL) && (__collector_strStartWith (envp[i], envvar)))
+ i++;
+ if ((envp[i] == NULL) || (envp[i][__collector_strlen (envvar)] != '='))
+ TprintfT (DBG_LT4, "env_match(): @%p []%s not defined in envp\n", envp, envvar);
+ else
+ {
+ TprintfT (DBG_LT4, "env_match(): @%p [%d]%s defined in envp\n", envp, i, envp[i]);
+ match = i;
+ }
+ }
+ TprintfT (DBG_LT1, "env_match(%s): found in slot %d\n", envvar, match);
+ return (match);
+}
+
+/* allocate new environment with collector variables */
+/* 1) copy all current envp[] ptrs into a new array, coll_env[] */
+/* 2) if collector-related env ptrs not in envp[], append them to coll_env */
+/* from processes' "environ" (allocate_env==1) */
+/* or from sp_env_backup (allocate_env==0)*/
+/* If they already exist in envp, probably is an error... */
+/* 3) return coll_env */
+
+/* __collector__env_update() need be called after this to set LD_ENV*/
+char **
+__collector_env_allocate (char *const old_env[], int allocate_env)
+{
+ extern char **environ; /* the process' actual environment */
+ char **new_env; /* a new environment for collection */
+ TprintfT (DBG_LT3, "__collector_env_allocate(old_env=0x%p %s environ=0x%p)\n",
+ old_env, (old_env == environ) ? "==" : "!=", environ);
+ /* set up a copy of the provided old_env for collector use */
+ int old_env_size = 0;
+
+ /* determine number of (used) slots in old_env */
+ if (old_env)
+ while (old_env[old_env_size] != NULL)
+ old_env_size++;
+ /* allocate a new vector with additional slots */
+ int new_env_alloc_sz = old_env_size + NUM_SP_ENV_VARS + NUM_LD_ENV_VARS + 1;
+ new_env = (char**) __collector_allocCSize (__collector_heap, new_env_alloc_sz * sizeof (char*), 1);
+ if (new_env == NULL)
+ return NULL;
+ TprintfT (DBG_LT4, "__collector_env_allocate(): old_env has %d entries, new_env @ 0x%p\n", old_env_size, new_env);
+
+ /* copy provided old_env pointers to new collector environment */
+ int new_env_size = 0;
+ for (new_env_size = 0; new_env_size < old_env_size; new_env_size++)
+ new_env[new_env_size] = old_env[new_env_size];
+
+ /* check each required environment variable, adding as required */
+ const char * env_var;
+ int v;
+ for (v = 0; (env_var = SP_ENV[v]) != NULL; v++)
+ {
+ if (env_match ((char**) old_env, env_var) == -1)
+ {
+ int idx;
+ /* not found in old_env */
+ if (allocate_env)
+ {
+ if ((idx = env_match (environ, env_var)) != -1)
+ {
+ /* found in environ */
+ TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
+ new_env_size, environ[idx]);
+ int varsz = __collector_strlen (environ[idx]) + 1;
+ char * var = (char*) __collector_allocCSize (__collector_heap, varsz, 1);
+ if (var == NULL)
+ return NULL;
+ __collector_strlcpy (var, environ[idx], varsz);
+ new_env[new_env_size++] = var;
+ }
+ else
+ {
+ /* not found in environ */
+ if ((__collector_strcmp (env_var, SP_COLLECTOR_PARAMS) == 0) ||
+ (__collector_strcmp (env_var, SP_COLLECTOR_EXPNAME) == 0))
+ TprintfT (DBG_LT1, "__collector_env_allocate(): note: %s environment variable not found\n",
+ env_var);
+ }
+ }
+ else
+ {
+ if ((idx = env_match (sp_env_backup, env_var)) != -1)
+ {
+ /* found in backup */
+ TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
+ new_env_size, sp_env_backup[idx]);
+ new_env[new_env_size++] = sp_env_backup[idx];
+ }
+ else
+ {
+ /* not found in environ */
+ if ((__collector_strcmp (env_var, SP_COLLECTOR_PARAMS) == 0) ||
+ (__collector_strcmp (env_var, SP_COLLECTOR_EXPNAME) == 0))
+ TprintfT (DBG_LT1, "__collector_env_allocate(): note: %s environment variable not found\n",
+ env_var);
+ }
+ }
+ }
+ }
+
+ for (v = 0; (env_var = LD_ENV[v]) != NULL; v++)
+ {
+ if (env_match ((char**) old_env, env_var) == -1)
+ {
+ int idx;
+ /* not found in old_env */
+ if (allocate_env)
+ {
+ if ((idx = env_match (environ, env_var)) != -1)
+ {
+ /* found in environ */
+ TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
+ new_env_size, environ[idx]);
+
+ int varsz = __collector_strlen (env_var) + 2;
+ char * var = (char*) __collector_allocCSize (__collector_heap, varsz, 1);
+ if (var == NULL)
+ return NULL;
+ // assume __collector_env_update() will fill content of env_var
+ CALL_UTIL (snprintf)(var, varsz, "%s=", env_var);
+ new_env[new_env_size++] = var;
+ }
+ }
+ else
+ {
+ if ((idx = env_match (sp_env_backup, env_var)) != -1)
+ {
+ /* found in backup */
+ TprintfT (DBG_LT4, "__collector_env_allocate(): [%d]%s env restored!\n",
+ new_env_size, sp_env_backup[idx]);
+ new_env[new_env_size++] = sp_env_backup[idx];
+ }
+ }
+ }
+ }
+
+ /* ensure new_env vector ends with NULL */
+ new_env[new_env_size] = NULL;
+ assert (new_env_size <= new_env_alloc_sz);
+ TprintfT (DBG_LT4, "__collector_env_allocate(): new_env has %d entries (%d added), new_env=0x%p\n",
+ new_env_size, new_env_size - old_env_size, new_env);
+ if (new_env_size != old_env_size && !allocate_env)
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%d</event>\n",
+ SP_JCMD_CWARN, COL_WARN_EXECENV, new_env_size - old_env_size);
+ __collector_env_printall ("__collector_env_allocate", new_env);
+ return (new_env);
+}
+
+/* unset collection environment variables */
+/* if they exist in env... */
+/* 1) push non-collectorized version to env */
+
+/* Not mt safe */
+void
+__collector_env_unset (char *envp[])
+{
+ int v;
+ const char * env_name;
+ TprintfT (DBG_LT3, "env_unset(envp=0x%p)\n", envp);
+ if (envp == NULL)
+ {
+ for (v = 0; (env_name = LD_PRELOAD[v]); v++)
+ {
+ const char *env_val = CALL_UTIL (getenv)(env_name);
+ if (env_val && CALL_UTIL (strstr)(env_val, sp_preloads[v]))
+ {
+ size_t sz = __collector_strlen (env_name) + 1 + __collector_strlen (env_val) + 1;
+ char * ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
+ if (ev == NULL)
+ return;
+ CALL_UTIL (snprintf)(ev, sz, "%s=%s", env_name, env_val);
+ assert (__collector_strlen (ev) + 1 == sz);
+ TprintfT (DBG_LT4, "env_unset(): old %s\n", ev);
+ env_ld_preload_strip (ev);
+ CALL_UTIL (putenv)(ev);
+ TprintfT (DBG_LT4, "env_unset(): new %s\n", ev);
+ }
+ }
+ // unset JAVA_TOOL_OPTIONS
+ env_name = JAVA_TOOL_OPTIONS;
+ const char * env_val = CALL_UTIL (getenv)(env_name);
+ if (env_val && CALL_UTIL (strstr)(env_val, COLLECTOR_JVMTI_OPTION))
+ {
+ size_t sz = __collector_strlen (env_name) + 1 + __collector_strlen (env_val) + 1;
+ char * ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
+ if (ev == NULL)
+ return;
+ CALL_UTIL (snprintf)(ev, sz, "%s=%s", env_name, env_val);
+ assert (__collector_strlen (ev) + 1 == sz);
+ TprintfT (DBG_LT4, "env_unset(): old %s\n", ev);
+ env_strip (ev, COLLECTOR_JVMTI_OPTION);
+ CALL_UTIL (putenv)(ev);
+ TprintfT (DBG_LT4, "env_unset(): new %s\n", ev);
+ }
+ __collector_env_print ("__collector_env_unset");
+ }
+ else
+ {
+ __collector_env_printall ("__collector_env_unset, before", envp);
+ for (v = 0; (env_name = LD_PRELOAD[v]); v++)
+ {
+ int idx = env_match (envp, env_name);
+ if (idx != -1)
+ {
+ char *env_val = envp[idx];
+ TprintfT (DBG_LT4, "env_unset(): old %s\n", env_val);
+ envp[idx] = "junk="; /* xxxx is it ok to use original string? */
+ env_ld_preload_strip (env_val);
+ envp[idx] = env_val;
+ TprintfT (DBG_LT4, "env_unset(): new %s\n", envp[idx]);
+ }
+ }
+ // unset JAVA_TOOL_OPTIONS
+ env_name = JAVA_TOOL_OPTIONS;
+ int idx = env_match(envp, env_name);
+ if (idx != -1) {
+ char *env_val = envp[idx];
+ TprintfT(DBG_LT4, "env_unset(): old %s\n", env_val);
+ envp[idx] = "junk="; /* xxxx is it ok to use original string? */
+ env_strip(env_val, COLLECTOR_JVMTI_OPTION);
+ envp[idx] = env_val;
+ TprintfT(DBG_LT4, "env_unset(): new %s\n", envp[idx]);
+ }
+ __collector_env_printall ("__collector_env_unset, after", envp );
+ }
+}
+
+/* update collection environment variables */
+/* update LD_PRELOADs and push them */
+/* not mt safe */
+void
+__collector_env_update (char *envp[])
+{
+ const char *env_name;
+ TprintfT (DBG_LT1, "__collector_env_update(envp=0x%p)\n", envp);
+ extern char **environ;
+ if (envp == NULL)
+ {
+ int v;
+ TprintfT (DBG_LT2, "__collector_env_update(envp=NULL)\n");
+ __collector_env_printall (" environ array, before", environ);
+ __collector_env_print (" env_update at entry ");
+
+ /* SP_ENV */
+ for (v = 0; (env_name = SP_ENV[v]) != NULL; v++)
+ {
+ if (env_match (environ, env_name) == -1)
+ {
+ int idx;
+ if ((idx = env_match (sp_env_backup, env_name)) != -1)
+ {
+ unsigned strsz = __collector_strlen (sp_env_backup[idx]) + 1;
+ char *ev = (char*) __collector_allocCSize (__collector_heap, strsz, 1);
+ CALL_UTIL (snprintf)(ev, strsz, "%s", sp_env_backup[idx]);
+ if (CALL_UTIL (putenv)(ev) != 0)
+ TprintfT (DBG_LT2, "__collector_env_update(): ERROR %s is not set!\n",
+ sp_env_backup[idx]);
+ }
+ }
+ }
+ __collector_env_print (" env_update after SP_ENV settings ");
+
+ /* LD_LIBRARY_PATH */
+ for (v = 0; (env_name = LD_LIBRARY_PATH[v]); v++)
+ /* assumes same index used between LD and SP vars */
+ if (putenv_prepend (env_name, sp_libpaths[v], ":"))
+ TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n",
+ env_name, sp_libpaths[v]);
+ __collector_env_print (" env_update after LD_LIBRARY_PATH settings ");
+
+ /* LD_PRELOAD */
+ for (v = 0; (env_name = LD_PRELOAD[v]); v++)
+ /* assumes same index used between LD and SP vars */
+ if (putenv_prepend (env_name, sp_preloads[v], " "))
+ TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n",
+ env_name, sp_preloads[v]);
+ __collector_env_print (" env_update after LD_PRELOAD settings ");
+
+ /* JAVA_TOOL_OPTIONS */
+ if (java_mode)
+ if (putenv_prepend (JAVA_TOOL_OPTIONS, COLLECTOR_JVMTI_OPTION, " "))
+ TprintfT (DBG_LT2, "collector: ERROR %s=%s could not be set\n",
+ JAVA_TOOL_OPTIONS, COLLECTOR_JVMTI_OPTION);
+ __collector_env_print (" env_update after JAVA_TOOL settings ");
+ }
+ else
+ {
+ int v;
+ int idx;
+ TprintfT (DBG_LT2, "__collector_env_update(envp=0x%p) not NULL\n", envp);
+ __collector_env_printall ("__collector_env_update, before", envp);
+ /* LD_LIBRARY_PATH */
+ for (v = 0; (env_name = LD_LIBRARY_PATH[v]); v++)
+ {
+ int idx = env_match (envp, env_name);
+ if (idx != -1)
+ {
+ char *env_val = __collector_strchr (envp[idx], '=');
+ if (env_val)
+ env_val++; /* skip '=' */
+ /* assumes same index used between LD and SP vars */
+ char *new_str = env_prepend (env_name, sp_libpaths[v],
+ ":", env_val);
+ if (new_str)
+ envp[idx] = new_str;
+ }
+ }
+
+ /* LD_PRELOAD */
+ for (v = 0; (env_name = LD_PRELOAD[v]); v++)
+ {
+ int idx = env_match (envp, env_name);
+ if (idx != -1)
+ {
+ char *env_val = __collector_strchr (envp[idx], '=');
+ if (env_val)
+ env_val++; /* skip '=' */
+ /* assumes same index used between LD and SP vars */
+ char *new_str = env_prepend (env_name, sp_preloads[v],
+ " ", env_val);
+ if (new_str)
+ envp[idx] = new_str;
+ }
+ }
+
+ /* JAVA_TOOL_OPTIONS */
+ if (java_mode)
+ {
+ env_name = JAVA_TOOL_OPTIONS;
+ idx = env_match (envp, env_name);
+ if (idx != -1)
+ {
+ char *env_val = __collector_strchr (envp[idx], '=');
+ if (env_val)
+ env_val++; /* skip '=' */
+ char *new_str = env_prepend (env_name, COLLECTOR_JVMTI_OPTION,
+ " ", env_val);
+ if (new_str)
+ envp[idx] = new_str;
+ }
+ }
+ }
+ __collector_env_printall ("__collector_env_update, after", environ);
+}
+
+
+/*------------------------------------------------------------- putenv */
+int putenv () __attribute__ ((weak, alias ("__collector_putenv")));
+int _putenv () __attribute__ ((weak, alias ("__collector_putenv")));
+
+int
+__collector_putenv (char * string)
+{
+ if (CALL_UTIL (putenv) == __collector_putenv ||
+ CALL_UTIL (putenv) == NULL)
+ { // __collector_libc_funcs_init failed
+ CALL_UTIL (putenv) = (int(*)())dlsym (RTLD_NEXT, "putenv");
+ if (CALL_UTIL (putenv) == NULL || CALL_UTIL (putenv) == __collector_putenv)
+ CALL_UTIL (putenv) = (int(*)())dlsym (RTLD_DEFAULT, "putenv");
+ if (CALL_UTIL (putenv) == NULL || CALL_UTIL (putenv) == __collector_putenv)
+ {
+ TprintfT (DBG_LT2, "__collector_putenv(): ERROR: no pointer found.\n");
+ errno = EBUSY;
+ return -1;
+ }
+ }
+ if (user_follow_mode == FOLLOW_NONE)
+ return CALL_UTIL (putenv)(string);
+ char * envp[] = {string, NULL};
+ __collector_env_update (envp);
+ return CALL_UTIL (putenv)(envp[0]);
+}
+
+/*------------------------------------------------------------- setenv */
+int setenv () __attribute__ ((weak, alias ("__collector_setenv")));
+int _setenv () __attribute__ ((weak, alias ("__collector_setenv")));
+
+int
+__collector_setenv (const char *name, const char *value, int overwrite)
+{
+ if (CALL_UTIL (setenv) == __collector_setenv ||
+ CALL_UTIL (setenv) == NULL)
+ { // __collector_libc_funcs_init failed
+ CALL_UTIL (setenv) = (int(*)())dlsym (RTLD_NEXT, "setenv");
+ if (CALL_UTIL (setenv) == NULL || CALL_UTIL (setenv) == __collector_setenv)
+ CALL_UTIL (setenv) = (int(*)())dlsym (RTLD_DEFAULT, "setenv");
+ if (CALL_UTIL (setenv) == NULL || CALL_UTIL (setenv) == __collector_setenv)
+ {
+ TprintfT (DBG_LT2, "__collector_setenv(): ERROR: no pointer found.\n");
+ errno = EBUSY;
+ return -1;
+ }
+ }
+ if (user_follow_mode == FOLLOW_NONE || !overwrite)
+ return CALL_UTIL (setenv)(name, value, overwrite);
+ size_t sz = __collector_strlen (name) + 1 + __collector_strlen (value) + 1;
+ char *ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
+ if (ev == NULL)
+ return CALL_UTIL (setenv)(name, value, overwrite);
+ CALL_UTIL (snprintf)(ev, sz, "%s=%s", name, value);
+ char * envp[] = {ev, NULL};
+ __collector_env_update (envp);
+ if (envp[0] == ev)
+ {
+ __collector_freeCSize (__collector_heap, ev, sz);
+ return CALL_UTIL (setenv)(name, value, overwrite);
+ }
+ else
+ {
+ char *env_val = __collector_strchr (envp[0], '=');
+ if (env_val)
+ {
+ *env_val = '\0';
+ env_val++; /* skip '=' */
+ }
+ return CALL_UTIL (setenv)(envp[0], env_val, overwrite);
+ }
+}
+
+/*------------------------------------------------------------- unsetenv */
+int unsetenv () __attribute__ ((weak, alias ("__collector_unsetenv")));
+int _unsetenv () __attribute__ ((weak, alias ("__collector_unsetenv")));
+
+int
+__collector_unsetenv (const char *name)
+{
+ if (CALL_UTIL (unsetenv) == __collector_unsetenv ||
+ CALL_UTIL (unsetenv) == NULL)
+ { // __collector_libc_funcs_init failed
+ CALL_UTIL (unsetenv) = (int(*)())dlsym (RTLD_NEXT, "unsetenv");
+ if (CALL_UTIL (unsetenv) == NULL || CALL_UTIL (unsetenv) == __collector_unsetenv)
+ CALL_UTIL (unsetenv) = (int(*)())dlsym (RTLD_DEFAULT, "unsetenv");
+ if (CALL_UTIL (unsetenv) == NULL || CALL_UTIL (unsetenv) == __collector_unsetenv)
+ {
+ TprintfT (DBG_LT2, "__collector_unsetenv(): ERROR: no pointer found.\n");
+ errno = EBUSY;
+ return -1;
+ }
+ }
+ int ret = CALL_UTIL (unsetenv)(name);
+ if (user_follow_mode == FOLLOW_NONE)
+ return ret;
+ TprintfT (DBG_LT2, "__collector_unsetenv(): %d.\n", user_follow_mode);
+ size_t sz = __collector_strlen (name) + 1 + 1;
+ char *ev = (char*) __collector_allocCSize (__collector_heap, sz, 1);
+ if (ev == NULL)
+ return ret;
+ CALL_UTIL (snprintf)(ev, sz, "%s=", name);
+ char * envp[] = {ev, NULL};
+ __collector_env_update (envp);
+ if (envp[0] == ev)
+ __collector_freeCSize (__collector_heap, ev, sz);
+ else
+ CALL_UTIL (putenv)(envp[0]);
+ return ret;
+}
+
+/*------------------------------------------------------------- clearenv */
+int clearenv () __attribute__ ((weak, alias ("__collector_clearenv")));
+
+int
+__collector_clearenv (void)
+{
+ if (CALL_UTIL (clearenv) == __collector_clearenv || CALL_UTIL (clearenv) == NULL)
+ {
+ /* __collector_libc_funcs_init failed; look up clearenv now */
+ CALL_UTIL (clearenv) = (int(*)())dlsym (RTLD_NEXT, "clearenv");
+ if (CALL_UTIL (clearenv) == NULL || CALL_UTIL (clearenv) == __collector_clearenv)
+ /* still not found; try again */
+ CALL_UTIL (clearenv) = (int(*)())dlsym (RTLD_DEFAULT, "clearenv");
+ if (CALL_UTIL (clearenv) == NULL || CALL_UTIL (clearenv) == __collector_clearenv)
+ {
+ /* still not found -- a fatal error */
+ TprintfT (DBG_LT2, "__collector_clearenv(): ERROR: %s\n", dlerror ());
+ CALL_UTIL (fprintf)(stderr, "__collector_clearenv(): ERROR: %s\n", dlerror ());
+ errno = EBUSY;
+ return -1;
+ }
+ }
+ int ret = CALL_UTIL (clearenv)();
+ if (user_follow_mode == FOLLOW_NONE)
+ return ret;
+ if (sp_env_backup == NULL)
+ {
+ TprintfT (DBG_LT2, "__collector_clearenv: ERROR sp_env_backup is not set!\n");
+ return ret;
+ }
+ for (int v = 0; v < NUM_SP_ENV_VARS + NUM_LD_ENV_VARS; v++)
+ if (sp_env_backup[v] && CALL_UTIL (putenv)(sp_env_backup[v]) != 0)
+ TprintfT (DBG_LT2, "__collector_clearenv: ERROR %s is not set!\n",
+ sp_env_backup[v]);
+ return ret;
+}
diff --git a/gprofng/libcollector/gethrtime.c b/gprofng/libcollector/gethrtime.c
new file mode 100644
index 0000000..f369cdc
--- /dev/null
+++ b/gprofng/libcollector/gethrtime.c
@@ -0,0 +1,41 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "config.h"
+#include <time.h>
+#include "gp-time.h"
+
+/*
+ * CLOCK_MONOTONIC
+ * Clock that cannot be set and represents monotonic time since some
+ * unspecified starting point.
+ */
+static hrtime_t
+linux_gethrtime ()
+{
+ struct timespec tp;
+ hrtime_t rc = 0;
+ int r = clock_gettime (CLOCK_MONOTONIC_RAW, &tp);
+ if (r == 0)
+ rc = ((hrtime_t) tp.tv_sec)*1000000000 + (hrtime_t) tp.tv_nsec;
+ return rc;
+}
+
+hrtime_t (*__collector_gethrtime)() = linux_gethrtime;
diff --git a/gprofng/libcollector/heaptrace.c b/gprofng/libcollector/heaptrace.c
new file mode 100644
index 0000000..470a269
--- /dev/null
+++ b/gprofng/libcollector/heaptrace.c
@@ -0,0 +1,503 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/*
+ * Heap tracing events
+ */
+
+#include "config.h"
+#include <dlfcn.h>
+
+#include "gp-defs.h"
+#include "collector_module.h"
+#include "gp-experiment.h"
+#include "data_pckts.h"
+#include "tsd.h"
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+#define DBG_LT4 4
+
+/* define the packets to be written out */
+typedef struct Heap_packet
+{ /* Malloc/free tracing packet */
+ Common_packet comm;
+ Heap_type mtype; /* subtype of packet */
+ Size_type size; /* size of malloc/realloc request */
+ Vaddr_type vaddr; /* vaddr given to free or returned from malloc/realloc */
+ Vaddr_type ovaddr; /* Previous vaddr given to realloc */
+} Heap_packet;
+
+static int init_heap_intf ();
+static int open_experiment (const char *);
+static int start_data_collection (void);
+static int stop_data_collection (void);
+static int close_experiment (void);
+static int detach_experiment (void);
+
+static ModuleInterface module_interface = {
+ SP_HEAPTRACE_FILE, /* description */
+ NULL, /* initInterface */
+ open_experiment, /* openExperiment */
+ start_data_collection, /* startDataCollection */
+ stop_data_collection, /* stopDataCollection */
+ close_experiment, /* closeExperiment */
+ detach_experiment /* detachExperiment (fork child) */
+};
+
+static CollectorInterface *collector_interface = NULL;
+static int heap_mode = 0;
+static CollectorModule heap_hndl = COLLECTOR_MODULE_ERR;
+static unsigned heap_key = COLLECTOR_TSD_INVALID_KEY;
+
+#define CHCK_REENTRANCE(x) ( !heap_mode || ((x) = collector_interface->getKey( heap_key )) == NULL || (*(x) != 0) )
+#define PUSH_REENTRANCE(x) ((*(x))++)
+#define POP_REENTRANCE(x) ((*(x))--)
+#define CALL_REAL(x) (__real_##x)
+#define NULL_PTR(x) (__real_##x == NULL)
+#define gethrtime collector_interface->getHiResTime
+
+#ifdef DEBUG
+#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
+#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
+#else
+#define Tprintf(...)
+#define TprintfT(...)
+#endif
+
+static void *(*__real_malloc)(size_t) = NULL;
+static void (*__real_free)(void *);
+static void *(*__real_realloc)(void *, size_t);
+static void *(*__real_memalign)(size_t, size_t);
+static void *(*__real_calloc)(size_t, size_t);
+static void *(*__real_valloc)(size_t);
+static char *(*__real_strchr)(const char *, int);
+
+void *__libc_malloc (size_t);
+void __libc_free (void *);
+void *__libc_realloc (void *, size_t);
+
+static void
+collector_memset (void *s, int c, size_t n)
+{
+ unsigned char *s1 = s;
+ while (n--)
+ *s1++ = (unsigned char) c;
+}
+
+void
+__collector_module_init (CollectorInterface *_collector_interface)
+{
+ if (_collector_interface == NULL)
+ return;
+ collector_interface = _collector_interface;
+ Tprintf (0, "heaptrace: __collector_module_init\n");
+ heap_hndl = collector_interface->registerModule (&module_interface);
+
+ /* Initialize next module */
+ ModuleInitFunc next_init = (ModuleInitFunc) dlsym (RTLD_NEXT, "__collector_module_init");
+ if (next_init != NULL)
+ next_init (_collector_interface);
+ return;
+}
+
+static int
+open_experiment (const char *exp)
+{
+ if (collector_interface == NULL)
+ {
+ Tprintf (0, "heaptrace: collector_interface is null.\n");
+ return COL_ERROR_HEAPINIT;
+ }
+ if (heap_hndl == COLLECTOR_MODULE_ERR)
+ {
+ Tprintf (0, "heaptrace: handle create failed.\n");
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_HEAPINIT);
+ return COL_ERROR_HEAPINIT;
+ }
+ TprintfT (0, "heaptrace: open_experiment %s\n", exp);
+ if (NULL_PTR (malloc))
+ init_heap_intf ();
+
+ const char *params = collector_interface->getParams ();
+ while (params)
+ {
+ if ((params[0] == 'H') && (params[1] == ':'))
+ {
+ params += 2;
+ break;
+ }
+ params = CALL_REAL (strchr)(params, ';');
+ if (params)
+ params++;
+ }
+ if (params == NULL) /* Heap data collection not specified */
+ return COL_ERROR_HEAPINIT;
+
+ heap_key = collector_interface->createKey (sizeof ( int), NULL, NULL);
+ if (heap_key == (unsigned) - 1)
+ {
+ Tprintf (0, "heaptrace: TSD key create failed.\n");
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_HEAPINIT);
+ return COL_ERROR_HEAPINIT;
+ }
+ collector_interface->writeLog ("<profile name=\"%s\">\n", SP_JCMD_HEAPTRACE);
+ collector_interface->writeLog (" <profdata fname=\"%s\"/>\n",
+ module_interface.description);
+
+ /* Record Heap_packet description */
+ Heap_packet *pp = NULL;
+ collector_interface->writeLog (" <profpckt kind=\"%d\" uname=\"Heap tracing data\">\n", HEAP_PCKT);
+ collector_interface->writeLog (" <field name=\"LWPID\" uname=\"Lightweight process id\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"THRID\" uname=\"Thread number\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"CPUID\" uname=\"CPU id\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"High resolution timestamp\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"HTYPE\" uname=\"Heap trace function type\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->mtype, sizeof (pp->mtype) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"HSIZE\" uname=\"Memory size\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->size, sizeof (pp->size) == 4 ? "UINT32" : "UINT64");
+ collector_interface->writeLog (" <field name=\"HVADDR\" uname=\"Memory address\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->vaddr, sizeof (pp->vaddr) == 4 ? "UINT32" : "UINT64");
+ collector_interface->writeLog (" <field name=\"HOVADDR\" uname=\"Previous memory address\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->ovaddr, sizeof (pp->ovaddr) == 4 ? "UINT32" : "UINT64");
+ collector_interface->writeLog (" </profpckt>\n");
+ collector_interface->writeLog ("</profile>\n");
+ return COL_ERROR_NONE;
+}
+
+static int
+start_data_collection (void)
+{
+ heap_mode = 1;
+ Tprintf (0, "heaptrace: start_data_collection\n");
+ return 0;
+}
+
+static int
+stop_data_collection (void)
+{
+ heap_mode = 0;
+ Tprintf (0, "heaptrace: stop_data_collection\n");
+ return 0;
+}
+
+static int
+close_experiment (void)
+{
+ heap_mode = 0;
+ heap_key = COLLECTOR_TSD_INVALID_KEY;
+ Tprintf (0, "heaptrace: close_experiment\n");
+ return 0;
+}
+
+static int
+detach_experiment (void)
+/* fork child. Clean up state but don't write to experiment */
+{
+ heap_mode = 0;
+ heap_key = COLLECTOR_TSD_INVALID_KEY;
+ Tprintf (0, "heaptrace: detach_experiment\n");
+ return 0;
+}
+
+static int in_init_heap_intf = 0; // Flag that we are in init_heap_intf()
+
+static int
+init_heap_intf ()
+{
+ void *dlflag;
+ in_init_heap_intf = 1;
+ __real_malloc = (void*(*)(size_t))dlsym (RTLD_NEXT, "malloc");
+ if (__real_malloc == NULL)
+ {
+ /* We are probably dlopened after libthread/libc,
+ * try to search in the previously loaded objects
+ */
+ __real_malloc = (void*(*)(size_t))dlsym (RTLD_DEFAULT, "malloc");
+ if (__real_malloc == NULL)
+ {
+ Tprintf (0, "heaptrace: ERROR: real malloc not found\n");
+ in_init_heap_intf = 0;
+ return 1;
+ }
+ Tprintf (DBG_LT1, "heaptrace: real malloc found with RTLD_DEFAULT\n");
+ dlflag = RTLD_DEFAULT;
+ }
+ else
+ {
+ Tprintf (DBG_LT1, "heaptrace: real malloc found with RTLD_NEXT\n");
+ dlflag = RTLD_NEXT;
+ }
+ __real_free = (void(*)(void *))dlsym (dlflag, "free");
+ __real_realloc = (void*(*)(void *, size_t))dlsym (dlflag, "realloc");
+ __real_memalign = (void*(*)(size_t, size_t))dlsym (dlflag, "memalign");
+ __real_calloc = (void*(*)(size_t, size_t))dlsym (dlflag, "calloc");
+ __real_valloc = (void*(*)(size_t))dlsym (dlflag, "valloc");
+ __real_strchr = (char*(*)(const char *, int))dlsym (dlflag, "strchr");
+ Tprintf (0, "heaptrace: init_heap_intf done\n");
+ in_init_heap_intf = 0;
+ return 0;
+}
+
+/*------------------------------------------------------------- malloc */
+
+void *
+malloc (size_t size)
+{
+ void *ret;
+ int *guard;
+ Heap_packet hpacket;
+ /* Linux startup workaround */
+ if (!heap_mode)
+ {
+ void *ppp = (void *) __libc_malloc (size);
+ Tprintf (DBG_LT4, "heaptrace: LINUX malloc(%ld, %p)...\n", (long) size, ppp);
+ return ppp;
+ }
+ if (NULL_PTR (malloc))
+ init_heap_intf ();
+ if (CHCK_REENTRANCE (guard))
+ {
+ ret = (void *) CALL_REAL (malloc)(size);
+ Tprintf (DBG_LT4, "heaptrace: real malloc(%ld) = %p\n", (long) size, ret);
+ return ret;
+ }
+ PUSH_REENTRANCE (guard);
+
+ ret = (void *) CALL_REAL (malloc)(size);
+ collector_memset (&hpacket, 0, sizeof ( Heap_packet));
+ hpacket.comm.tsize = sizeof ( Heap_packet);
+ hpacket.comm.tstamp = gethrtime ();
+ hpacket.mtype = MALLOC_TRACE;
+ hpacket.size = (Size_type) size;
+ hpacket.vaddr = (Vaddr_type) ret;
+ hpacket.ovaddr = (Vaddr_type) 0;
+ hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
+ collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
+ POP_REENTRANCE (guard);
+ return (void *) ret;
+}
+
+/*------------------------------------------------------------- free */
+
+void
+free (void *ptr)
+{
+ int *guard;
+ Heap_packet hpacket;
+ /* Linux startup workaround */
+ if (!heap_mode)
+ {
+ // Tprintf(DBG_LT4,"heaptrace: LINUX free(%p)...\n",ptr);
+ __libc_free (ptr);
+ return;
+ }
+ if (NULL_PTR (malloc))
+ init_heap_intf ();
+ if (CHCK_REENTRANCE (guard))
+ {
+ CALL_REAL (free)(ptr);
+ return;
+ }
+ if (ptr == NULL)
+ return;
+ PUSH_REENTRANCE (guard);
+
+ /* Get a timestamp before 'free' to enforce consistency */
+ hrtime_t ts = gethrtime ();
+ CALL_REAL (free)(ptr);
+ collector_memset (&hpacket, 0, sizeof ( Heap_packet));
+ hpacket.comm.tsize = sizeof ( Heap_packet);
+ hpacket.comm.tstamp = ts;
+ hpacket.mtype = FREE_TRACE;
+ hpacket.size = (Size_type) 0;
+ hpacket.vaddr = (Vaddr_type) ptr;
+ hpacket.ovaddr = (Vaddr_type) 0;
+ hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
+ collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
+ POP_REENTRANCE (guard);
+ return;
+}
+
+/*------------------------------------------------------------- realloc */
+void *
+realloc (void *ptr, size_t size)
+{
+ void *ret;
+ int *guard;
+ Heap_packet hpacket;
+
+ /* Linux startup workaround */
+ if (!heap_mode)
+ {
+ void * ppp = (void *) __libc_realloc (ptr, size);
+ Tprintf (DBG_LT4, "heaptrace: LINUX realloc(%ld, %p->%p)...\n",
+ (long) size, ptr, ppp);
+ return ppp;
+ }
+ if (NULL_PTR (realloc))
+ init_heap_intf ();
+ if (CHCK_REENTRANCE (guard))
+ {
+ ret = (void *) CALL_REAL (realloc)(ptr, size);
+ return ret;
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t ts = gethrtime ();
+ ret = (void *) CALL_REAL (realloc)(ptr, size);
+ collector_memset (&hpacket, 0, sizeof ( Heap_packet));
+ hpacket.comm.tsize = sizeof ( Heap_packet);
+ hpacket.comm.tstamp = ts;
+ hpacket.mtype = REALLOC_TRACE;
+ hpacket.size = (Size_type) size;
+ hpacket.vaddr = (Vaddr_type) ret;
+ hpacket.ovaddr = (Vaddr_type) ptr;
+ hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
+ collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
+ POP_REENTRANCE (guard);
+ return (void *) ret;
+}
+
+/*------------------------------------------------------------- memalign */
+void *
+memalign (size_t align, size_t size)
+{
+ void *ret;
+ int *guard;
+ Heap_packet hpacket;
+ if (NULL_PTR (memalign))
+ init_heap_intf ();
+ if (CHCK_REENTRANCE (guard))
+ {
+ ret = (void *) CALL_REAL (memalign)(align, size);
+ return ret;
+ }
+ PUSH_REENTRANCE (guard);
+ ret = (void *) CALL_REAL (memalign)(align, size);
+ collector_memset (&hpacket, 0, sizeof ( Heap_packet));
+ hpacket.comm.tsize = sizeof ( Heap_packet);
+ hpacket.comm.tstamp = gethrtime ();
+ hpacket.mtype = MALLOC_TRACE;
+ hpacket.size = (Size_type) size;
+ hpacket.vaddr = (Vaddr_type) ret;
+ hpacket.ovaddr = (Vaddr_type) 0;
+ hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
+ collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- valloc */
+
+void *
+valloc (size_t size)
+{
+ void *ret;
+ int *guard;
+ Heap_packet hpacket;
+ if (NULL_PTR (memalign))
+ init_heap_intf ();
+ if (CHCK_REENTRANCE (guard))
+ {
+ ret = (void *) CALL_REAL (valloc)(size);
+ return ret;
+ }
+ PUSH_REENTRANCE (guard);
+ ret = (void *) CALL_REAL (valloc)(size);
+ collector_memset (&hpacket, 0, sizeof ( Heap_packet));
+ hpacket.comm.tsize = sizeof ( Heap_packet);
+ hpacket.comm.tstamp = gethrtime ();
+ hpacket.mtype = MALLOC_TRACE;
+ hpacket.size = (Size_type) size;
+ hpacket.vaddr = (Vaddr_type) ret;
+ hpacket.ovaddr = (Vaddr_type) 0;
+ hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
+ collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- calloc */
+void *
+calloc (size_t size, size_t esize)
+{
+ void *ret;
+ int *guard;
+ Heap_packet hpacket;
+ if (NULL_PTR (calloc))
+ {
+ if (in_init_heap_intf != 0)
+ return NULL; // Terminate infinite loop
+ init_heap_intf ();
+ }
+ if (CHCK_REENTRANCE (guard))
+ {
+ ret = (void *) CALL_REAL (calloc)(size, esize);
+ return ret;
+ }
+ PUSH_REENTRANCE (guard);
+ ret = (void *) CALL_REAL (calloc)(size, esize);
+ collector_memset (&hpacket, 0, sizeof ( Heap_packet));
+ hpacket.comm.tsize = sizeof ( Heap_packet);
+ hpacket.comm.tstamp = gethrtime ();
+ hpacket.mtype = MALLOC_TRACE;
+ hpacket.size = (Size_type) (size * esize);
+ hpacket.vaddr = (Vaddr_type) ret;
+ hpacket.ovaddr = (Vaddr_type) 0;
+ hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
+ collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/* __collector_heap_record is used to record java allocations/deallocations.
+ * It uses the same facilities as regular heap tracing for now.
+ */
+void
+__collector_heap_record (int mtype, size_t size, void *vaddr)
+{
+ int *guard;
+ Heap_packet hpacket;
+ if (CHCK_REENTRANCE (guard))
+ return;
+ PUSH_REENTRANCE (guard);
+ collector_memset (&hpacket, 0, sizeof ( Heap_packet));
+ hpacket.comm.tsize = sizeof ( Heap_packet);
+ hpacket.comm.tstamp = gethrtime ();
+ hpacket.mtype = mtype;
+ hpacket.size = (Size_type) size;
+ hpacket.vaddr = (Vaddr_type) vaddr;
+ hpacket.ovaddr = (Vaddr_type) 0;
+ hpacket.comm.frinfo = collector_interface->getFrameInfo (heap_hndl, hpacket.comm.tstamp, FRINFO_FROM_STACK, &hpacket);
+ collector_interface->writeDataRecord (heap_hndl, (Common_packet*) & hpacket);
+ POP_REENTRANCE (guard);
+ return;
+}
diff --git a/gprofng/libcollector/hwprofile.c b/gprofng/libcollector/hwprofile.c
new file mode 100644
index 0000000..6fdaf1b
--- /dev/null
+++ b/gprofng/libcollector/hwprofile.c
@@ -0,0 +1,905 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/* Hardware counter profiling */
+
+#include "config.h"
+#include <alloca.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/syscall.h>
+#include <signal.h>
+#include <ucontext.h>
+
+#include "gp-defs.h"
+#define _STRING_H 1 /* XXX MEZ: temporary workaround */
+#include "hwcdrv.h"
+#include "collector_module.h"
+#include "gp-experiment.h"
+#include "libcol_util.h"
+#include "hwprofile.h"
+#include "ABS.h"
+#include "tsd.h"
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+#define DBG_LT4 4
+#define DBG_LT5 5
+
+#define SD_OFF 0 /* before start or after close she shut down process */
+#define SD_PENDING 1 /* before running real_detach_experiment() */
+#define SD_COMPLETE 2 /* after running real_detach_experiment() */
+
+static int init_interface (CollectorInterface*);
+static int open_experiment (const char *);
+static int start_data_collection (void);
+static int stop_data_collection (void);
+static int close_experiment (void);
+static int detach_experiment (void);
+static int real_detach_experiment (void);
+
+static ModuleInterface module_interface ={
+ SP_HWCNTR_FILE, /* description */
+ init_interface, /* initInterface */
+ open_experiment, /* openExperiment */
+ start_data_collection, /* startDataCollection */
+ stop_data_collection, /* stopDataCollection */
+ close_experiment, /* closeExperiment */
+ detach_experiment /* detachExperiment (fork child) */
+};
+
+static CollectorInterface *collector_interface = NULL;
+
+
+/*---------------------------------------------------------------------------*/
+/* compile options and workarounds */
+
+/* Solaris: We set ITIMER_REALPROF to ensure that counters get started on
+ * LWPs that existed before the collector initialization.
+ *
+ * In addition, if the appropriate #define's are set, we check for:
+ * lost-hw-overflow -- the HW counters rollover, but the overflow
+ * interrupt is not generated (counters keep running)
+ * lost-sigemt -- the interrupt is received by the kernel,
+ * which stops the counters, but the kernel fails
+ * to deliver the signal.
+ */
+
+/*---------------------------------------------------------------------------*/
+/* typedefs */
+
+typedef enum {
+ HWCMODE_OFF, /* before start or after close */
+ HWCMODE_SUSPEND, /* stop_data_collection called */
+ HWCMODE_ACTIVE, /* counters are defined and after start_data_collection() */
+ HWCMODE_ABORT /* fatal error occured. Log a message, stop recording */
+} hwc_mode_t;
+
+/*---------------------------------------------------------------------------*/
+/* prototypes */
+static void init_ucontexts (void);
+static int hwc_initialize_handlers (void);
+static void collector_record_counter (ucontext_t*,
+ int timecvt,
+ ABST_type, hrtime_t,
+ unsigned, uint64_t);
+static void collector_hwc_ABORT (int errnum, const char *msg);
+static void hwclogwrite0 ();
+static void hwclogwrite (Hwcentry *);
+static void set_hwc_mode (hwc_mode_t);
+static void collector_sigemt_handler (int sig, siginfo_t *si, void *puc);
+
+/*---------------------------------------------------------------------------*/
+/* static variables */
+
+/* --- user counter selections and options */
+static int hwcdef_has_memspace; /* true to indicate use of extened packets */
+static unsigned hwcdef_cnt; /* number of *active* hardware counters */
+static unsigned hwcdef_num_sampling_ctrdefs; /* ctrs that use sampling */
+static unsigned hwcdef_num_overflow_ctrdefs; /* ctrs that use overflow */
+static Hwcentry **hwcdef; /* HWC definitions */
+static int cpcN_cpuver = CPUVER_UNDEFINED;
+static int hwcdrv_inited; /* Don't call hwcdrv_init() in fork_child */
+static hwcdrv_api_t *hwc_driver = NULL;
+static unsigned hwprofile_tsd_key = COLLECTOR_TSD_INVALID_KEY;
+static int hwprofile_tsd_sz = 0;
+static volatile hwc_mode_t hwc_mode = HWCMODE_OFF;
+static volatile unsigned int nthreads_in_sighandler = 0;
+static volatile unsigned int sd_state = SD_OFF;
+
+/* --- experiment logging state */
+static CollectorModule expr_hndl = COLLECTOR_MODULE_ERR;
+static ucontext_t expr_dummy_uc; // used for hacked "collector" frames
+static ucontext_t expr_out_of_range_uc; // used for "out-of-range" frames
+static ucontext_t expr_frozen_uc; // used for "frozen" frames
+static ucontext_t expr_nopc_uc; // used for not-program-related frames
+static ucontext_t expr_lostcounts_uc; // used for lost_counts frames
+
+/* --- signal handler state */
+static struct sigaction old_sigemt_handler; //overwritten in fork-child
+
+/*---------------------------------------------------------------------------*/
+/* macros */
+#define COUNTERS_ENABLED() (hwcdef_cnt)
+#define gethrtime collector_interface->getHiResTime
+
+#ifdef DEBUG
+#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
+#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
+#else
+#define Tprintf(...)
+#define TprintfT(...)
+#endif
+
+
+/*---------------------------------------------------------------------------*/
+
+/* Initialization routines */
+static hwcdrv_api_t *
+get_hwc_driver ()
+{
+ if (hwc_driver == NULL)
+ hwc_driver = __collector_get_hwcdrv ();
+ return hwc_driver;
+}
+
+static void init_module () __attribute__ ((constructor));
+static void
+init_module ()
+{
+ __collector_dlsym_guard = 1;
+ RegModuleFunc reg_module = (RegModuleFunc) dlsym (RTLD_DEFAULT, "__collector_register_module");
+ __collector_dlsym_guard = 0;
+ if (reg_module == NULL)
+ {
+ TprintfT (0, "hwprofile: init_module FAILED - reg_module = NULL\n");
+ return;
+ }
+ expr_hndl = reg_module (&module_interface);
+ if (expr_hndl == COLLECTOR_MODULE_ERR)
+ {
+ TprintfT (0, "hwprofile: ERROR: handle not created.\n");
+ if (collector_interface)
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_HWCINIT);
+ }
+}
+
+static int
+init_interface (CollectorInterface *_collector_interface)
+{
+ collector_interface = _collector_interface;
+ return COL_ERROR_NONE;
+}
+
+static void *
+hwprofile_get_tsd ()
+{
+ return collector_interface->getKey (hwprofile_tsd_key);
+}
+
+static int
+open_experiment (const char *exp)
+{
+ if (collector_interface == NULL)
+ {
+ TprintfT (0, "hwprofile: ERROR: collector_interface is null.\n");
+ return COL_ERROR_HWCINIT;
+ }
+ const char *params = collector_interface->getParams ();
+ while (params)
+ {
+ if (__collector_strStartWith (params, "h:*") == 0)
+ {
+ /* HWC counters set by default */
+ collector_interface->writeLog ("<%s %s=\"1\"/>\n",
+ SP_TAG_SETTING, SP_JCMD_HWC_DEFAULT);
+ params += 3;
+ break;
+ }
+ else if (__collector_strStartWith (params, "h:") == 0)
+ {
+ params += 2;
+ break;
+ }
+ params = CALL_UTIL (strchr)(params, ';');
+ if (params)
+ params++;
+ }
+ if (params == NULL) /* HWC profiling not specified */
+ return COL_ERROR_HWCINIT;
+ char *s = CALL_UTIL (strchr)(params, (int) ';');
+ int sz = s ? s - params : CALL_UTIL (strlen)(params);
+ char *defstring = (char*) alloca (sz + 1);
+ CALL_UTIL (strlcpy)(defstring, params, sz + 1);
+ TprintfT (0, "hwprofile: open_experiment %s -- %s\n", exp, defstring);
+
+ int err = COL_ERROR_NONE;
+ /* init counter library */
+ if (!hwcdrv_inited)
+ { /* do not call hwcdrv_init() from fork-child */
+ hwcdrv_inited = 1;
+ get_hwc_driver ();
+ if (hwc_driver->hwcdrv_init (collector_hwc_ABORT, &hwprofile_tsd_sz) == 0)
+ {
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring);
+ TprintfT (0, "hwprofile: ERROR: hwcfuncs_init() failed\n");
+ return COL_ERROR_HWCINIT;
+ }
+
+ if (hwc_driver->hwcdrv_enable_mt (hwprofile_get_tsd))
+ {
+ // It is OK to call hwcdrv_enable_mt() before tsd key is created
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring);
+ TprintfT (0, "hwprofile: ERROR: hwcdrv_enable_mt() failed\n");
+ return COL_ERROR_HWCINIT;
+ }
+
+ hwc_driver->hwcdrv_get_info (&cpcN_cpuver, NULL, NULL, NULL, NULL);
+ if (cpcN_cpuver < 0)
+ {
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring);
+ TprintfT (0, "hwprofile: ERROR: hwcdrv_get_info() failed\n");
+ return COL_ERROR_HWCINIT;
+ }
+ }
+
+ if (hwprofile_tsd_sz)
+ {
+ hwprofile_tsd_key = collector_interface->createKey (hwprofile_tsd_sz, NULL, NULL);
+ if (hwprofile_tsd_key == COLLECTOR_TSD_INVALID_KEY)
+ {
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_HWCINIT, defstring);
+ TprintfT (0, "hwprofile: ERROR: TSD createKey failed\n");
+ return COL_ERROR_HWCINIT;
+ }
+ }
+ hwcdef_cnt = 0;
+ hwcdef_has_memspace = 0;
+
+ /* create counters based on hwcdef[] */
+ err = __collector_hwcfuncs_bind_descriptor (defstring);
+ if (err)
+ {
+ err = err == HWCFUNCS_ERROR_HWCINIT ? COL_ERROR_HWCINIT : COL_ERROR_HWCARGS;
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
+ SP_JCMD_CERROR, err, defstring);
+ TprintfT (0, "hwprofile: ERROR: open_experiment() failed, RC=%d \n", err);
+ return err;
+ }
+
+ /* generate an array of counter structures for each requested counter */
+ hwcdef = __collector_hwcfuncs_get_ctrs (&hwcdef_cnt);
+ hwcdef_num_sampling_ctrdefs = hwcdef_num_overflow_ctrdefs = 0;
+ int idx;
+ for (idx = 0; idx < hwcdef_cnt; idx++)
+ {
+ if (HWCENTRY_USES_SAMPLING (hwcdef[idx]))
+ {
+ hwcdef_num_sampling_ctrdefs++;
+ }
+ else
+ {
+ hwcdef_num_overflow_ctrdefs++;
+ }
+ }
+
+ init_ucontexts ();
+
+ /* initialize the SIGEMT handler, and the periodic HWC checker */
+ err = hwc_initialize_handlers ();
+ if (err != COL_ERROR_NONE)
+ {
+ hwcdef_cnt = 0;
+ TprintfT (0, "hwprofile: ERROR: open_experiment() failed, RC=%d \n", err);
+ /* log written by hwc_initialize_handlers() */
+ return err;
+ }
+
+ for (idx = 0; idx < hwcdef_cnt; idx++)
+ if (ABST_BACKTRACK_ENABLED (hwcdef[idx]->memop))
+ hwcdef_has_memspace = 1;
+
+ /* record the hwc definitions in the log, based on the counter array */
+ hwclogwrite0 ();
+ for (idx = 0; idx < hwcdef_cnt; idx++)
+ hwclogwrite (hwcdef[idx]);
+ return COL_ERROR_NONE;
+}
+
+int
+__collector_ext_hwc_lwp_init ()
+{
+ return get_hwc_driver ()->hwcdrv_lwp_init ();
+}
+
+void
+__collector_ext_hwc_lwp_fini ()
+{
+ get_hwc_driver ()->hwcdrv_lwp_fini ();
+}
+
+int
+__collector_ext_hwc_lwp_suspend ()
+{
+ return get_hwc_driver ()->hwcdrv_lwp_suspend ();
+}
+
+int
+__collector_ext_hwc_lwp_resume ()
+{
+ return get_hwc_driver ()->hwcdrv_lwp_resume ();
+}
+
+/* Dummy routine, used to provide a context for non-program related profiles */
+void
+__collector_not_program_related () { }
+
+/* Dummy routine, used to provide a context for lost counts (perf_events) */
+void
+__collector_hwc_samples_lost () { }
+
+/* Dummy routine, used to provide a context */
+void
+__collector_hwcs_frozen () { }
+
+/* Dummy routine, used to provide a context */
+void
+__collector_hwcs_out_of_range () { }
+/* initialize some structures */
+static void
+init_ucontexts (void)
+{
+ /* initialize dummy context for "collector" frames */
+ getcontext (&expr_dummy_uc);
+ SETFUNCTIONCONTEXT (&expr_dummy_uc, NULL);
+
+ /* initialize dummy context for "out-of-range" frames */
+ getcontext (&expr_out_of_range_uc);
+ SETFUNCTIONCONTEXT (&expr_out_of_range_uc, &__collector_hwcs_out_of_range);
+
+ /* initialize dummy context for "frozen" frames */
+ getcontext (&expr_frozen_uc);
+ SETFUNCTIONCONTEXT (&expr_frozen_uc, &__collector_hwcs_frozen);
+
+ /* initialize dummy context for non-program-related frames */
+ getcontext (&expr_nopc_uc);
+ SETFUNCTIONCONTEXT (&expr_nopc_uc, &__collector_not_program_related);
+
+ /* initialize dummy context for lost-counts-related frames */
+ getcontext (&expr_lostcounts_uc);
+ SETFUNCTIONCONTEXT (&expr_lostcounts_uc, &__collector_hwc_samples_lost);
+}
+/* initialize the signal handler */
+static int
+hwc_initialize_handlers (void)
+{
+ /* install the signal handler for SIGEMT */
+ struct sigaction oact;
+ if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &oact) != 0)
+ {
+ TprintfT (0, "hwc_initialize_handlers(): ERROR: hwc_initialize_handlers(): __collector_sigaction() failed to get oact\n");
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">old handler could not be determined</event>\n", SP_JCMD_CERROR, COL_ERROR_HWCINIT);
+ return COL_ERROR_HWCINIT;
+ }
+ if (oact.sa_sigaction == collector_sigemt_handler)
+ {
+ /* signal handler is already in place; we are probably in a fork-child */
+ TprintfT (DBG_LT1, "hwc_initialize_handlers(): hwc_initialize_handlers() collector_sigemt_handler already installed\n");
+ }
+ else
+ {
+ /* set our signal handler */
+ struct sigaction c_act;
+ CALL_UTIL (memset)(&c_act, 0, sizeof c_act);
+ sigemptyset (&c_act.sa_mask);
+ sigaddset (&c_act.sa_mask, SIGPROF); /* block SIGPROF delivery in handler */
+ /* XXXX should probably also block sample_sig & pause_sig */
+ c_act.sa_sigaction = collector_sigemt_handler; /* note: used to set sa_handler instead */
+ c_act.sa_flags = SA_RESTART | SA_SIGINFO;
+ if (__collector_sigaction (HWCFUNCS_SIGNAL, &c_act, &old_sigemt_handler) != 0)
+ {
+ TprintfT (0, "hwc_initialize_handlers(): ERROR: hwc_initialize_handlers(): __collector_sigaction() failed to set cact\n");
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">event handler could not be installed</event>\n", SP_JCMD_CERROR, COL_ERROR_HWCINIT);
+ return COL_ERROR_HWCINIT;
+ }
+ }
+ return COL_ERROR_NONE;
+}
+
+static int
+close_experiment (void)
+{
+ /* note: stop_data_collection() should have already been called by
+ * collector_close_experiment()
+ */
+ if (!COUNTERS_ENABLED ())
+ return COL_ERROR_NONE;
+ detach_experiment ();
+
+ /* cpc or libperfctr may still generate sigemts for a while */
+ /* verify that SIGEMT handler is still installed */
+ /* (still required with sigaction interposition and management,
+ since interposition is not done for attach experiments)
+ */
+ struct sigaction curr;
+ if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &curr) == -1)
+ {
+ TprintfT (0, "hwprofile close_experiment: ERROR: hwc sigaction check failed: errno=%d\n", errno);
+ }
+ else if (curr.sa_sigaction != collector_sigemt_handler)
+ {
+ TprintfT (DBG_LT1, "hwprofile close_experiment: WARNING: collector sigemt handler replaced by 0x%p!\n", curr.sa_handler);
+ (void) collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">0x%p</event>\n",
+ SP_JCMD_CWARN, COL_WARN_SIGEMT, curr.sa_handler);
+ }
+ else
+ TprintfT (DBG_LT1, "hwprofile close_experiment: collector sigemt handler integrity verified!\n");
+ TprintfT (0, "hwprofile: close_experiment\n");
+ return 0;
+}
+
+static int
+detach_experiment (void)
+{
+ /* fork child. Clean up state but don't write to experiment */
+ /* note: stop_data_collection() has already been called by the fork_prologue */
+ // detach_experiment() can be called asynchronously
+ // from anywhere, even from within a sigemt handler
+ // via DBX detach.
+ // Important: stop_data_collection() _must_ be called
+ // before detach_experiment() is called.
+ if (!COUNTERS_ENABLED ())
+ return COL_ERROR_NONE;
+ TprintfT (0, "hwprofile: detach_experiment()\n");
+ if (SD_OFF != __collector_cas_32 (&sd_state, SD_OFF, SD_PENDING))
+ return 0;
+ // one and only one call should ever make it here here.
+ if (hwc_mode == HWCMODE_ACTIVE)
+ {
+ TprintfT (0, "hwprofile: ERROR: stop_data_collection() should have been called before detach_experiment()\n");
+ stop_data_collection ();
+ }
+
+ // Assumption: The only calls to sigemt_handler
+ // we should see at this point
+ // will be those that were already in-flight before
+ // stop_new_sigemts() was called.
+ if (nthreads_in_sighandler > 0)
+ {
+ // sigemt handlers should see
+ // SD_PENDING and should call real_detach_experiment()
+ // when the last handler is finished.
+ TprintfT (DBG_LT1, "hwprofile: detach in the middle of signal handler.\n");
+ return 0;
+ }
+
+ // If we get here, there should be no remaining
+ // sigemt handlers. However, we don't really know
+ // if there were ever any in flight, so call
+ // real_detach_experiment() here:
+ return real_detach_experiment (); // multiple calls to this OK
+}
+
+static int
+real_detach_experiment (void)
+{
+ /*multiple calls to this routine are OK.*/
+ if (SD_PENDING != __collector_cas_32 (&sd_state, SD_PENDING, SD_COMPLETE))
+ return 0;
+ // only the first caller to this routine should get here.
+ hwcdef_cnt = 0; /* since now deinstalled */
+ hwcdef = NULL;
+ set_hwc_mode (HWCMODE_OFF);
+ if (SD_COMPLETE != __collector_cas_32 (&sd_state, SD_COMPLETE, SD_OFF))
+ {
+ TprintfT (0, "hwprofile: ERROR: unexpected sd_state in real_detach_experiment()\n");
+ sd_state = SD_OFF;
+ }
+ hwprofile_tsd_key = COLLECTOR_TSD_INVALID_KEY;
+ TprintfT (DBG_LT0, "hwprofile: real_detach_experiment() detached from experiment.\n");
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/* Record counter values. */
+
+/* <value> should already be adjusted to be "zero-based" (counting up from 0).*/
+static void
+collector_record_counter_internal (ucontext_t *ucp, int timecvt,
+ ABST_type ABS_memop, hrtime_t time,
+ unsigned tag, uint64_t value, uint64_t pc,
+ uint64_t va, uint64_t latency,
+ uint64_t data_source)
+{
+ MHwcntr_packet pckt;
+ CALL_UTIL (memset)(&pckt, 0, sizeof ( MHwcntr_packet));
+ pckt.comm.tstamp = time;
+ pckt.tag = tag;
+ if (timecvt > 1)
+ {
+ if (HWCVAL_HAS_ERR (value))
+ {
+ value = HWCVAL_CLR_ERR (value);
+ value *= timecvt;
+ value = HWCVAL_SET_ERR (value);
+ }
+ else
+ value *= timecvt;
+ }
+ pckt.interval = value;
+ pckt.comm.type = HW_PCKT;
+ pckt.comm.tsize = sizeof (Hwcntr_packet);
+ TprintfT (DBG_LT4, "hwprofile: %llu sample %lld tag %u recorded\n",
+ (unsigned long long) time, (long long) value, tag);
+ if (ABS_memop == ABST_NOPC)
+ ucp = &expr_nopc_uc;
+ pckt.comm.frinfo = collector_interface->getFrameInfo (expr_hndl, pckt.comm.tstamp, FRINFO_FROM_UC, ucp);
+ collector_interface->writeDataRecord (expr_hndl, (Common_packet*) & pckt);
+}
+
+static void
+collector_record_counter (ucontext_t *ucp, int timecvt, ABST_type ABS_memop,
+ hrtime_t time, unsigned tag, uint64_t value)
+{
+ collector_record_counter_internal (ucp, timecvt, ABS_memop, time, tag, value,
+ HWCFUNCS_INVALID_U64, HWCFUNCS_INVALID_U64,
+ HWCFUNCS_INVALID_U64, HWCFUNCS_INVALID_U64);
+}
+
+
+/*---------------------------------------------------------------------------*/
+/* Signal handlers */
+
+/* SIGEMT -- relayed from libcpc, when the counter overflows */
+
+/* Generates the appropriate event or events, and resets the counters */
+static void
+collector_sigemt_handler (int sig, siginfo_t *si, void *puc)
+{
+ int rc;
+ hwc_event_t sample, lost_samples;
+ if (sig != HWCFUNCS_SIGNAL)
+ {
+ TprintfT (0, "hwprofile: ERROR: %s: unexpected signal %d\n", "collector_sigemt_handler", sig);
+ return;
+ }
+ if (!COUNTERS_ENABLED ())
+ { /* apparently deinstalled */
+ TprintfT (0, "hwprofile: WARNING: SIGEMT detected after close_experiment()\n");
+ /* kills future sigemts since hwcdrv_sighlr_restart() not called */
+ return;
+ }
+
+ /* Typically, we expect HWC overflow signals to come from the kernel: si_code > 0.
+ * On Linux, however, dbx might be "forwarding" a signal using tkill()/tgkill().
+ * For more information on what si_code values can be expected on Linux, check:
+ * cmn_components/Collector_Interface/hwcdrv_pcl.c hwcdrv_overflow()
+ * cmn_components/Collector_Interface/hwcdrv_perfctr.c hdrv_perfctr_overflow()
+ */
+ if (puc == NULL || si == NULL || (si->si_code <= 0 && si->si_code != SI_TKILL))
+ {
+ TprintfT (DBG_LT3, "hwprofile: collector_sigemt_handler SIG%02d\n", sig);
+ if (old_sigemt_handler.sa_handler == SIG_DFL)
+ __collector_SIGDFL_handler (HWCFUNCS_SIGNAL);
+ else if (old_sigemt_handler.sa_handler != SIG_IGN &&
+ old_sigemt_handler.sa_sigaction != &collector_sigemt_handler)
+ {
+ /* Redirect the signal to the previous signal handler */
+ (old_sigemt_handler.sa_sigaction)(sig, si, puc);
+ TprintfT (DBG_LT1, "hwprofile: collector_sigemt_handler SIG%02d redirected to original handler\n", sig);
+ }
+ return;
+ }
+ rc = get_hwc_driver ()->hwcdrv_overflow (si, &sample, &lost_samples);
+ if (rc)
+ {
+ /* hwcdrv_sighlr_restart() should not be called */
+ TprintfT (0, "hwprofile: ERROR: collector_sigemt_handler: hwcdrv_overflow() failed\n");
+ return;
+ }
+
+ if (hwc_mode == HWCMODE_ACTIVE)
+ {
+ /* record the event only if counters are active */
+ /* The following has been copied from dispatcher.c */
+#if ARCH(SPARC)
+ /* 23340823 signal handler third argument should point to a ucontext_t */
+ /* Convert sigcontext to ucontext_t on sparc-Linux */
+ ucontext_t uctxmem;
+ struct sigcontext *sctx = (struct sigcontext*) puc;
+ ucontext_t *uctx = &uctxmem;
+ uctx->uc_link = NULL;
+#if WSIZE(32)
+ uctx->uc_mcontext.gregs[REG_PC] = sctx->si_regs.pc;
+ __collector_memcpy (&uctx->uc_mcontext.gregs[3],
+ sctx->si_regs.u_regs,
+ sizeof (sctx->si_regs.u_regs));
+#else
+ uctx->uc_mcontext.mc_gregs[MC_PC] = sctx->sigc_regs.tpc;
+ __collector_memcpy (&uctx->uc_mcontext.mc_gregs[3],
+ sctx->sigc_regs.u_regs,
+ sizeof (sctx->sigc_regs.u_regs));
+#endif /* WSIZE() */
+#else
+ ucontext_t *uctx = (ucontext_t*) puc;
+#endif /* ARCH() */
+
+ for (int ii = 0; ii < hwcdef_cnt; ii++)
+ if (lost_samples.ce_pic[ii])
+ collector_record_counter (&expr_lostcounts_uc, hwcdef[ii]->timecvt,
+ hwcdef[ii]->memop, lost_samples.ce_hrt,
+ hwcdef[ii]->sort_order, lost_samples.ce_pic[ii]);
+ for (int ii = 0; ii < hwcdef_cnt; ii++)
+ if (sample.ce_pic[ii])
+ collector_record_counter (uctx, hwcdef[ii]->timecvt,
+ hwcdef[ii]->memop, sample.ce_hrt,
+ hwcdef[ii]->sort_order, sample.ce_pic[ii]);
+ }
+ rc = get_hwc_driver ()->hwcdrv_sighlr_restart (NULL);
+}
+/* SIGPROF -- not installed as handler, but
+ * __collector_ext_hwc_check: called by (SIGPROF) dispatcher.
+ * Periodical check of integrity of HWC count/signal mechanism,
+ * as required for various chip/system bugs/workarounds.
+ */
+void
+__collector_ext_hwc_check (siginfo_t *info, ucontext_t *vcontext) { }
+
+/*---------------------------------------------------------------------------*/
+int
+collector_sigemt_sigaction (const struct sigaction *nact,
+ struct sigaction *oact)
+{
+ struct sigaction oact_check;
+ /* Error codes and messages that refer to HWC are tricky.
+ * E.g., HWC profiling might not even be on; we might
+ * encounter an error here simply because the user is
+ * trying to set a handler for a signal that happens to
+ * be HWCFUNCS_SIGNAL, which we aren't even using.
+ */
+ if (__collector_sigaction (HWCFUNCS_SIGNAL, NULL, &oact_check) != 0)
+ {
+ TprintfT (0, "hwprofile: ERROR: collector_sigemt_sigaction(): request to set handler for signal %d, but check on existing handler failed\n", HWCFUNCS_SIGNAL);
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">old handler for signal %d could not be determined</event>\n", SP_JCMD_CERROR, COL_ERROR_HWCINIT, HWCFUNCS_SIGNAL);
+ return COL_ERROR_HWCINIT;
+ }
+
+ if (oact_check.sa_sigaction == collector_sigemt_handler)
+ {
+ /* dispatcher is in place, so nact/oact apply to old_sigemt_handler */
+ if (oact != NULL)
+ {
+ oact->sa_handler = old_sigemt_handler.sa_handler;
+ oact->sa_mask = old_sigemt_handler.sa_mask;
+ oact->sa_flags = old_sigemt_handler.sa_flags;
+ }
+ if (nact != NULL)
+ {
+ old_sigemt_handler.sa_handler = nact->sa_handler;
+ old_sigemt_handler.sa_mask = nact->sa_mask;
+ old_sigemt_handler.sa_flags = nact->sa_flags;
+ }
+ return COL_ERROR_NONE;
+ }
+ else /* no dispatcher in place, so just act like normal sigaction() */
+ return __collector_sigaction (HWCFUNCS_SIGNAL, nact, oact);
+}
+
+static void
+collector_hwc_ABORT (int errnum, const char *msg)
+{
+ TprintfT (0, "hwprofile: collector_hwc_ABORT: [%d] %s\n", errnum, msg);
+ if (hwc_mode == HWCMODE_ABORT) /* HWC collection already aborted! */
+ return;
+ set_hwc_mode (HWCMODE_ABORT); /* set global flag to disable handlers and indicate abort */
+
+ /* Write the error message to the experiment */
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s: errno=%d</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_HWCFAIL, msg, errnum);
+
+#ifdef REAL_DEBUG
+ abort ();
+#else
+ TprintfT (0, "hwprofile: Continuing without HWC collection...\n");
+#endif
+}
+
+static int
+start_data_collection (void)
+{
+ hwc_mode_t old_mode = hwc_mode;
+ if (!COUNTERS_ENABLED ())
+ return COL_ERROR_NONE;
+ TprintfT (0, "hwprofile: start_data_collection (hwc_mode=%d)\n", old_mode);
+ switch (old_mode)
+ {
+ case HWCMODE_OFF:
+ if (get_hwc_driver ()->hwcdrv_start ())
+ {
+ TprintfT (0, "hwprofile: ERROR: start_data_collection() failed in hwcdrv_start()\n");
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s: errno=%d</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_HWCFAIL,
+ "start_data_collection()", errno);
+ return COL_ERROR_HWCINIT;
+ }
+ set_hwc_mode (HWCMODE_ACTIVE); /* start handling events on signals */
+ break;
+ case HWCMODE_SUSPEND:
+ if (get_hwc_driver ()->hwcdrv_lwp_resume ())
+ {
+ TprintfT (0, "hwprofile: ERROR: start_data_collection() failed in hwcdrv_lwp_resume()\n");
+ /* ignore errors from lwp_resume() */
+ }
+ set_hwc_mode (HWCMODE_ACTIVE); /* start handling events on signals */
+ break;
+ default:
+ TprintfT (0, "hwprofile: ERROR: start_data_collection() invalid mode\n");
+ return COL_ERROR_HWCINIT;
+ }
+ return COL_ERROR_NONE;
+}
+
+static int
+stop_data_collection (void)
+{
+ hwc_mode_t old_mode = hwc_mode;
+ if (!COUNTERS_ENABLED ())
+ return COL_ERROR_NONE;
+ TprintfT (0, "hwprofile: stop_data_collection (hwc_mode=%d)\n", old_mode);
+ switch (old_mode)
+ {
+ case HWCMODE_SUSPEND:
+ return COL_ERROR_NONE;
+ case HWCMODE_ACTIVE:
+ set_hwc_mode (HWCMODE_SUSPEND); /* stop handling signals */
+ break;
+ default:
+ /* Don't change the mode, but attempt to suspend anyway... */
+ break;
+ }
+
+ if (get_hwc_driver ()->hwcdrv_lwp_suspend ())
+ /* ignore errors from lwp_suspend() */
+ TprintfT (0, "hwprofile: ERROR: stop_data_collection() failed in hwcdrv_lwp_suspend()\n");
+
+ /*
+ * hwcdrv_lwp_suspend() cannot guarantee that all SIGEMTs will stop
+ * but hwc_mode will prevent logging and counters will overflow once
+ * then stay frozen.
+ */
+ /* There may still be pending SIGEMTs so don't reset the SIG_DFL handler.
+ */
+ /* see comment in dispatcher.c */
+ /* ret = __collector_sigaction( SIGEMT, &old_sigemt_handler, NULL ); */
+ return COL_ERROR_NONE;
+}
+
+/*---------------------------------------------------------------------------*/
+
+/* utilities */
+static void
+set_hwc_mode (hwc_mode_t md)
+{
+ TprintfT (DBG_LT1, "hwprofile: set_hwc_mode(%d)\n", md);
+ hwc_mode = md;
+}
+
+int
+__collector_ext_hwc_active ()
+{
+ return (hwc_mode == HWCMODE_ACTIVE);
+}
+
+static void
+hwclogwrite0 ()
+{
+ collector_interface->writeLog ("<profdata fname=\"%s\"/>\n",
+ module_interface.description);
+ /* Record Hwcntr_packet description */
+ Hwcntr_packet *pp = NULL;
+ collector_interface->writeLog ("<profpckt kind=\"%d\" uname=\"" STXT ("Hardware counter profiling data") "\">\n", HW_PCKT);
+ collector_interface->writeLog (" <field name=\"LWPID\" uname=\"" STXT ("Lightweight process id") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"THRID\" uname=\"" STXT ("Thread number") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"CPUID\" uname=\"" STXT ("CPU id") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"" STXT ("High resolution timestamp") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"HWCTAG\" uname=\"" STXT ("Hardware counter index") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->tag, sizeof (pp->tag) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"HWCINT\" uname=\"" STXT ("Hardware counter interval") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->interval, sizeof (pp->interval) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog ("</profpckt>\n");
+ if (hwcdef_has_memspace)
+ {
+ /* Record MHwcntr_packet description */
+ MHwcntr_packet *xpp = NULL;
+ collector_interface->writeLog ("<profpckt kind=\"%d\" uname=\"" STXT ("Hardware counter profiling data") "\">\n", MHWC_PCKT);
+ collector_interface->writeLog (" <field name=\"LWPID\" uname=\"" STXT ("Lightweight process id") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->comm.lwp_id, sizeof (xpp->comm.lwp_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"THRID\" uname=\"" STXT ("Thread number") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->comm.thr_id, sizeof (xpp->comm.thr_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"CPUID\" uname=\"" STXT ("CPU id") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->comm.cpu_id, sizeof (xpp->comm.cpu_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"" STXT ("High resolution timestamp") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->comm.tstamp, sizeof (xpp->comm.tstamp) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->comm.frinfo, sizeof (xpp->comm.frinfo) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"HWCTAG\" uname=\"" STXT ("Hardware counter index") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->tag, sizeof (xpp->tag) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"HWCINT\" uname=\"" STXT ("Hardware counter interval") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->interval, sizeof (xpp->interval) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"VADDR\" uname=\"" STXT ("Virtual address (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->ea_vaddr, sizeof (xpp->ea_vaddr) == 4 ? "UINT32" : "UINT64");
+ collector_interface->writeLog (" <field name=\"PADDR\" uname=\"" STXT ("Physical address (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->ea_paddr, sizeof (xpp->ea_paddr) == 4 ? "UINT32" : "UINT64");
+ collector_interface->writeLog (" <field name=\"VIRTPC\" uname=\"" STXT ("Virtual address (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->pc_vaddr, sizeof (xpp->pc_vaddr) == 4 ? "UINT32" : "UINT64");
+ collector_interface->writeLog (" <field name=\"PHYSPC\" uname=\"" STXT ("Physical address (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->pc_paddr, sizeof (xpp->pc_paddr) == 4 ? "UINT32" : "UINT64");
+ collector_interface->writeLog (" <field name=\"EA_PAGESIZE\" uname=\"" STXT ("Page size (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->ea_pagesz, sizeof (xpp->ea_pagesz) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"PC_PAGESIZE\" uname=\"" STXT ("Page size (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->pc_pagesz, sizeof (xpp->pc_pagesz) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"EA_LGRP\" uname=\"" STXT ("Page locality group (data)") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->ea_lgrp, sizeof (xpp->ea_lgrp) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"PC_LGRP\" uname=\"" STXT ("Page locality group (instruction)") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->pc_lgrp, sizeof (xpp->pc_lgrp) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"LWP_LGRP_HOME\" uname=\"" STXT ("LWP home lgroup id") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->lgrp_lwp, sizeof (xpp->lgrp_lwp) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"PS_LGRP_HOME\" uname=\"" STXT ("Process home lgroup id") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->lgrp_ps, sizeof (xpp->lgrp_ps) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"MEM_LAT\" uname=\"" STXT ("Memory Latency Cycles") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->latency, sizeof (xpp->latency) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"MEM_SRC\" uname=\"" STXT ("Memory Data Source") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &xpp->data_source, sizeof (xpp->data_source) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog ("</profpckt>\n");
+ }
+}
+
+static void
+hwclogwrite (Hwcentry * ctr)
+{
+ TprintfT (DBG_LT1, "hwprofile: writeLog(%s %u %s %d %u %d)\n",
+ SP_JCMD_HW_COUNTER, cpcN_cpuver, ctr->name ? ctr->name : "NULL",
+ ctr->val, ctr->sort_order, ctr->memop);
+ collector_interface->writeLog ("<profile name=\"%s\"", SP_JCMD_HW_COUNTER);
+ collector_interface->writeLog (" cpuver=\"%u\"", cpcN_cpuver);
+ collector_interface->writeLog (" hwcname=\"%s\"", ctr->name);
+ collector_interface->writeLog (" int_name=\"%s\"", ctr->int_name);
+ collector_interface->writeLog (" interval=\"%d\"", ctr->val);
+ collector_interface->writeLog (" tag=\"%u\"", ctr->sort_order);
+ collector_interface->writeLog (" memop=\"%d\"", ctr->memop);
+ collector_interface->writeLog ("/>\n");
+}
diff --git a/gprofng/libcollector/hwprofile.h b/gprofng/libcollector/hwprofile.h
new file mode 100644
index 0000000..4d01bf1
--- /dev/null
+++ b/gprofng/libcollector/hwprofile.h
@@ -0,0 +1,89 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#ifndef _HWPROFILE_H
+#define _HWPROFILE_H
+
+#include <data_pckts.h>
+
+typedef struct Hwcntr_packet
+{ /* HW counter profiling packet */
+ Common_packet comm;
+ uint32_t tag; /* hw counter index, register */
+ uint64_t interval; /* overflow value */
+} Hwcntr_packet;
+
+typedef struct MHwcntr_packet
+{ /* extended (superset) Hwcntr_packet */
+ Common_packet comm;
+ uint32_t tag; /* hw counter index, register */
+ uint64_t interval; /* overflow value */
+ Vaddr_type ea_vaddr; /* virtual addr causing HWC event */
+ Vaddr_type pc_vaddr; /* candidate eventPC */
+ uint64_t ea_paddr; /* physical address for ea_vaddr */
+ uint64_t pc_paddr; /* physical address for pc_vaddr */
+ uint64_t ea_pagesz; /* pagesz (bytes) for ea_paddr */
+ uint64_t pc_pagesz; /* pagesz (bytes) for pc_paddr */
+ uint32_t ea_lgrp; /* latency group of ea_paddr */
+ uint32_t pc_lgrp; /* latency group of pc_paddr */
+ uint32_t lgrp_lwp; /* locality group of lwp */
+ uint32_t lgrp_ps; /* locality group of process */
+ uint64_t latency; /* latency in cycles (sampling only) */
+ uint64_t data_source; /* data source (sampling only) */
+} MHwcntr_packet;
+
+#if ARCH(SPARC)
+#define CONTEXT_PC MC_PC
+#define CONTEXT_SP MC_O6
+#define CONTEXT_FP MC_O7
+#define SETFUNCTIONCONTEXT(ucp,funcp) \
+ (ucp)->uc_mcontext.gregs[CONTEXT_PC] = (greg_t)(funcp); \
+ (ucp)->uc_mcontext.gregs[CONTEXT_SP] = 0; \
+ (ucp)->uc_mcontext.gregs[CONTEXT_FP] = 0;
+
+#elif ARCH(Intel)
+#include <sys/reg.h>
+
+#if WSIZE(64)
+#define CONTEXT_PC REG_RIP
+#define CONTEXT_FP REG_RBP
+#define CONTEXT_SP REG_RSP
+
+#elif WSIZE(32)
+#define CONTEXT_PC REG_EIP
+#define CONTEXT_FP REG_EBP
+#define CONTEXT_SP REG_ESP
+#endif /* WSIZE() */
+#define SETFUNCTIONCONTEXT(ucp,funcp) \
+ (ucp)->uc_mcontext.gregs[CONTEXT_PC] = (greg_t)(funcp); \
+ (ucp)->uc_mcontext.gregs[CONTEXT_SP] = 0; \
+ (ucp)->uc_mcontext.gregs[CONTEXT_FP] = 0;
+
+#elif ARCH(Aarch64)
+#define CONTEXT_PC 15
+#define CONTEXT_FP 14
+#define CONTEXT_SP 13
+#define SETFUNCTIONCONTEXT(ucp,funcp) \
+ (ucp)->uc_mcontext.regs[CONTEXT_PC] = (greg_t)(funcp); \
+ (ucp)->uc_mcontext.regs[CONTEXT_SP] = 0; \
+ (ucp)->uc_mcontext.regs[CONTEXT_FP] = 0;
+#endif /* ARCH() */
+
+#endif
diff --git a/gprofng/libcollector/iolib.c b/gprofng/libcollector/iolib.c
new file mode 100644
index 0000000..6881f02
--- /dev/null
+++ b/gprofng/libcollector/iolib.c
@@ -0,0 +1,1156 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "config.h"
+#include <dlfcn.h>
+#include <pthread.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include "gp-defs.h"
+#include "collector.h"
+#include "gp-experiment.h"
+#include "memmgr.h"
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+
+/* ------------- Data and prototypes for block management --------- */
+#define IO_BLK 0 /* Concurrent requests */
+#define IO_SEQ 1 /* All requests are sequential, f.e. JAVA_CLASSES */
+#define IO_TXT 2 /* Sequential requests. Text strings. */
+#define ST_INIT 0 /* Initial state. Not allocated */
+#define ST_FREE 1 /* Available */
+#define ST_BUSY 2 /* Not available */
+
+/* IO_BLK, IO_SEQ */
+#define NCHUNKS 64
+
+/* IO_TXT */
+#define NBUFS 64 /* Number of text buffers */
+#define CUR_BUSY(x) ((uint32_t) ((x)>>63)) /* bit 63 */
+#define CUR_INDX(x) ((uint32_t) (((x)>>57) & 0x3fULL)) /* bits 62:57 */
+#define CUR_FOFF(x) ((x) & 0x01ffffffffffffffULL) /* bits 56: 0 */
+#define CUR_MAKE(busy, indx, foff) ((((uint64_t)(busy))<<63) | (((uint64_t)(indx))<<57) | ((uint64_t)(foff)) )
+
+typedef struct Buffer
+{
+ uint8_t *vaddr;
+ uint32_t left; /* bytes left */
+ uint32_t state; /* ST_FREE or ST_BUSY */
+} Buffer;
+
+typedef struct DataHandle
+{
+ Pckt_type kind; /* obsolete (to be removed) */
+ int iotype; /* IO_BLK, IO_SEQ, IO_TXT */
+ int active;
+ char fname[MAXPATHLEN]; /* data file name */
+
+ /* IO_BLK, IO_SEQ */
+ uint32_t nflow; /* number of data flows */
+ uint32_t *blkstate; /* block states, nflow*NCHUNKS array */
+ uint32_t *blkoff; /* block offset, nflow*NCHUNKS array */
+ uint32_t nchnk; /* number of active chunks, probably small for IO_BLK */
+ uint8_t *chunks[NCHUNKS]; /* chunks (nflow contiguous blocks in virtual memory) */
+ uint32_t chblk[NCHUNKS]; /* number of active blocks in a chunk */
+ uint32_t nblk; /* number of blocks in data file */
+ int exempt; /* if exempt from experiment size limit */
+
+ /* IO_TXT */
+ Buffer *buffers; /* array of text buffers */
+ uint64_t curpos; /* current buffer and file offset */
+} DataHandle;
+
+#define PROFILE_DATAHNDL_MAX 16
+static DataHandle data_hndls[PROFILE_DATAHNDL_MAX];
+static int initialized = 0;
+static long blksz; /* Block size. Multiple of page size. Power of two to make (x%blksz)==(x&(blksz-1)) fast. */
+static long log2blksz; /* log2(blksz) to make (x/blksz)==(x>>log2blksz) fast. */
+static uint32_t size_limit; /* Experiment size limit */
+static uint32_t cur_size; /* Current experiment size */
+static void init ();
+static void deleteHandle (DataHandle *hndl);
+static int exp_size_ck (int nblocks, char *fname);
+
+/* IO_BLK, IO_SEQ */
+static int allocateChunk (DataHandle *hndl, unsigned ichunk);
+static uint8_t *getBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk);
+static int remapBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk);
+static int newBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk);
+static void deleteBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk);
+
+/* IO_TXT */
+static int is_not_the_log_file (char *fname);
+static int mapBuffer (char *fname, Buffer *buf, off64_t foff);
+static int newBuffer (DataHandle *hndl, uint64_t pos);
+static void writeBuffer (Buffer *buf, int blk_off, char *src, int len);
+static void deleteBuffer (Buffer *buf);
+
+/*
+ * Common buffer management routines
+ */
+static void
+init ()
+{
+ /* set the block size */
+ long pgsz = CALL_UTIL (sysconf)(_SC_PAGESIZE);
+ blksz = pgsz;
+ log2blksz = 16; /* ensure a minimum size */
+ while ((1 << log2blksz) < blksz)
+ log2blksz += 1;
+ blksz = 1L << log2blksz; /* ensure that blksz is a power of two */
+ TprintfT (DBG_LT1, "iolib init: page size=%ld (0x%lx) blksz=%ld (0x%lx) log2blksz=%ld\n",
+ pgsz, pgsz, (long) blksz, (long) blksz, (long) log2blksz);
+ size_limit = 0;
+ cur_size = 0;
+ initialized = 1;
+}
+
+DataHandle *
+__collector_create_handle (char *descp)
+{
+ int exempt = 0;
+ char *desc = descp;
+ if (desc[0] == '*')
+ {
+ desc++;
+ exempt = 1;
+ }
+ if (!initialized)
+ init ();
+
+ /* set up header for file, file name, etc. */
+ if (__collector_exp_dir_name == NULL)
+ {
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">__collector_exp_dir_name==NULL</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_EXPOPEN);
+ return NULL;
+ }
+ char fname[MAXPATHLEN];
+ CALL_UTIL (strlcpy)(fname, __collector_exp_dir_name, sizeof (fname));
+ CALL_UTIL (strlcat)(fname, "/", sizeof (fname));
+ Pckt_type kind = 0;
+ int iotype = IO_BLK;
+ if (__collector_strcmp (desc, SP_HEAPTRACE_FILE) == 0)
+ kind = HEAP_PCKT;
+ else if (__collector_strcmp (desc, SP_SYNCTRACE_FILE) == 0)
+ kind = SYNC_PCKT;
+ else if (__collector_strcmp (desc, SP_IOTRACE_FILE) == 0)
+ kind = IOTRACE_PCKT;
+ else if (__collector_strcmp (desc, SP_RACETRACE_FILE) == 0)
+ kind = RACE_PCKT;
+ else if (__collector_strcmp (desc, SP_PROFILE_FILE) == 0)
+ kind = PROF_PCKT;
+ else if (__collector_strcmp (desc, SP_OMPTRACE_FILE) == 0)
+ kind = OMP_PCKT;
+ else if (__collector_strcmp (desc, SP_HWCNTR_FILE) == 0)
+ kind = HW_PCKT;
+ else if (__collector_strcmp (desc, SP_DEADLOCK_FILE) == 0)
+ kind = DEADLOCK_PCKT;
+ else if (__collector_strcmp (desc, SP_FRINFO_FILE) == 0)
+ CALL_UTIL (strlcat)(fname, "data.", sizeof (fname));
+ else if (__collector_strcmp (desc, SP_LOG_FILE) == 0)
+ iotype = IO_TXT;
+ else if (__collector_strcmp (desc, SP_MAP_FILE) == 0)
+ iotype = IO_TXT;
+ else if (__collector_strcmp (desc, SP_JCLASSES_FILE) == 0)
+ iotype = IO_SEQ;
+ else
+ {
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">iolib unknown file desc %s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_EXPOPEN, desc);
+ return NULL;
+ }
+
+ CALL_UTIL (strlcat)(fname, desc, sizeof (fname));
+ TprintfT (DBG_LT1, "createHandle calling open on fname = `%s', desc = `%s' %s\n",
+ fname, desc, (exempt == 0 ? "non-exempt" : "exempt"));
+
+ /* allocate a handle -- not mt-safe */
+ DataHandle *hndl = NULL;
+ for (int i = 0; i < PROFILE_DATAHNDL_MAX; ++i)
+ if (data_hndls[i].active == 0)
+ {
+ hndl = &data_hndls[i];
+ break;
+ }
+
+ /* out of handles? */
+ if (hndl == NULL)
+ {
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_NOHNDL, fname);
+ return NULL;
+ }
+
+ hndl->kind = kind;
+ hndl->nblk = 0;
+ hndl->exempt = exempt;
+ CALL_UTIL (strlcpy)(hndl->fname, fname, sizeof (hndl->fname));
+ int fd = CALL_UTIL (open)(hndl->fname,
+ O_RDWR | O_CREAT | O_TRUNC | O_EXCL,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd < 0)
+ {
+ TprintfT (0, "createHandle open failed -- hndl->fname = `%s', SP_LOG_FILE = `%s': %s\n",
+ hndl->fname, SP_LOG_FILE, CALL_UTIL (strerror)(errno));
+ if (is_not_the_log_file (hndl->fname) == 0)
+ {
+ char errbuf[4096];
+ /* If we are trying to create the handle for the log file, write to stderr, not the experiment */
+ CALL_UTIL (snprintf)(errbuf, sizeof (errbuf),
+ "create_handle: COL_ERROR_LOG_OPEN %s: %s\n", hndl->fname, CALL_UTIL (strerror)(errno));
+ CALL_UTIL (write)(2, errbuf, CALL_UTIL (strlen)(errbuf));
+
+ }
+ else
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: create_handle</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_FILEOPN, errno, hndl->fname);
+ return NULL;
+ }
+ CALL_UTIL (close)(fd);
+
+ hndl->iotype = iotype;
+ if (hndl->iotype == IO_TXT)
+ {
+ /* allocate our buffers in virtual memory */
+ /* later, we will remap buffers individually to the file */
+ uint8_t *memory = (uint8_t*) CALL_UTIL (mmap64)(0,
+ (size_t) (NBUFS * blksz),
+ PROT_READ | PROT_WRITE,
+#if ARCH(SPARC)
+ MAP_SHARED | MAP_ANON,
+#else
+ MAP_PRIVATE | MAP_ANON,
+#endif
+ -1,
+ (off64_t) 0);
+ if (memory == MAP_FAILED)
+ {
+ TprintfT (0, "create_handle: can't mmap MAP_ANON (for %s): %s\n", hndl->fname, CALL_UTIL (strerror)(errno));
+ /* see if this is the log file */
+ if (is_not_the_log_file (hndl->fname) == 0)
+ {
+ /* If we are trying to map the log file, write to stderr, not to the experiment */
+ char errbuf[4096];
+ CALL_UTIL (snprintf)(errbuf, sizeof (errbuf),
+ "create_handle: can't mmap MAP_ANON (for %s): %s\n", hndl->fname, CALL_UTIL (strerror)(errno));
+ CALL_UTIL (write)(2, errbuf, CALL_UTIL (strlen)(errbuf));
+ }
+ else /* write the error message into the experiment */
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">MAP_ANON (for %s); create_handle</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_FILEMAP, errno, hndl->fname);
+ return NULL;
+ }
+ TprintfT (DBG_LT2, " create_handle IO_TXT data buffer length=%ld (0x%lx) file='%s' memory=%p -- %p\n",
+ (long) (NBUFS * blksz), (long) (NBUFS * blksz), hndl->fname,
+ memory, memory + (NBUFS * blksz) - 1);
+
+ /* set up an array of buffers, pointing them to the virtual addresses */
+ TprintfT (DBG_LT2, "create_handle IO_TXT Buffer structures fname = `%s', NBUFS= %d, size = %ld (0x%lx)\n", fname,
+ NBUFS, (long) NBUFS * sizeof (Buffer), (long) NBUFS * sizeof (Buffer));
+ hndl->buffers = (Buffer*) __collector_allocCSize (__collector_heap, NBUFS * sizeof (Buffer), 1);
+ if (hndl->buffers == NULL)
+ {
+ TprintfT (0, "create_handle allocCSize for hndl->buffers failed\n");
+ CALL_UTIL (munmap)(memory, NBUFS * blksz);
+ return NULL;
+ }
+ for (int i = 0; i < NBUFS; i++)
+ {
+ Buffer *buf = &hndl->buffers[i];
+ buf->vaddr = memory + i * blksz;
+ buf->state = ST_FREE;
+ }
+ /* set the file pointer to the beginning of the file */
+ hndl->curpos = CUR_MAKE (0, 0, 0);
+ }
+ else
+ {
+ if (hndl->iotype == IO_BLK)
+ {
+ long nflow = CALL_UTIL (sysconf)(_SC_NPROCESSORS_ONLN);
+ if (nflow < 16)
+ nflow = 16;
+ hndl->nflow = (uint32_t) nflow;
+ }
+ else if (hndl->iotype == IO_SEQ)
+ hndl->nflow = 1;
+ TprintfT (DBG_LT2, "create_handle calling allocCSize blkstate fname=`%s' nflow=%d NCHUNKS=%d size=%ld (0x%lx)\n",
+ fname, hndl->nflow, NCHUNKS,
+ (long) (hndl->nflow * NCHUNKS * sizeof (uint32_t)),
+ (long) (hndl->nflow * NCHUNKS * sizeof (uint32_t)));
+ uint32_t *blkstate = (uint32_t*) __collector_allocCSize (__collector_heap, hndl->nflow * NCHUNKS * sizeof (uint32_t), 1);
+ if (blkstate == NULL)
+ return NULL;
+ for (int j = 0; j < hndl->nflow * NCHUNKS; ++j)
+ blkstate[j] = ST_INIT;
+ hndl->blkstate = blkstate;
+ TprintfT (DBG_LT2, "create_handle calling allocCSize blkoff fname=`%s' nflow=%d NCHUNKS=%d size=%ld (0x%lx)\n",
+ fname, hndl->nflow, NCHUNKS,
+ (long) (hndl->nflow * NCHUNKS * sizeof (uint32_t)),
+ (long) (hndl->nflow * NCHUNKS * sizeof (uint32_t)));
+ hndl->blkoff = (uint32_t*) __collector_allocCSize (__collector_heap, hndl->nflow * NCHUNKS * sizeof (uint32_t), 1);
+ if (hndl->blkoff == NULL)
+ return NULL;
+ hndl->nchnk = 0;
+ for (int j = 0; j < NCHUNKS; ++j)
+ {
+ hndl->chunks[j] = NULL;
+ hndl->chblk[j] = 0;
+ }
+ }
+ hndl->active = 1;
+ return hndl;
+}
+
+static void
+deleteHandle (DataHandle *hndl)
+{
+ if (hndl->active == 0)
+ return;
+ hndl->active = 0;
+
+ if (hndl->iotype == IO_BLK || hndl->iotype == IO_SEQ)
+ {
+ /* Delete all blocks. */
+ /* Since access to hndl->active is not synchronized it's still
+ * possible that we leave some blocks undeleted.
+ */
+ for (int j = 0; j < hndl->nflow * NCHUNKS; ++j)
+ {
+ uint32_t oldstate = hndl->blkstate[j];
+ if (oldstate != ST_FREE)
+ continue;
+ /* Mark as busy */
+ uint32_t state = __collector_cas_32 (hndl->blkstate + j, oldstate, ST_BUSY);
+ if (state != oldstate)
+ continue;
+ deleteBlock (hndl, j / NCHUNKS, j % NCHUNKS);
+ }
+ }
+ else if (hndl->iotype == IO_TXT)
+ {
+ /*
+ * First, make sure that buffers are in some "coherent" state:
+ *
+ * At this point, the handle is no longer active. But some threads
+ * might already have passed the active-handle check and are now
+ * trying to schedule writes. So, set the handle pointer to "busy".
+ * This will prevent new writes from being scheduled. Threads that
+ * polling will time out.
+ */
+ hrtime_t timeout = __collector_gethrtime () + 10 * ((hrtime_t) 1000000000);
+ volatile uint32_t busy = 0;
+ while (1)
+ {
+ uint32_t indx;
+ uint64_t opos, npos, foff;
+ int blk_off;
+ /* read the current pointer */
+ opos = hndl->curpos;
+ busy = CUR_BUSY (opos);
+ indx = CUR_INDX (opos);
+ foff = CUR_FOFF (opos);
+ if (busy == 1)
+ {
+ if (__collector_gethrtime () > timeout)
+ {
+ TprintfT (0, "deleteHandle ERROR: timeout cleaning up handle for %s\n", hndl->fname);
+ return;
+ }
+ continue;
+ }
+ blk_off = foff & (blksz - 1);
+ if (blk_off > 0)
+ foff += blksz - blk_off;
+ npos = CUR_MAKE (1, indx, foff);
+
+ /* try to update the handle position atomically */
+ if (__collector_cas_64p (&hndl->curpos, &opos, &npos) != opos)
+ continue;
+
+ /*
+ * If the last buffer won't be filled, account for
+ * the white space at the end so that the buffer will
+ * be deleted properly.
+ */
+ if (blk_off > 0)
+ {
+ Buffer *buf = &hndl->buffers[indx];
+ if (__collector_subget_32 (&buf->left, blksz - blk_off) == 0)
+ deleteBuffer (buf);
+ }
+ break;
+ }
+ /* wait for buffers to be deleted */
+ timeout = __collector_gethrtime () + 10 * ((hrtime_t) 1000000000);
+ for (int i = 0; i < NBUFS; i++)
+ {
+ Buffer *buf = &hndl->buffers[i];
+ while (__collector_cas_32 (&buf->state, ST_FREE, ST_INIT) != ST_FREE)
+ {
+ if (__collector_gethrtime () > timeout)
+ {
+ TprintfT (0, "deleteHandle ERROR: timeout waiting for buffer %d for %s\n", i, hndl->fname);
+ return;
+ }
+ }
+ CALL_UTIL (munmap)(buf->vaddr, blksz);
+ }
+
+ /* free buffer array */
+ __collector_freeCSize (__collector_heap, hndl->buffers, NBUFS * sizeof (Buffer));
+ }
+}
+
+void
+__collector_delete_handle (DataHandle *hndl)
+{
+ if (hndl == NULL)
+ return;
+ deleteHandle (hndl);
+}
+
+static int
+exp_size_ck (int nblocks, char *fname)
+{
+ if (size_limit == 0)
+ return 0;
+ /* do an atomic add to the cur_size */
+ uint32_t old_size = cur_size;
+ uint32_t new_size;
+ for (;;)
+ {
+ new_size = __collector_cas_32 (&cur_size, old_size, old_size + nblocks);
+ if (new_size == old_size)
+ {
+ new_size = old_size + nblocks;
+ break;
+ }
+ old_size = new_size;
+ }
+ TprintfT (DBG_LT2, "exp_size_ck() adding %d block(s); new_size = %d, limit = %d blocks; fname = %s\n",
+ nblocks, new_size, size_limit, fname);
+
+ /* pause the entire collector if we have exceeded the limit */
+ if (old_size < size_limit && new_size >= size_limit)
+ {
+ TprintfT (0, "exp_size_ck() experiment size limit exceeded; new_size = %ld, limit = %ld blocks; fname = %s\n",
+ (long) new_size, (long) size_limit, fname);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%ld blocks (each %ld bytes)</event>\n",
+ SP_JCMD_CWARN, COL_ERROR_SIZELIM, (long) size_limit, (long) blksz);
+ __collector_pause_m ("size-limit");
+ __collector_terminate_expt ();
+ return -1;
+ }
+ return 0;
+}
+
+int
+__collector_set_size_limit (char *par)
+{
+ if (!initialized)
+ init ();
+
+ int lim = CALL_UTIL (strtol)(par, &par, 0);
+ size_limit = (uint32_t) ((uint64_t) lim * 1024 * 1024 / blksz);
+ TprintfT (DBG_LT0, "collector_size_limit set to %d MB. = %d blocks\n",
+ lim, size_limit);
+ (void) __collector_log_write ("<setting limit=\"%d\"/>\n", lim);
+ return COL_ERROR_NONE;
+}
+
+/*
+ * IO_BLK and IO_SEQ files
+ */
+
+/*
+ * Allocate a chunk (nflow blocks) contiguously in virtual memory.
+ * Its blocks will be mmapped to the file individually.
+ */
+static int
+allocateChunk (DataHandle *hndl, unsigned ichunk)
+{
+ /*
+ * hndl->chunks[ichunk] is one of:
+ * - NULL (initial value)
+ * - CHUNK_BUSY (transition state when allocating the chunk)
+ * - some address (the allocated chunk)
+ */
+ uint8_t *CHUNK_BUSY = (uint8_t *) 1;
+ hrtime_t timeout = 0;
+ while (1)
+ {
+ if (hndl->chunks[ichunk] > CHUNK_BUSY)
+ return 0; /* the chunk has already been allocated */
+ /* try to allocate the chunk (change: NULL => CHUNK_BUSY) */
+ if (__collector_cas_ptr (&hndl->chunks[ichunk], NULL, CHUNK_BUSY) == NULL)
+ {
+ /* allocate virtual memory */
+ uint8_t *newchunk = (uint8_t*) CALL_UTIL (mmap64)(0,
+ (size_t) (blksz * hndl->nflow),
+ PROT_READ | PROT_WRITE,
+#if ARCH(SPARC)
+ MAP_SHARED | MAP_ANON,
+#else
+ MAP_PRIVATE | MAP_ANON,
+#endif
+ -1, (off64_t) 0);
+ if (newchunk == MAP_FAILED)
+ {
+ deleteHandle (hndl);
+ TprintfT (DBG_LT1, " allocateChunk mmap: start=0x%x length=%ld (0x%lx), offset=%d ret=%p\n",
+ 0, (long) (blksz * hndl->nflow),
+ (long) (blksz * hndl->nflow), 0, newchunk);
+ TprintfT (0, "allocateChunk: can't mmap MAP_ANON (for %s): %s\n", hndl->fname, CALL_UTIL (strerror) (errno));
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">MAP_ANON (for %s)</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_FILEMAP, errno, hndl->fname);
+ return 1;
+ }
+
+ /* assign allocated address to our chunk */
+ if (__collector_cas_ptr (&hndl->chunks[ichunk], CHUNK_BUSY, newchunk) != CHUNK_BUSY)
+ {
+ TprintfT (0, "allocateChunk: can't release chunk CAS lock for %s\n", hndl->fname);
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">couldn't release chunk CAS lock (%s)</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_GENERAL, hndl->fname);
+ }
+ __collector_inc_32 (&hndl->nchnk);
+ return 0;
+ }
+
+ /* check for time out */
+ if (timeout == 0)
+ timeout = __collector_gethrtime () + 10 * ((hrtime_t) 1000000000);
+ if (__collector_gethrtime () > timeout)
+ {
+ TprintfT (0, "allocateChunk: timeout for %s\n", hndl->fname);
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">timeout allocating chunk for %s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_GENERAL, hndl->fname);
+ return 1;
+ }
+ }
+}
+
+/*
+ * Get the address for block (iflow,ichunk).
+ */
+static uint8_t *
+getBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk)
+{
+ return hndl->chunks[ichunk] + iflow * blksz;
+}
+
+/*
+ * Map block (iflow,ichunk) to the next part of the file.
+ */
+static int
+remapBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk)
+{
+ int rc = 0;
+ int fd;
+ /* Get the old file nblk and increment it atomically. */
+ uint32_t oldblk = hndl->nblk;
+ for (;;)
+ {
+ uint32_t newblk = __collector_cas_32 (&hndl->nblk, oldblk, oldblk + 1);
+ if (newblk == oldblk)
+ break;
+ oldblk = newblk;
+ }
+ off64_t offset = (off64_t) oldblk * blksz;
+
+ /* 6618470: disable thread cancellation */
+ int old_cstate;
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old_cstate);
+
+ /* Open the file. */
+ int iter = 0;
+ hrtime_t tso = __collector_gethrtime ();
+ for (;;)
+ {
+ fd = CALL_UTIL (open)(hndl->fname, O_RDWR, 0);
+ if (fd < 0)
+ {
+ if (errno == EMFILE)
+ {
+ /* too many open files */
+ iter++;
+ if (iter > 1000)
+ {
+ /* we've tried 1000 times; kick error back to caller */
+ char errmsg[MAXPATHLEN + 50];
+ hrtime_t teo = __collector_gethrtime ();
+ double deltato = (double) (teo - tso) / 1000000.;
+ (void) CALL_UTIL (snprintf) (errmsg, sizeof (errmsg), " t=%d, %s: open-retries-failed = %d, %3.6f ms.; remap",
+ __collector_thr_self (), hndl->fname, iter, deltato);
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
+ SP_JCMD_COMMENT, COL_COMMENT_NONE, errmsg);
+ rc = 1;
+ goto exit;
+ }
+ /* keep trying */
+ continue;
+ }
+ deleteHandle (hndl);
+ TprintfT (0, "remapBlock: can't open file: %s: %s\n", hndl->fname, STR (CALL_UTIL (strerror)(errno)));
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">t=%llu, %s: remap </event>\n",
+ SP_JCMD_CERROR, COL_ERROR_FILEOPN, errno,
+ (unsigned long long) __collector_thr_self (),
+ hndl->fname);
+ rc = 1;
+ goto exit;
+ }
+ else
+ break;
+ }
+
+ /* report number of retries of the open due to too many open fd's */
+ if (iter > 0)
+ {
+ char errmsg[MAXPATHLEN + 50];
+ hrtime_t teo = __collector_gethrtime ();
+ double deltato = (double) (teo - tso) / 1000000.;
+ (void) CALL_UTIL (snprintf) (errmsg, sizeof (errmsg), " t=%d, %s: open-retries = %d, %3.6f ms.; remap",
+ __collector_thr_self (), hndl->fname, iter, deltato);
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
+ SP_JCMD_COMMENT, COL_COMMENT_NONE, errmsg);
+ }
+
+ /* Ensure disk space is allocated and the block offset is 0 */
+ uint32_t zero = 0;
+ int n = CALL_UTIL (pwrite64)(fd, &zero, sizeof (zero), (off64_t) (offset + blksz - sizeof (zero)));
+ if (n <= 0)
+ {
+ deleteHandle (hndl);
+ TprintfT (0, "remapBlock: can't pwrite file: %s : errno=%d\n", hndl->fname, errno);
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: remap</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_NOSPACE, errno, hndl->fname);
+ CALL_UTIL (close)(fd);
+ rc = 1;
+ goto exit;
+ }
+ hndl->blkoff[iflow * NCHUNKS + ichunk] = 0;
+
+ /* Map block to file */
+ uint8_t *bptr = getBlock (hndl, iflow, ichunk);
+ uint8_t *vaddr = (uint8_t *) CALL_UTIL (mmap64)(
+ (void*) bptr,
+ (size_t) blksz,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_FIXED,
+ fd,
+ offset);
+
+ if (vaddr != bptr)
+ {
+ deleteHandle (hndl);
+ TprintfT (DBG_LT1, " remapBlock mmap: start=%p length=%ld (0x%lx) offset=0x%llx ret=%p\n",
+ bptr, (long) blksz, (long) blksz, (long long) offset, vaddr);
+ TprintfT (0, "remapBlock: can't mmap file: %s : errno=%d\n", hndl->fname, errno);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: remap</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_FILEMAP, errno, hndl->fname);
+ CALL_UTIL (close)(fd);
+ rc = 1;
+ goto exit;
+ }
+ CALL_UTIL (close)(fd);
+
+ if (hndl->exempt == 0)
+ exp_size_ck (1, hndl->fname);
+ else
+ Tprintf (DBG_LT1, "exp_size_ck() bypassed for %d block(s); exempt fname = %s\n",
+ 1, hndl->fname);
+exit:
+ /* Restore the previous cancellation state */
+ pthread_setcancelstate (old_cstate, NULL);
+
+ return rc;
+}
+
+static int
+newBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk)
+{
+ if (allocateChunk (hndl, ichunk) != 0)
+ return 1;
+ if (remapBlock (hndl, iflow, ichunk) != 0)
+ return 1;
+
+ /* Update the number of active blocks */
+ __collector_inc_32 (hndl->chblk + ichunk);
+ return 0;
+}
+
+static void
+deleteBlock (DataHandle *hndl, unsigned iflow, unsigned ichunk)
+{
+ uint8_t *bptr = getBlock (hndl, iflow, ichunk);
+ CALL_UTIL (munmap)((void*) bptr, blksz);
+ hndl->blkstate[iflow * NCHUNKS + ichunk] = ST_INIT;
+
+ /* Update the number of active blocks */
+ __collector_dec_32 (hndl->chblk + ichunk);
+}
+
+int
+__collector_write_record (DataHandle *hndl, Common_packet *pckt)
+{
+ if (hndl == NULL || !hndl->active)
+ return 1;
+ /* fill in the fields of the common packet structure */
+ if (pckt->type == 0)
+ pckt->type = hndl->kind;
+ if (pckt->tstamp == 0)
+ pckt->tstamp = __collector_gethrtime ();
+ if (pckt->lwp_id == 0)
+ pckt->lwp_id = __collector_lwp_self ();
+ if (pckt->thr_id == 0)
+ pckt->thr_id = __collector_thr_self ();
+ if (pckt->cpu_id == 0)
+ pckt->cpu_id = CALL_UTIL (getcpuid)();
+ if (pckt->tsize == 0)
+ pckt->tsize = sizeof (Common_packet);
+ TprintfT (DBG_LT3, "collector_write_record to %s, type:%d tsize:%d\n",
+ hndl->fname, pckt->type, pckt->tsize);
+ return __collector_write_packet (hndl, (CM_Packet*) pckt);
+}
+
+int
+__collector_write_packet (DataHandle *hndl, CM_Packet *pckt)
+{
+ if (hndl == NULL || !hndl->active)
+ return 1;
+
+ /* if the experiment is not open, there should be no writes */
+ if (__collector_expstate != EXP_OPEN)
+ {
+#ifdef DEBUG
+ char *xstate;
+ switch (__collector_expstate)
+ {
+ case EXP_INIT:
+ xstate = "EXP_INIT";
+ break;
+ case EXP_OPEN:
+ xstate = "EXP_OPEN";
+ break;
+ case EXP_PAUSED:
+ xstate = "EXP_PAUSED";
+ break;
+ case EXP_CLOSED:
+ xstate = "EXP_CLOSED";
+ break;
+ default:
+ xstate = "Unknown";
+ break;
+ }
+ TprintfT (0, "collector_write_packet: write to %s while experiment state is %s\n",
+ hndl->fname, xstate);
+#endif
+ return 1;
+ }
+ int recsz = pckt->tsize;
+ if (recsz > blksz)
+ {
+ TprintfT (0, "collector_write_packet: packet too long: %d (max %ld)\n", recsz, blksz);
+ return 1;
+ }
+ unsigned tid = (__collector_no_threads ? __collector_lwp_self () : __collector_thr_self ());
+ unsigned iflow = tid % hndl->nflow;
+
+ /* Acquire block */
+ uint32_t *sptr = &hndl->blkstate[iflow * NCHUNKS];
+ uint32_t state = ST_BUSY;
+ unsigned ichunk;
+ for (ichunk = 0; ichunk < NCHUNKS; ++ichunk)
+ {
+ uint32_t oldstate = sptr[ichunk];
+ if (oldstate == ST_BUSY)
+ continue;
+ /* Mark as busy */
+ state = __collector_cas_32 (sptr + ichunk, oldstate, ST_BUSY);
+ if (state == oldstate)
+ break;
+ if (state == ST_BUSY)
+ continue;
+ /* It's possible the state changed from ST_INIT to ST_FREE */
+ oldstate = state;
+ state = __collector_cas_32 (sptr + ichunk, oldstate, ST_BUSY);
+ if (state == oldstate)
+ break;
+ }
+
+ if (state == ST_BUSY || ichunk == NCHUNKS)
+ {
+ /* We are out of blocks for this data flow.
+ * We might switch to another flow but for now report and return.
+ */
+ TprintfT (0, "collector_write_packet: all %d blocks on flow %d for %s are busy\n",
+ NCHUNKS, iflow, hndl->fname);
+ return 1;
+ }
+
+ if (state == ST_INIT && newBlock (hndl, iflow, ichunk) != 0)
+ return 1;
+ uint8_t *bptr = getBlock (hndl, iflow, ichunk);
+ uint32_t blkoff = hndl->blkoff[iflow * NCHUNKS + ichunk];
+ if (blkoff + recsz > blksz)
+ {
+ /* The record doesn't fit. Close the block */
+ if (blkoff < blksz)
+ {
+ Common_packet *closed = (Common_packet *) (bptr + blkoff);
+ closed->type = CLOSED_PCKT;
+ closed->tsize = blksz - blkoff; /* redundant */
+ }
+ if (remapBlock (hndl, iflow, ichunk) != 0)
+ return 1;
+ blkoff = hndl->blkoff[iflow * NCHUNKS + ichunk];
+ }
+ if (blkoff + recsz < blksz)
+ {
+ /* Set the empty padding */
+ Common_packet *empty = (Common_packet *) (bptr + blkoff + recsz);
+ empty->type = EMPTY_PCKT;
+ empty->tsize = blksz - blkoff - recsz;
+ }
+ __collector_memcpy (bptr + blkoff, pckt, recsz);
+
+ /* Release block */
+ if (hndl->active == 0)
+ {
+ deleteBlock (hndl, iflow, ichunk);
+ return 0;
+ }
+ hndl->blkoff[iflow * NCHUNKS + ichunk] += recsz;
+ sptr[ichunk] = ST_FREE;
+ return 0;
+}
+
+/*
+ * IO_TXT files
+ *
+ * IO_TXT covers the case where many threads are trying to write text messages
+ * sequentially (atomically) to a file. Examples include SP_LOG_FILE and SP_MAP_FILE.
+ *
+ * The file is not written directly, but by writing to mmapped virtual memory.
+ * The granularity of the mapping is a "Buffer". There may be as many as
+ * NBUFS buffers at any one time.
+ *
+ * The current position of the file is handled via hndl->curpos.
+ *
+ * * It is accessed atomically with 64-bit CAS instructions.
+ *
+ * * This 64-bit word encapsulates:
+ * - busy: a bit to lock access to hndl->curpos
+ * - indx: an index indicating which Buffer to use for the current position
+ * - foff: the file offset
+ *
+ * * The contents are accessed with:
+ * - unpack macros: CUR_BUSY CUR_INDX CUR_FOFF
+ * - pack macro : CUR_MAKE
+ *
+ * Conceptually, what happens when a thread wants to write a message is:
+ * - acquire the hndl->curpos "busy" lock
+ * . acquire and map new Buffers if needed to complete the message
+ * . update the file offset
+ * . release the lock
+ * - write to the corresponding buffers
+ *
+ * Each Buffer has a buf->left field that tracks how many more bytes
+ * need to be written to the Buffer. After a thread writes to a Buffer,
+ * it decrements buf->left atomically. When buf->left reaches 0, the
+ * Buffer (mapping) is deleted, freeing the Buffer for a new mapping.
+ *
+ * The actual implementation has some twists:
+ *
+ * * If the entire text message fits into the current Buffer -- that is,
+ * no new Buffers are needed -- the thread does not acquire the lock.
+ * It simply updates hndl->curpos atomically to the new file offset.
+ *
+ * * There are various timeouts to prevent hangs in case of abnormalities.
+ */
+static int
+is_not_the_log_file (char *fname)
+{
+ if (CALL_UTIL (strstr)(fname, SP_LOG_FILE) == NULL)
+ return 1;
+ return 0;
+}
+
+static int
+mapBuffer (char *fname, Buffer *buf, off64_t foff)
+{
+ int rc = 0;
+ /* open fname */
+ int fd = CALL_UTIL (open)(fname, O_RDWR, 0);
+ if (fd < 0)
+ {
+ TprintfT (0, "mapBuffer ERROR: can't open file: %s\n", fname);
+ if (is_not_the_log_file (fname))
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: mapBuffer</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_FILEOPN, errno, fname);
+ return 1;
+ }
+ TprintfT (DBG_LT2, "mapBuffer pwrite file %s at 0x%llx\n", fname, (long long) foff);
+
+ /* ensure disk space is allocated */
+ char nl = '\n';
+ int n = CALL_UTIL (pwrite64)(fd, &nl, sizeof (nl), (off64_t) (foff + blksz - sizeof (nl)));
+ if (n <= 0)
+ {
+ TprintfT (0, "mapBuffer ERROR: can't pwrite file %s at 0x%llx\n", fname,
+ (long long) (foff + blksz - sizeof (nl)));
+ if (is_not_the_log_file (fname))
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: mapBuffer</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_FILETRNC, errno, fname);
+ rc = 1;
+ goto exit;
+ }
+ /* mmap buf->vaddr to fname at foff */
+ uint8_t *vaddr = CALL_UTIL (mmap64)(buf->vaddr, (size_t) blksz,
+ PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FIXED, fd, foff);
+ if (vaddr != buf->vaddr)
+ {
+ TprintfT (DBG_LT1, " mapBuffer mmap: start=%p length=%ld (0x%lx) offset=0x%llx ret=%p\n",
+ buf->vaddr, blksz, blksz, (long long) foff, vaddr);
+ TprintfT (0, "mapBuffer ERROR: can't mmap %s: vaddr=%p size=%ld (0x%lx) ret=%p off=0x%llx errno=%d\n",
+ fname, buf->vaddr, blksz, blksz, vaddr, (long long) foff, errno);
+ if (is_not_the_log_file (fname))
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: mapBuffer</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_FILEMAP, errno, fname);
+ rc = 1;
+ }
+ else
+ buf->left = blksz;
+exit:
+ CALL_UTIL (close)(fd);
+
+ /* Should we check buffer size? Let's not since:
+ * - IO_TXT is typically not going to be that big
+ * - we want log.xml to be treated specially
+ */
+ /* exp_size_ck( 1, fname ); */
+ return rc;
+}
+
+static int
+newBuffer (DataHandle *hndl, uint64_t foff)
+{
+ /* find a ST_FREE buffer and mark it ST_BUSY */
+ int ibuf;
+ for (ibuf = 0; ibuf < NBUFS; ibuf++)
+ if (__collector_cas_32 (&hndl->buffers[ibuf].state, ST_FREE, ST_BUSY) == ST_FREE)
+ break;
+ if (ibuf >= NBUFS)
+ {
+ TprintfT (0, "newBuffer ERROR: all buffers busy for %s\n", hndl->fname);
+ return -1;
+ }
+ Buffer *nbuf = hndl->buffers + ibuf;
+
+ /* map buffer */
+ if (mapBuffer (hndl->fname, nbuf, foff) != 0)
+ {
+ nbuf->state = ST_FREE;
+ ibuf = -1;
+ goto exit;
+ }
+exit:
+ return ibuf;
+}
+
+static void
+writeBuffer (Buffer *buf, int blk_off, char *src, int len)
+{
+ __collector_memcpy (buf->vaddr + blk_off, src, len);
+ if (__collector_subget_32 (&buf->left, len) == 0)
+ deleteBuffer (buf);
+}
+
+static void
+deleteBuffer (Buffer *buf)
+{
+ buf->state = ST_FREE;
+}
+
+int
+__collector_write_string (DataHandle *hndl, char *src, int len)
+{
+ if (hndl == NULL || !hndl->active)
+ return 1;
+ if (len <= 0)
+ return 0;
+
+ hrtime_t timeout = __collector_gethrtime () + 20 * ((hrtime_t) 1000000000);
+ volatile uint32_t busy = 0;
+ while (1)
+ {
+ uint32_t indx;
+ uint64_t opos, foff, base;
+ int blk_off, buf_indices[NBUFS], ibuf, nbufs;
+
+ /* read and decode the current pointer */
+ opos = hndl->curpos;
+ busy = CUR_BUSY (opos);
+ indx = CUR_INDX (opos);
+ foff = CUR_FOFF (opos);
+ if (busy == 1)
+ {
+ if (__collector_gethrtime () > timeout)
+ {
+ /*
+ * E.g., if another thread deleted the handle
+ * after we checked hndl->active.
+ */
+ TprintfT (0, "__collector_write_string ERROR: timeout writing length=%d to text file: %s\n", len, hndl->fname);
+ return 1;
+ }
+ continue;
+ }
+
+ /* initial block offset */
+ blk_off = foff & (blksz - 1);
+
+ /* number of new buffers to map */
+ int lastbuf = ((foff + len - 1) >> log2blksz); /* last block file index we will write */
+ int firstbuf = ((foff - 1) >> log2blksz); /* last block file index we have written */
+ nbufs = lastbuf - firstbuf;
+ TprintfT (DBG_LT2, "__collector_write_string firstbuf = %d, lastbuf = %d, nbufs = %d, log2blksz = %ld\n",
+ firstbuf, lastbuf, nbufs, log2blksz);
+ if (nbufs >= NBUFS)
+ {
+ Tprintf (0, "__collector_write_string ERROR: string of length %d too long to be written to text file: %s\n", len, hndl->fname);
+ return 1;
+ }
+
+ /* things are simple if we don't need new buffers */
+ if (nbufs == 0)
+ {
+ /* try to update the handle position atomically */
+ uint64_t npos = CUR_MAKE (0, indx, foff + len);
+ if (__collector_cas_64p (&hndl->curpos, &opos, &npos) != opos)
+ continue;
+
+ /* success! copy our string and we're done */
+ TprintfT (DBG_LT2, "__collector_write_string writeBuffer[%d]: vaddr = %p, len = %d, foff = %lld, '%s'\n",
+ indx, hndl->buffers[indx].vaddr, len, (long long) foff, src);
+ writeBuffer (&hndl->buffers[indx], foff & (blksz - 1), src, len);
+ break;
+ }
+
+ /* initialize the new signal mask */
+ sigset_t new_mask;
+ sigset_t old_mask;
+ CALL_UTIL (sigfillset)(&new_mask);
+
+ /* 6618470: disable thread cancellation */
+ int old_cstate;
+ pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &old_cstate);
+ /* block all signals */
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask);
+
+ /* but if we need new buffers, "lock" the handle pointer */
+ uint64_t lpos = CUR_MAKE (1, indx, foff);
+ if (__collector_cas_64p (&hndl->curpos, &opos, &lpos) != opos)
+ {
+ /* restore signal mask */
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
+ /* Restore the previous cancellation state */
+ pthread_setcancelstate (old_cstate, NULL);
+ continue;
+ }
+
+ /* map new buffers */
+ base = ((foff - 1) & ~(blksz - 1)); /* last buffer to have been mapped */
+ for (ibuf = 0; ibuf < nbufs; ibuf++)
+ {
+ base += blksz;
+ buf_indices[ibuf] = newBuffer (hndl, base);
+ if (buf_indices[ibuf] < 0)
+ break;
+ }
+
+ /* "unlock" the handle pointer */
+ uint64_t npos = CUR_MAKE (0, indx, foff);
+ if (ibuf == nbufs)
+ npos = CUR_MAKE (0, buf_indices[nbufs - 1], foff + len);
+ if (__collector_cas_64p (&hndl->curpos, &lpos, &npos) != lpos)
+ {
+ TprintfT (0, "__collector_write_string ERROR: file handle corrupted: %s\n", hndl->fname);
+ /*
+ * At this point, the handle is apparently corrupted and
+ * presumably locked. No telling what's going on. Still
+ * let's proceed and write our data and let a later thread
+ * raise an error if it encounters one.
+ */
+ }
+
+ /* restore signal mask */
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
+ /* Restore the previous cancellation state */
+ pthread_setcancelstate (old_cstate, NULL);
+
+ /* if we couldn't map all the buffers we needed, don't write any part of the string */
+ if (ibuf < nbufs)
+ {
+ TprintfT (0, "__collector_write_string ERROR: can't map new buffer: %s\n", hndl->fname);
+ return 1;
+ }
+
+ /* write any data to the old block */
+ if (blk_off > 0)
+ {
+ TprintfT (DBG_LT2, "__collector_write_string partial writeBuffer[%d]: len=%ld, foff = %d '%s'\n",
+ indx, blksz - blk_off, blk_off, src);
+ writeBuffer (&hndl->buffers[indx], blk_off, src, blksz - blk_off);
+ src += blksz - blk_off;
+ len -= blksz - blk_off;
+ }
+
+ /* write data to the new blocks */
+ for (ibuf = 0; ibuf < nbufs; ibuf++)
+ {
+ int clen = blksz;
+ if (clen > len)
+ clen = len;
+ TprintfT (DBG_LT2, "__collector_write_string continue writeBuffer[%d]: len= %d, %s",
+ ibuf, clen, src);
+ writeBuffer (&hndl->buffers[buf_indices[ibuf]], 0, src, clen);
+ src += clen;
+ len -= clen;
+ }
+ break;
+ }
+ return 0;
+}
+
diff --git a/gprofng/libcollector/iotrace.c b/gprofng/libcollector/iotrace.c
new file mode 100644
index 0000000..462ccf2
--- /dev/null
+++ b/gprofng/libcollector/iotrace.c
@@ -0,0 +1,3728 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/*
+ * IO events
+ */
+#include "config.h"
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+// create() and others are defined in fcntl.h.
+// Our 'create' should not have the __nonnull attribute
+#undef __nonnull
+#define __nonnull(x)
+#include <fcntl.h>
+
+#include "gp-defs.h"
+#include "collector_module.h"
+#include "gp-experiment.h"
+#include "data_pckts.h"
+#include "tsd.h"
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LTT 0 // for interposition on GLIBC functions
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+
+/* define the packet that will be written out */
+typedef struct IOTrace_packet
+{ /* IO tracing packet */
+ Common_packet comm;
+ IOTrace_type iotype; /* IO type */
+ int32_t fd; /* file descriptor */
+ Size_type nbyte; /* number of bytes */
+ hrtime_t requested; /* time of IO requested */
+ int32_t ofd; /* original file descriptor */
+ FileSystem_type fstype; /* file system type */
+ char fname; /* file name */
+} IOTrace_packet;
+
+typedef long long offset_t;
+
+static int open_experiment (const char *);
+static int start_data_collection (void);
+static int stop_data_collection (void);
+static int close_experiment (void);
+static int detach_experiment (void);
+static int init_io_intf ();
+
+static ModuleInterface module_interface ={
+ SP_IOTRACE_FILE, /* description */
+ NULL, /* initInterface */
+ open_experiment, /* openExperiment */
+ start_data_collection, /* startDataCollection */
+ stop_data_collection, /* stopDataCollection */
+ close_experiment, /* closeExperiment */
+ detach_experiment /* detachExperiment (fork child) */
+};
+
+static CollectorInterface *collector_interface = NULL;
+static struct Heap *io_heap = NULL;
+static int io_mode = 0;
+static CollectorModule io_hndl = COLLECTOR_MODULE_ERR;
+static unsigned io_key = COLLECTOR_TSD_INVALID_KEY;
+
+#define CHCK_REENTRANCE(x) (!io_mode || ((x) = collector_interface->getKey( io_key )) == NULL || (*(x) != 0))
+#define RECHCK_REENTRANCE(x) (!io_mode || ((x) = collector_interface->getKey( io_key )) == NULL || (*(x) == 0))
+#define PUSH_REENTRANCE(x) ((*(x))++)
+#define POP_REENTRANCE(x) ((*(x))--)
+
+#define CALL_REAL(x) (__real_##x)
+#define NULL_PTR(x) (__real_##x == NULL)
+
+#define gethrtime collector_interface->getHiResTime
+
+#ifdef DEBUG
+#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
+#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
+#else
+#define Tprintf(...)
+#define TprintfT(...)
+#endif
+
+/* interposition function handles */
+static int (*__real_open)(const char *path, int oflag, ...) = NULL;
+static int (*__real_fcntl)(int fildes, int cmd, ...) = NULL;
+static int (*__real_openat)(int fildes, const char *path, int oflag, ...) = NULL;
+static int (*__real_close)(int fildes) = NULL;
+static FILE *(*__real_fopen)(const char *filename, const char *mode) = NULL;
+static int (*__real_fclose)(FILE *stream) = NULL;
+static int (*__real_dup)(int fildes) = NULL;
+static int (*__real_dup2)(int fildes, int fildes2) = NULL;
+static int (*__real_pipe)(int fildes[2]) = NULL;
+static int (*__real_socket)(int domain, int type, int protocol) = NULL;
+static int (*__real_mkstemp)(char *template) = NULL;
+static int (*__real_mkstemps)(char *template, int slen) = NULL;
+static int (*__real_creat)(const char *path, mode_t mode) = NULL;
+static FILE *(*__real_fdopen)(int fildes, const char *mode) = NULL;
+static ssize_t (*__real_read)(int fildes, void *buf, size_t nbyte) = NULL;
+static ssize_t (*__real_write)(int fildes, const void *buf, size_t nbyte) = NULL;
+static ssize_t (*__real_readv)(int fildes, const struct iovec *iov, int iovcnt) = NULL;
+static ssize_t (*__real_writev)(int fildes, const struct iovec *iov, int iovcnt) = NULL;
+static size_t (*__real_fread)(void *ptr, size_t size, size_t nitems, FILE *stream) = NULL;
+static size_t (*__real_fwrite)(const void *ptr, size_t size, size_t nitems, FILE *stream) = NULL;
+static ssize_t (*__real_pread)(int fildes, void *buf, size_t nbyte, off_t offset) = NULL;
+static ssize_t (*__real_pwrite)(int fildes, const void *buf, size_t nbyte, off_t offset) = NULL;
+static ssize_t (*__real_pwrite64)(int fildes, const void *buf, size_t nbyte, off64_t offset) = NULL;
+static char *(*__real_fgets)(char *s, int n, FILE *stream) = NULL;
+static int (*__real_fputs)(const char *s, FILE *stream) = NULL;
+static int (*__real_fputc)(int c, FILE *stream) = NULL;
+static int (*__real_fprintf)(FILE *stream, const char *format, ...) = NULL;
+static int (*__real_vfprintf)(FILE *stream, const char *format, va_list ap) = NULL;
+static off_t (*__real_lseek)(int fildes, off_t offset, int whence) = NULL;
+static offset_t (*__real_llseek)(int fildes, offset_t offset, int whence) = NULL;
+static int (*__real_chmod)(const char *path, mode_t mode) = NULL;
+static int (*__real_access)(const char *path, int amode) = NULL;
+static int (*__real_rename)(const char *old, const char *new) = NULL;
+static int (*__real_mkdir)(const char *path, mode_t mode) = NULL;
+static int (*__real_getdents)(int fildes, struct dirent *buf, size_t nbyte) = NULL;
+static int (*__real_unlink)(const char *path) = NULL;
+static int (*__real_fseek)(FILE *stream, long offset, int whence) = NULL;
+static void (*__real_rewind)(FILE *stream) = NULL;
+static long (*__real_ftell)(FILE *stream) = NULL;
+static int (*__real_fgetpos)(FILE *stream, fpos_t *pos) = NULL;
+static int (*__real_fsetpos)(FILE *stream, const fpos_t *pos) = NULL;
+static int (*__real_fsync)(int fildes) = NULL;
+static struct dirent *(*__real_readdir)(DIR *dirp) = NULL;
+static int (*__real_flock)(int fd, int operation) = NULL;
+static int (*__real_lockf)(int fildes, int function, off_t size) = NULL;
+static int (*__real_fflush)(FILE *stream) = NULL;
+
+#if WSIZE(32)
+static int (*__real_open64)(const char *path, int oflag, ...) = NULL;
+static int (*__real_creat64)(const char *path, mode_t mode) = NULL;
+static int (*__real_fgetpos64)(FILE *stream, fpos64_t *pos) = NULL;
+static int (*__real_fsetpos64)(FILE *stream, const fpos64_t *pos) = NULL;
+
+#if ARCH(Intel)
+static FILE *(*__real_fopen_2_1)(const char *filename, const char *mode) = NULL;
+static int (*__real_fclose_2_1)(FILE *stream) = NULL;
+static FILE *(*__real_fdopen_2_1)(int fildes, const char *mode) = NULL;
+static int (*__real_fgetpos_2_2)(FILE *stream, fpos_t *pos) = NULL;
+static int (*__real_fsetpos_2_2)(FILE *stream, const fpos_t *pos) = NULL;
+static int (*__real_fgetpos64_2_2)(FILE *stream, fpos64_t *pos) = NULL;
+static int (*__real_fsetpos64_2_2)(FILE *stream, const fpos64_t *pos) = NULL;
+static int (*__real_open64_2_2)(const char *path, int oflag, ...) = NULL;
+static ssize_t (*__real_pread_2_2)(int fildes, void *buf, size_t nbyte, off_t offset) = NULL;
+static ssize_t (*__real_pwrite_2_2)(int fildes, const void *buf, size_t nbyte, off_t offset) = NULL;
+static ssize_t (*__real_pwrite64_2_2)(int fildes, const void *buf, size_t nbyte, off64_t offset) = NULL;
+static FILE *(*__real_fopen_2_0)(const char *filename, const char *mode) = NULL;
+static int (*__real_fclose_2_0)(FILE *stream) = NULL;
+static FILE *(*__real_fdopen_2_0)(int fildes, const char *mode) = NULL;
+static int (*__real_fgetpos_2_0)(FILE *stream, fpos_t *pos) = NULL;
+static int (*__real_fsetpos_2_0)(FILE *stream, const fpos_t *pos) = NULL;
+static int (*__real_fgetpos64_2_1)(FILE *stream, fpos64_t *pos) = NULL;
+static int (*__real_fsetpos64_2_1)(FILE *stream, const fpos64_t *pos) = NULL;
+static int (*__real_open64_2_1)(const char *path, int oflag, ...) = NULL;
+static ssize_t (*__real_pread_2_1)(int fildes, void *buf, size_t nbyte, off_t offset) = NULL;
+static ssize_t (*__real_pwrite_2_1)(int fildes, const void *buf, size_t nbyte, off_t offset) = NULL;
+static ssize_t (*__real_pwrite64_2_1)(int fildes, const void *buf, size_t nbyte, off64_t offset) = NULL;
+#endif /* ARCH() */
+#endif /* WSIZE(32) */
+
+static int
+collector_align_pktsize (int sz)
+{
+ int pktSize = sz;
+ if (sz <= 0)
+ return sz;
+ if ((sz % 8) != 0)
+ {
+ pktSize = (sz / 8) + 1;
+ pktSize *= 8;
+ }
+ return pktSize;
+}
+
+static void
+collector_memset (void *s, int c, size_t n)
+{
+ unsigned char *s1 = s;
+ while (n--)
+ *s1++ = (unsigned char) c;
+}
+
+static size_t
+collector_strlen (const char *s)
+{
+ if (s == NULL)
+ return 0;
+ int len = -1;
+ while (s[++len] != '\0')
+ ;
+ return len;
+}
+
+static size_t
+collector_strncpy (char *dst, const char *src, size_t dstsize)
+{
+ size_t i;
+ for (i = 0; i < dstsize; i++)
+ {
+ dst[i] = src[i];
+ if (src[i] == '\0')
+ break;
+ }
+ return i;
+}
+
+static char *
+collector_strchr (const char *s, int c)
+{
+ do
+ {
+ if (*s == (char) c)
+ return ((char *) s);
+ }
+ while (*s++);
+ return (NULL);
+}
+
+static FileSystem_type
+collector_fstype (const char *path)
+{
+ return UNKNOWNFS_TYPE;
+}
+
+void
+__collector_module_init (CollectorInterface *_collector_interface)
+{
+ if (_collector_interface == NULL)
+ return;
+ collector_interface = _collector_interface;
+ Tprintf (0, "iotrace: __collector_module_init\n");
+ io_hndl = collector_interface->registerModule (&module_interface);
+ /* Initialize next module */
+ ModuleInitFunc next_init = (ModuleInitFunc) dlsym (RTLD_NEXT, "__collector_module_init");
+ if (next_init != NULL)
+ next_init (_collector_interface);
+ return;
+}
+
+static int
+open_experiment (const char *exp)
+{
+ if (collector_interface == NULL)
+ {
+ Tprintf (0, "iotrace: collector_interface is null.\n");
+ return COL_ERROR_IOINIT;
+ }
+ if (io_hndl == COLLECTOR_MODULE_ERR)
+ {
+ Tprintf (0, "iotrace: handle create failed.\n");
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_IOINIT);
+ return COL_ERROR_IOINIT;
+ }
+ TprintfT (0, "iotrace: open_experiment %s\n", exp);
+ if (NULL_PTR (fopen))
+ init_io_intf ();
+ if (io_heap == NULL)
+ {
+ io_heap = collector_interface->newHeap ();
+ if (io_heap == NULL)
+ {
+ Tprintf (0, "iotrace: new heap failed.\n");
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">new iotrace heap not created</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_IOINIT);
+ return COL_ERROR_IOINIT;
+ }
+ }
+
+ const char *params = collector_interface->getParams ();
+ while (params)
+ {
+ if ((params[0] == 'i') && (params[1] == ':'))
+ {
+ params += 2;
+ break;
+ }
+ params = collector_strchr (params, ';');
+ if (params)
+ params++;
+ }
+ if (params == NULL) /* IO data collection not specified */
+ return COL_ERROR_IOINIT;
+
+ io_key = collector_interface->createKey (sizeof ( int), NULL, NULL);
+ if (io_key == (unsigned) - 1)
+ {
+ Tprintf (0, "iotrace: TSD key create failed.\n");
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_IOINIT);
+ return COL_ERROR_IOINIT;
+ }
+
+ collector_interface->writeLog ("<profile name=\"%s\">\n", SP_JCMD_IOTRACE);
+ collector_interface->writeLog (" <profdata fname=\"%s\"/>\n",
+ module_interface.description);
+ /* Record IOTrace_packet description */
+ IOTrace_packet *pp = NULL;
+ collector_interface->writeLog (" <profpckt kind=\"%d\" uname=\"IO tracing data\">\n", IOTRACE_PCKT);
+ collector_interface->writeLog (" <field name=\"LWPID\" uname=\"Lightweight process id\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"THRID\" uname=\"Thread number\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"CPUID\" uname=\"CPU id\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"High resolution timestamp\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"IOTYPE\" uname=\"IO trace function type\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->iotype, sizeof (pp->iotype) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"IOFD\" uname=\"File descriptor\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->fd, sizeof (pp->fd) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"IONBYTE\" uname=\"Number of bytes\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->nbyte, sizeof (pp->nbyte) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"IORQST\" uname=\"Time of IO requested\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->requested, sizeof (pp->requested) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"IOOFD\" uname=\"Original file descriptor\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->ofd, sizeof (pp->ofd) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"IOFSTYPE\" uname=\"File system type\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->fstype, sizeof (pp->fstype) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"IOFNAME\" uname=\"File name\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->fname, "STRING");
+ collector_interface->writeLog (" </profpckt>\n");
+ collector_interface->writeLog ("</profile>\n");
+ return COL_ERROR_NONE;
+}
+
+static int
+start_data_collection (void)
+{
+ io_mode = 1;
+ Tprintf (0, "iotrace: start_data_collection\n");
+ return 0;
+}
+
+static int
+stop_data_collection (void)
+{
+ io_mode = 0;
+ Tprintf (0, "iotrace: stop_data_collection\n");
+ return 0;
+}
+
+static int
+close_experiment (void)
+{
+ io_mode = 0;
+ io_key = COLLECTOR_TSD_INVALID_KEY;
+ if (io_heap != NULL)
+ {
+ collector_interface->deleteHeap (io_heap);
+ io_heap = NULL;
+ }
+ Tprintf (0, "iotrace: close_experiment\n");
+ return 0;
+}
+
+static int
+detach_experiment (void)
+{
+ /* fork child. Clean up state but don't write to experiment */
+ io_mode = 0;
+ io_key = COLLECTOR_TSD_INVALID_KEY;
+ if (io_heap != NULL)
+ {
+ collector_interface->deleteHeap (io_heap);
+ io_heap = NULL;
+ }
+ Tprintf (0, "iotrace: detach_experiment\n");
+ return 0;
+}
+
+static int
+init_io_intf ()
+{
+ void *dlflag;
+ int rc = 0;
+ /* if we detect recursion/reentrance, SEGV so we can get a stack */
+ static int init_io_intf_started;
+ static int init_io_intf_finished;
+ init_io_intf_started++;
+ if (!init_io_intf_finished && init_io_intf_started >= 3)
+ {
+ /* pull the plug if recursion occurs... */
+ abort ();
+ }
+
+ /* lookup fprint to print fatal error message */
+ void *ptr = dlsym (RTLD_NEXT, "fprintf");
+ if (ptr)
+ __real_fprintf = (int (*)(FILE*, const char*, ...)) ptr;
+ else
+ abort ();
+
+#if ARCH(Intel)
+#if WSIZE(32)
+#define SYS_FOPEN_X_VERSION "GLIBC_2.1"
+#define SYS_FGETPOS_X_VERSION "GLIBC_2.2"
+#define SYS_FGETPOS64_X_VERSION "GLIBC_2.2"
+#define SYS_OPEN64_X_VERSION "GLIBC_2.2"
+#define SYS_PREAD_X_VERSION "GLIBC_2.2"
+#define SYS_PWRITE_X_VERSION "GLIBC_2.2"
+#define SYS_PWRITE64_X_VERSION "GLIBC_2.2"
+#else /* WSIZE(64) */
+#define SYS_FOPEN_X_VERSION "GLIBC_2.2.5"
+#define SYS_FGETPOS_X_VERSION "GLIBC_2.2.5"
+#endif
+#elif ARCH(SPARC)
+#if WSIZE(32)
+#define SYS_FOPEN_X_VERSION "GLIBC_2.1"
+#define SYS_FGETPOS_X_VERSION "GLIBC_2.2"
+#else /* WSIZE(64) */
+#define SYS_FOPEN_X_VERSION "GLIBC_2.2"
+#define SYS_FGETPOS_X_VERSION "GLIBC_2.2"
+#endif
+#elif ARCH(Aarch64)
+#define SYS_FOPEN_X_VERSION "GLIBC_2.17"
+#define SYS_FGETPOS_X_VERSION "GLIBC_2.17"
+#endif /* ARCH() */
+
+#if WSIZE(32)
+ dlflag = RTLD_NEXT;
+ __real_fopen = (FILE * (*)(const char*, const char*))dlvsym (dlflag, "fopen", SYS_FOPEN_X_VERSION);
+ if (__real_fopen == NULL)
+ {
+ /* We are probably dlopened after libc,
+ * try to search in the previously loaded objects
+ */
+ __real_fopen = (FILE * (*)(const char*, const char*))dlvsym (RTLD_DEFAULT, "fopen", SYS_FOPEN_X_VERSION);
+ if (__real_fopen != NULL)
+ {
+ Tprintf (0, "iotrace: WARNING: init_io_intf() using RTLD_DEFAULT for Linux io routines\n");
+ dlflag = RTLD_DEFAULT;
+ }
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fopen\n");
+ rc = COL_ERROR_IOINIT;
+ }
+ }
+
+ __real_fclose = (int (*)(FILE*))dlvsym (dlflag, "fclose", SYS_FOPEN_X_VERSION);
+ if (__real_fclose == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fclose\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fdopen = (FILE * (*)(int, const char*))dlvsym (dlflag, "fdopen", SYS_FOPEN_X_VERSION);
+ if (__real_fdopen == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fdopen\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fgetpos = (int (*)(FILE*, fpos_t*))dlvsym (dlflag, "fgetpos", SYS_FGETPOS_X_VERSION);
+ if (__real_fgetpos == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgetpos\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fsetpos = (int (*)(FILE*, const fpos_t*))dlvsym (dlflag, "fsetpos", SYS_FGETPOS_X_VERSION);
+ if (__real_fsetpos == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsetpos\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+
+#if ARCH(Intel)
+ __real_fopen_2_1 = __real_fopen;
+ __real_fclose_2_1 = __real_fclose;
+ __real_fdopen_2_1 = __real_fdopen;
+ __real_fgetpos_2_2 = __real_fgetpos;
+ __real_fsetpos_2_2 = __real_fsetpos;
+
+ __real_fopen_2_0 = (FILE * (*)(const char*, const char*))dlvsym (dlflag, "fopen", "GLIBC_2.0");
+ if (__real_fopen_2_0 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fopen_2_0\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fclose_2_0 = (int (*)(FILE*))dlvsym (dlflag, "fclose", "GLIBC_2.0");
+ if (__real_fclose_2_0 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fclose_2_0\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fdopen_2_0 = (FILE * (*)(int, const char*))dlvsym (dlflag, "fdopen", "GLIBC_2.0");
+ if (__real_fdopen_2_0 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fdopen_2_0\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fgetpos_2_0 = (int (*)(FILE*, fpos_t*))dlvsym (dlflag, "fgetpos", "GLIBC_2.0");
+ if (__real_fgetpos_2_0 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgetpos_2_0\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fsetpos_2_0 = (int (*)(FILE*, const fpos_t*))dlvsym (dlflag, "fsetpos", "GLIBC_2.0");
+ if (__real_fsetpos_2_0 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsetpos_2_0\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fgetpos64_2_1 = (int (*)(FILE*, fpos64_t*))dlvsym (dlflag, "fgetpos64", "GLIBC_2.1");
+ if (__real_fgetpos64_2_1 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgetpos64_2_1\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fsetpos64_2_1 = (int (*)(FILE*, const fpos64_t*))dlvsym (dlflag, "fsetpos64", "GLIBC_2.1");
+ if (__real_fsetpos64_2_1 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsetpos64_2_1\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_open64_2_1 = (int (*)(const char*, int, ...))dlvsym (dlflag, "open64", "GLIBC_2.1");
+ if (__real_open64_2_1 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT open64_2_1\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_pread_2_1 = (int (*)(int fildes, void *buf, size_t nbyte, off_t offset))dlvsym (dlflag, "pread", "GLIBC_2.1");
+ if (__real_pread_2_1 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pread_2_1\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_pwrite_2_1 = (int (*)(int fildes, const void *buf, size_t nbyte, off_t offset))dlvsym (dlflag, "pwrite", "GLIBC_2.1");
+ if (__real_pwrite_2_1 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pwrite_2_1\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_pwrite64_2_1 = (int (*)(int fildes, const void *buf, size_t nbyte, off64_t offset))dlvsym (dlflag, "pwrite64", "GLIBC_2.1");
+ if (__real_pwrite64_2_1 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pwrite64_2_1\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fgetpos64_2_2 = (int (*)(FILE*, fpos64_t*))dlvsym (dlflag, "fgetpos64", SYS_FGETPOS64_X_VERSION);
+ if (__real_fgetpos64_2_2 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgetpos64_2_2\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fsetpos64_2_2 = (int (*)(FILE*, const fpos64_t*))dlvsym (dlflag, "fsetpos64", SYS_FGETPOS64_X_VERSION);
+ if (__real_fsetpos64_2_2 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsetpos64_2_2\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_open64_2_2 = (int (*)(const char*, int, ...))dlvsym (dlflag, "open64", SYS_OPEN64_X_VERSION);
+ if (__real_open64_2_2 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT open64_2_2\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_pread_2_2 = (int (*)(int fildes, void *buf, size_t nbyte, off_t offset))dlvsym (dlflag, "pread", SYS_PREAD_X_VERSION);
+ if (__real_pread_2_2 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pread_2_2\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_pwrite_2_2 = (int (*)(int fildes, const void *buf, size_t nbyte, off_t offset))dlvsym (dlflag, "pwrite", SYS_PWRITE_X_VERSION);
+ if (__real_pwrite_2_2 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pwrite_2_2\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_pwrite64_2_2 = (int (*)(int fildes, const void *buf, size_t nbyte, off64_t offset))dlvsym (dlflag, "pwrite64", SYS_PWRITE64_X_VERSION);
+ if (__real_pwrite64_2_2 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pwrite64_2_2\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+#endif
+
+#else /* WSIZE(64) */
+ dlflag = RTLD_NEXT;
+ __real_fopen = (FILE * (*)(const char*, const char*))dlvsym (dlflag, "fopen", SYS_FOPEN_X_VERSION);
+ if (__real_fopen == NULL)
+ {
+ /* We are probably dlopened after libc,
+ * try to search in the previously loaded objects
+ */
+ __real_fopen = (FILE * (*)(const char*, const char*))dlvsym (RTLD_DEFAULT, "fopen", SYS_FOPEN_X_VERSION);
+ if (__real_fopen != NULL)
+ {
+ Tprintf (0, "iotrace: WARNING: init_io_intf() using RTLD_DEFAULT for Linux io routines\n");
+ dlflag = RTLD_DEFAULT;
+ }
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fopen\n");
+ rc = COL_ERROR_IOINIT;
+ }
+ }
+
+ __real_fclose = (int (*)(FILE*))dlvsym (dlflag, "fclose", SYS_FOPEN_X_VERSION);
+ if (__real_fclose == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fclose\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fdopen = (FILE * (*)(int, const char*))dlvsym (dlflag, "fdopen", SYS_FOPEN_X_VERSION);
+ if (__real_fdopen == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fdopen\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fgetpos = (int (*)(FILE*, fpos_t*))dlvsym (dlflag, "fgetpos", SYS_FGETPOS_X_VERSION);
+ if (__real_fgetpos == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgetpos\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fsetpos = (int (*)(FILE*, const fpos_t*))dlvsym (dlflag, "fsetpos", SYS_FGETPOS_X_VERSION);
+ if (__real_fsetpos == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsetpos\n");
+ rc = COL_ERROR_IOINIT;
+ }
+#endif /* WSIZE(32) */
+
+ __real_open = (int (*)(const char*, int, ...))dlsym (dlflag, "open");
+ if (__real_open == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT open\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+#if WSIZE(32)
+ __real_open64 = (int (*)(const char*, int, ...))dlsym (dlflag, "open64");
+ if (__real_open64 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT open64\n");
+ rc = COL_ERROR_IOINIT;
+ }
+#endif
+
+ __real_fcntl = (int (*)(int, int, ...))dlsym (dlflag, "fcntl");
+ if (__real_fcntl == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fcntl\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_openat = (int (*)(int, const char*, int, ...))dlsym (dlflag, "openat");
+ if (__real_openat == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT openat\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_close = (int (*)(int))dlsym (dlflag, "close");
+ if (__real_close == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT close\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_dup = (int (*)(int))dlsym (dlflag, "dup");
+ if (__real_dup == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT dup\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_dup2 = (int (*)(int, int))dlsym (dlflag, "dup2");
+ if (__real_dup2 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT dup2\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_pipe = (int (*)(int[]))dlsym (dlflag, "pipe");
+ if (__real_pipe == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pipe\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_socket = (int (*)(int, int, int))dlsym (dlflag, "socket");
+ if (__real_socket == NULL)
+ {
+ __real_socket = (int (*)(int, int, int))dlsym (RTLD_NEXT, "socket");
+ if (__real_socket == NULL)
+ {
+#if 0
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERXXX_IOINIT socket\n");
+ rc = COL_ERROR_IOINIT;
+#endif
+ }
+ }
+
+ __real_mkstemp = (int (*)(char*))dlsym (dlflag, "mkstemp");
+ if (__real_mkstemp == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT mkstemp\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_mkstemps = (int (*)(char*, int))dlsym (dlflag, "mkstemps");
+ if (__real_mkstemps == NULL)
+ {
+#if 0
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERXXX_IOINIT mkstemps\n");
+ rc = COL_ERROR_IOINIT;
+#endif
+ }
+
+ __real_creat = (int (*)(const char*, mode_t))dlsym (dlflag, "creat");
+ if (__real_creat == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT creat\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+#if WSIZE(32)
+ __real_creat64 = (int (*)(const char*, mode_t))dlsym (dlflag, "creat64");
+ if (__real_creat64 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT creat64\n");
+ rc = COL_ERROR_IOINIT;
+ }
+#endif
+
+ __real_read = (ssize_t (*)(int, void*, size_t))dlsym (dlflag, "read");
+ if (__real_read == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT read\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_write = (ssize_t (*)(int, const void*, size_t))dlsym (dlflag, "write");
+ if (__real_write == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT write\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_readv = (ssize_t (*)(int, const struct iovec*, int))dlsym (dlflag, "readv");
+ if (__real_readv == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT readv\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_writev = (ssize_t (*)(int, const struct iovec*, int))dlsym (dlflag, "writev");
+ if (__real_writev == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT writev\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fread = (size_t (*)(void*, size_t, size_t, FILE*))dlsym (dlflag, "fread");
+ if (__real_fread == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fread\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fwrite = (size_t (*)(const void*, size_t, size_t, FILE*))dlsym (dlflag, "fwrite");
+ if (__real_fwrite == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fwrite\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_pread = (ssize_t (*)(int, void*, size_t, off_t))dlsym (dlflag, "pread");
+ if (__real_pread == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pread\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_pwrite = (ssize_t (*)(int, const void*, size_t, off_t))dlsym (dlflag, "pwrite");
+ if (__real_pwrite == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pwrite\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_pwrite64 = (ssize_t (*)(int, const void*, size_t, off64_t))dlsym (dlflag, "pwrite64");
+ if (__real_pwrite64 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT pwrite64\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fgets = (char* (*)(char*, int, FILE*))dlsym (dlflag, "fgets");
+ if (__real_fgets == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgets\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fputs = (int (*)(const char*, FILE*))dlsym (dlflag, "fputs");
+ if (__real_fputs == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fputs\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fputc = (int (*)(int, FILE*))dlsym (dlflag, "fputc");
+ if (__real_fputc == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fputc\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_vfprintf = (int (*)(FILE*, const char*, va_list))dlsym (dlflag, "vfprintf");
+ if (__real_vfprintf == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT vfprintf\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+
+ __real_lseek = (off_t (*)(int, off_t, int))dlsym (dlflag, "lseek");
+ if (__real_lseek == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT lseek\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_llseek = (offset_t (*)(int, offset_t, int))dlsym (dlflag, "llseek");
+ if (__real_llseek == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT llseek\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_chmod = (int (*)(const char*, mode_t))dlsym (dlflag, "chmod");
+ if (__real_chmod == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT chmod\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_access = (int (*)(const char*, int))dlsym (dlflag, "access");
+ if (__real_access == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT access\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_rename = (int (*)(const char*, const char*))dlsym (dlflag, "rename");
+ if (__real_rename == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT rename\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_mkdir = (int (*)(const char*, mode_t))dlsym (dlflag, "mkdir");
+ if (__real_mkdir == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT mkdir\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_getdents = (int (*)(int, struct dirent*, size_t))dlsym (dlflag, "getdents");
+ if (__real_getdents == NULL)
+ {
+#if 0
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERXXX_IOINIT getdents\n");
+ rc = COL_ERROR_IOINIT;
+#endif
+ }
+
+ __real_unlink = (int (*)(const char*))dlsym (dlflag, "unlink");
+ if (__real_unlink == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT unlink\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fseek = (int (*)(FILE*, long, int))dlsym (dlflag, "fseek");
+ if (__real_fseek == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fseek\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_rewind = (void (*)(FILE*))dlsym (dlflag, "rewind");
+ if (__real_rewind == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT rewind\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_ftell = (long (*)(FILE*))dlsym (dlflag, "ftell");
+ if (__real_ftell == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT ftell\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fsync = (int (*)(int))dlsym (dlflag, "fsync");
+ if (__real_fsync == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsync\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_readdir = (struct dirent * (*)(DIR*))dlsym (dlflag, "readdir");
+ if (__real_readdir == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT readdir\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_flock = (int (*)(int, int))dlsym (dlflag, "flock");
+ if (__real_flock == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT flock\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_lockf = (int (*)(int, int, off_t))dlsym (dlflag, "lockf");
+ if (__real_lockf == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT lockf\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fflush = (int (*)(FILE*))dlsym (dlflag, "fflush");
+ if (__real_fflush == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fflush\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+#if WSIZE(32)
+ __real_fgetpos64 = (int (*)(FILE*, fpos64_t*))dlsym (dlflag, "fgetpos64");
+ if (__real_fgetpos64 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fgetpos64\n");
+ rc = COL_ERROR_IOINIT;
+ }
+
+ __real_fsetpos64 = (int (*)(FILE*, const fpos64_t*))dlsym (dlflag, "fsetpos64");
+ if (__real_fsetpos64 == NULL)
+ {
+ CALL_REAL (fprintf)(stderr, "iotrace_init COL_ERROR_IOINIT fsetpos64\n");
+ rc = COL_ERROR_IOINIT;
+ }
+#endif
+ init_io_intf_finished++;
+ return rc;
+}
+
+/*------------------------------------------------------------- open */
+int
+open (const char *path, int oflag, ...)
+{
+ int *guard;
+ int fd;
+ void *packet;
+ IOTrace_packet *iopkt;
+ mode_t mode;
+ va_list ap;
+ size_t sz;
+ unsigned pktSize;
+
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+ va_end (ap);
+
+ if (NULL_PTR (open))
+ init_io_intf ();
+
+ if (CHCK_REENTRANCE (guard) || path == NULL)
+ return CALL_REAL (open)(path, oflag, mode);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ fd = CALL_REAL (open)(path, oflag, mode);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return fd;
+ }
+ hrtime_t grnt = gethrtime ();
+ sz = collector_strlen (path);
+ pktSize = sizeof (IOTrace_packet) + sz;
+ pktSize = collector_align_pktsize (pktSize);
+ Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize);
+ packet = collector_interface->allocCSize (io_heap, pktSize, 1);
+ if (packet != NULL)
+ {
+ iopkt = (IOTrace_packet *) packet;
+ collector_memset (iopkt, 0, pktSize);
+ iopkt->comm.tsize = pktSize;
+ iopkt->comm.tstamp = grnt;
+ iopkt->requested = reqt;
+ if (fd != -1)
+ iopkt->iotype = OPEN_TRACE;
+ else
+ iopkt->iotype = OPEN_TRACE_ERROR;
+ iopkt->fd = fd;
+ iopkt->fstype = collector_fstype (path);
+ collector_strncpy (&(iopkt->fname), path, sz);
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt);
+ collector_interface->freeCSize (io_heap, packet, pktSize);
+ }
+ else
+ {
+ Tprintf (0, "iotrace: ERROR: open cannot allocate memory\n");
+ return -1;
+ }
+ POP_REENTRANCE (guard);
+ return fd;
+}
+
+/*------------------------------------------------------------- open64 */
+#if ARCH(Intel) && WSIZE(32)
+// map interposed symbol versions
+static int
+__collector_open64_symver (int(real_open64) (const char *, int, ...),
+ const char *path, int oflag, mode_t mode);
+
+int
+__collector_open64_2_2 (const char *path, int oflag, ...)
+{
+ mode_t mode;
+ va_list ap;
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+ va_end (ap);
+ TprintfT (DBG_LTT,
+ "iotrace: __collector_open64_2_2@%p(path=%s, oflag=0%o, mode=0%o\n",
+ CALL_REAL (open64_2_2), path ? path : "NULL", oflag, mode);
+ if (NULL_PTR (open64))
+ init_io_intf ();
+ return __collector_open64_symver (CALL_REAL (open64_2_2), path, oflag, mode);
+}
+
+int
+__collector_open64_2_1 (const char *path, int oflag, ...)
+{
+ mode_t mode;
+ va_list ap;
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+ va_end (ap);
+ TprintfT (DBG_LTT,
+ "iotrace: __collector_open64_2_1@%p(path=%s, oflag=0%o, mode=0%o\n",
+ CALL_REAL (open64_2_1), path ? path : "NULL", oflag, mode);
+ if (NULL_PTR (open64))
+ init_io_intf ();
+ return __collector_open64_symver (CALL_REAL (open64_2_1), path, oflag, mode);
+}
+
+__asm__(".symver __collector_open64_2_2,open64@@GLIBC_2.2");
+__asm__(".symver __collector_open64_2_1,open64@GLIBC_2.1");
+
+#endif /* ARCH(Intel) && WSIZE(32) */
+#if WSIZE(32)
+#if ARCH(Intel) && WSIZE(32)
+
+static int
+__collector_open64_symver (int(real_open64) (const char *, int, ...),
+ const char *path, int oflag, mode_t mode)
+{
+ int *guard;
+ int fd;
+ void *packet;
+ IOTrace_packet *iopkt;
+ size_t sz;
+ unsigned pktSize;
+ if (NULL_PTR (open64))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || path == NULL)
+ return (real_open64) (path, oflag, mode);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ fd = real_open64 (path, oflag, mode);
+#else /* ^ARCH(Intel) && WSIZE(32) */
+
+int
+open64 (const char *path, int oflag, ...)
+{
+ int *guard;
+ int fd;
+ void *packet;
+ IOTrace_packet *iopkt;
+ mode_t mode;
+ va_list ap;
+ size_t sz;
+ unsigned pktSize;
+
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+ va_end (ap);
+ if (NULL_PTR (open64))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || path == NULL)
+ return CALL_REAL (open64)(path, oflag, mode);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ fd = CALL_REAL (open64)(path, oflag, mode);
+#endif /* ^ARCH(Intel) && WSIZE(32) */
+
+ if (RECHCK_REENTRANCE (guard) || path == NULL)
+ {
+ POP_REENTRANCE (guard);
+ return fd;
+ }
+ hrtime_t grnt = gethrtime ();
+ sz = collector_strlen (path);
+ pktSize = sizeof (IOTrace_packet) + sz;
+ pktSize = collector_align_pktsize (pktSize);
+ Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize);
+ packet = collector_interface->allocCSize (io_heap, pktSize, 1);
+ if (packet != NULL)
+ {
+ iopkt = (IOTrace_packet *) packet;
+ collector_memset (iopkt, 0, pktSize);
+ iopkt->comm.tsize = pktSize;
+ iopkt->comm.tstamp = grnt;
+ iopkt->requested = reqt;
+ if (fd != -1)
+ iopkt->iotype = OPEN_TRACE;
+ else
+ iopkt->iotype = OPEN_TRACE_ERROR;
+ iopkt->fd = fd;
+ iopkt->fstype = collector_fstype (path);
+ collector_strncpy (&(iopkt->fname), path, sz);
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt);
+ collector_interface->freeCSize (io_heap, packet, pktSize);
+ }
+ else
+ {
+ Tprintf (0, "iotrace: ERROR: open64 cannot allocate memory\n");
+ return -1;
+ }
+ POP_REENTRANCE (guard);
+ return fd;
+}
+#endif
+
+#define F_ERROR_ARG 0
+#define F_INT_ARG 1
+#define F_LONG_ARG 2
+#define F_VOID_ARG 3
+
+/*
+ * The following macro is not defined in the
+ * older versions of Linux.
+ * #define F_DUPFD_CLOEXEC 1030
+ *
+ * Instead use the command that is defined below
+ * until we start compiling mpmt on the newer
+ * versions of Linux.
+ */
+#define TMP_F_DUPFD_CLOEXEC 1030
+
+/*------------------------------------------------------------- fcntl */
+int
+fcntl (int fildes, int cmd, ...)
+{
+ int *guard;
+ int fd = 0;
+ IOTrace_packet iopkt;
+ long long_arg = 0;
+ int int_arg = 0;
+ int which_arg = F_ERROR_ARG;
+ va_list ap;
+ switch (cmd)
+ {
+ case F_DUPFD:
+ case TMP_F_DUPFD_CLOEXEC:
+ case F_SETFD:
+ case F_SETFL:
+ case F_SETOWN:
+ case F_SETSIG:
+ case F_SETLEASE:
+ case F_NOTIFY:
+ case F_SETLK:
+ case F_SETLKW:
+ case F_GETLK:
+ va_start (ap, cmd);
+ long_arg = va_arg (ap, long);
+ va_end (ap);
+ which_arg = F_LONG_ARG;
+ break;
+ case F_GETFD:
+ case F_GETFL:
+ case F_GETOWN:
+ case F_GETLEASE:
+ case F_GETSIG:
+ which_arg = F_VOID_ARG;
+ break;
+ }
+ if (NULL_PTR (fcntl))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ {
+ switch (which_arg)
+ {
+ case F_INT_ARG:
+ return CALL_REAL (fcntl)(fildes, cmd, int_arg);
+ case F_LONG_ARG:
+ return CALL_REAL (fcntl)(fildes, cmd, long_arg);
+ case F_VOID_ARG:
+ return CALL_REAL (fcntl)(fildes, cmd);
+ case F_ERROR_ARG:
+ Tprintf (0, "iotrace: ERROR: Unsupported fcntl command\n");
+ return -1;
+ }
+ return -1;
+ }
+ if (cmd != F_DUPFD && cmd != TMP_F_DUPFD_CLOEXEC)
+ {
+ switch (which_arg)
+ {
+ case F_INT_ARG:
+ return CALL_REAL (fcntl)(fildes, cmd, int_arg);
+ case F_LONG_ARG:
+ return CALL_REAL (fcntl)(fildes, cmd, long_arg);
+ case F_VOID_ARG:
+ return CALL_REAL (fcntl)(fildes, cmd);
+ case F_ERROR_ARG:
+ Tprintf (0, "iotrace: ERROR: Unsupported fcntl command\n");
+ return -1;
+ }
+ return -1;
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ switch (cmd)
+ {
+ case F_DUPFD:
+ case TMP_F_DUPFD_CLOEXEC:
+ fd = CALL_REAL (fcntl)(fildes, cmd, long_arg);
+ break;
+ }
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return fd;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (fd != -1)
+ iopkt.iotype = OPEN_TRACE;
+ else
+ iopkt.iotype = OPEN_TRACE_ERROR;
+ iopkt.fd = fd;
+ iopkt.ofd = fildes;
+ iopkt.fstype = UNKNOWNFS_TYPE;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return fd;
+}
+
+/*------------------------------------------------------------- openat */
+int
+openat (int fildes, const char *path, int oflag, ...)
+{
+ int *guard;
+ int fd;
+ void *packet;
+ IOTrace_packet *iopkt;
+ mode_t mode;
+ va_list ap;
+ size_t sz;
+ unsigned pktSize;
+
+ va_start (ap, oflag);
+ mode = va_arg (ap, mode_t);
+ va_end (ap);
+ if (NULL_PTR (openat))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || path == NULL)
+ return CALL_REAL (openat)(fildes, path, oflag, mode);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ fd = CALL_REAL (openat)(fildes, path, oflag, mode);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return fd;
+ }
+ hrtime_t grnt = gethrtime ();
+ sz = collector_strlen (path);
+ pktSize = sizeof (IOTrace_packet) + sz;
+ pktSize = collector_align_pktsize (pktSize);
+ Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize);
+ packet = collector_interface->allocCSize (io_heap, pktSize, 1);
+ if (packet != NULL)
+ {
+ iopkt = (IOTrace_packet *) packet;
+ collector_memset (iopkt, 0, pktSize);
+ iopkt->comm.tsize = pktSize;
+ iopkt->comm.tstamp = grnt;
+ iopkt->requested = reqt;
+ if (fd != -1)
+ iopkt->iotype = OPEN_TRACE;
+ else
+ iopkt->iotype = OPEN_TRACE_ERROR;
+ iopkt->fd = fd;
+ iopkt->fstype = collector_fstype (path);
+ collector_strncpy (&(iopkt->fname), path, sz);
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt);
+ collector_interface->freeCSize (io_heap, packet, pktSize);
+ }
+ else
+ {
+ Tprintf (0, "iotrace: ERROR: openat cannot allocate memory\n");
+ return -1;
+ }
+ POP_REENTRANCE (guard);
+ return fd;
+}
+
+/*------------------------------------------------------------- creat */
+int
+creat (const char *path, mode_t mode)
+{
+ int *guard;
+ int fd;
+ void *packet;
+ IOTrace_packet *iopkt;
+ size_t sz;
+ unsigned pktSize;
+ if (NULL_PTR (creat))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || path == NULL)
+ return CALL_REAL (creat)(path, mode);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ fd = CALL_REAL (creat)(path, mode);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return fd;
+ }
+ hrtime_t grnt = gethrtime ();
+ sz = collector_strlen (path);
+ pktSize = sizeof (IOTrace_packet) + sz;
+ pktSize = collector_align_pktsize (pktSize);
+ Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize);
+ packet = collector_interface->allocCSize (io_heap, pktSize, 1);
+ if (packet != NULL)
+ {
+ iopkt = (IOTrace_packet *) packet;
+ collector_memset (iopkt, 0, pktSize);
+ iopkt->comm.tsize = pktSize;
+ iopkt->comm.tstamp = grnt;
+ iopkt->requested = reqt;
+ if (fd != -1)
+ iopkt->iotype = OPEN_TRACE;
+ else
+ iopkt->iotype = OPEN_TRACE_ERROR;
+ iopkt->fd = fd;
+ iopkt->fstype = collector_fstype (path);
+ collector_strncpy (&(iopkt->fname), path, sz);
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt);
+ collector_interface->freeCSize (io_heap, packet, pktSize);
+ }
+ else
+ {
+ Tprintf (0, "iotrace: ERROR: creat cannot allocate memory\n");
+ return -1;
+ }
+ POP_REENTRANCE (guard);
+ return fd;
+}
+
+/*------------------------------------------------------------- creat64 */
+#if WSIZE(32)
+int
+creat64 (const char *path, mode_t mode)
+{
+ int *guard;
+ int fd;
+ void *packet;
+ IOTrace_packet *iopkt;
+ size_t sz;
+ unsigned pktSize;
+
+ if (NULL_PTR (creat64))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || path == NULL)
+ return CALL_REAL (creat64)(path, mode);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ fd = CALL_REAL (creat64)(path, mode);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return fd;
+ }
+ hrtime_t grnt = gethrtime ();
+ sz = collector_strlen (path);
+ pktSize = sizeof (IOTrace_packet) + sz;
+ pktSize = collector_align_pktsize (pktSize);
+ Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize);
+ packet = collector_interface->allocCSize (io_heap, pktSize, 1);
+ if (packet != NULL)
+ {
+ iopkt = (IOTrace_packet *) packet;
+ collector_memset (iopkt, 0, pktSize);
+ iopkt->comm.tsize = pktSize;
+ iopkt->comm.tstamp = grnt;
+ iopkt->requested = reqt;
+ if (fd != -1)
+ iopkt->iotype = OPEN_TRACE;
+ else
+ iopkt->iotype = OPEN_TRACE_ERROR;
+ iopkt->fd = fd;
+ iopkt->fstype = collector_fstype (path);
+ collector_strncpy (&(iopkt->fname), path, sz);
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt);
+ collector_interface->freeCSize (io_heap, packet, pktSize);
+ }
+ else
+ {
+ Tprintf (0, "iotrace: ERROR: creat64 cannot allocate memory\n");
+ return -1;
+ }
+ POP_REENTRANCE (guard);
+ return fd;
+}
+#endif
+
+/*------------------------------------------------------------- mkstemp */
+int
+mkstemp (char *template)
+{
+ int *guard;
+ int fd;
+ void *packet;
+ IOTrace_packet *iopkt;
+ size_t sz;
+ unsigned pktSize;
+ if (NULL_PTR (mkstemp))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || template == NULL)
+ return CALL_REAL (mkstemp)(template);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ fd = CALL_REAL (mkstemp)(template);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return fd;
+ }
+ hrtime_t grnt = gethrtime ();
+ sz = collector_strlen (template);
+ pktSize = sizeof (IOTrace_packet) + sz;
+ pktSize = collector_align_pktsize (pktSize);
+ Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize);
+ packet = collector_interface->allocCSize (io_heap, pktSize, 1);
+ if (packet != NULL)
+ {
+ iopkt = (IOTrace_packet *) packet;
+ collector_memset (iopkt, 0, pktSize);
+ iopkt->comm.tsize = pktSize;
+ iopkt->comm.tstamp = grnt;
+ iopkt->requested = reqt;
+ if (fd != -1)
+ iopkt->iotype = OPEN_TRACE;
+ else
+ iopkt->iotype = OPEN_TRACE_ERROR;
+ iopkt->fd = fd;
+ iopkt->fstype = collector_fstype (template);
+ collector_strncpy (&(iopkt->fname), template, sz);
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt);
+ collector_interface->freeCSize (io_heap, packet, pktSize);
+ }
+ else
+ {
+ Tprintf (0, "iotrace: ERROR: mkstemp cannot allocate memory\n");
+ return -1;
+ }
+ POP_REENTRANCE (guard);
+ return fd;
+}
+
+/*------------------------------------------------------------- mkstemps */
+int
+mkstemps (char *template, int slen)
+{
+ int *guard;
+ int fd;
+ void *packet;
+ IOTrace_packet *iopkt;
+ size_t sz;
+ unsigned pktSize;
+ if (NULL_PTR (mkstemps))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || template == NULL)
+ return CALL_REAL (mkstemps)(template, slen);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ fd = CALL_REAL (mkstemps)(template, slen);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return fd;
+ }
+ hrtime_t grnt = gethrtime ();
+ sz = collector_strlen (template);
+ pktSize = sizeof (IOTrace_packet) + sz;
+ pktSize = collector_align_pktsize (pktSize);
+ Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize);
+ packet = collector_interface->allocCSize (io_heap, pktSize, 1);
+ if (packet != NULL)
+ {
+ iopkt = (IOTrace_packet *) packet;
+ collector_memset (iopkt, 0, pktSize);
+ iopkt->comm.tsize = pktSize;
+ iopkt->comm.tstamp = grnt;
+ iopkt->requested = reqt;
+ if (fd != -1)
+ iopkt->iotype = OPEN_TRACE;
+ else
+ iopkt->iotype = OPEN_TRACE_ERROR;
+ iopkt->fd = fd;
+ iopkt->fstype = collector_fstype (template);
+ collector_strncpy (&(iopkt->fname), template, sz);
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt);
+ collector_interface->freeCSize (io_heap, packet, pktSize);
+ }
+ else
+ {
+ Tprintf (0, "iotrace: ERROR: mkstemps cannot allocate memory\n");
+ return -1;
+ }
+ POP_REENTRANCE (guard);
+ return fd;
+}
+
+/*------------------------------------------------------------- close */
+int
+close (int fildes)
+{
+ int *guard;
+ int stat;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (close))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (close)(fildes);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ stat = CALL_REAL (close)(fildes);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return stat;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (stat == 0)
+ iopkt.iotype = CLOSE_TRACE;
+ else
+ iopkt.iotype = CLOSE_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return stat;
+}
+
+/*------------------------------------------------------------- fopen */
+// map interposed symbol versions
+#if ARCH(Intel) && WSIZE(32)
+
+static FILE*
+__collector_fopen_symver (FILE*(real_fopen) (), const char *filename, const char *mode);
+
+FILE*
+__collector_fopen_2_1 (const char *filename, const char *mode)
+{
+ if (NULL_PTR (fopen))
+ init_io_intf ();
+ TprintfT (DBG_LTT, "iotrace: __collector_fopen_2_1@%p\n", CALL_REAL (fopen_2_1));
+ return __collector_fopen_symver (CALL_REAL (fopen_2_1), filename, mode);
+}
+
+FILE*
+__collector_fopen_2_0 (const char *filename, const char *mode)
+{
+ if (NULL_PTR (fopen))
+ init_io_intf ();
+ TprintfT (DBG_LTT, "iotrace: __collector_fopen_2_0@%p\n", CALL_REAL (fopen_2_0));
+ return __collector_fopen_symver (CALL_REAL (fopen_2_0), filename, mode);
+}
+
+__asm__(".symver __collector_fopen_2_1,fopen@@GLIBC_2.1");
+__asm__(".symver __collector_fopen_2_0,fopen@GLIBC_2.0");
+
+#endif
+
+#if ARCH(Intel) && WSIZE(32)
+
+static FILE*
+__collector_fopen_symver (FILE*(real_fopen) (), const char *filename, const char *mode)
+{
+#else
+
+FILE*
+fopen (const char *filename, const char *mode)
+{
+#endif
+ int *guard;
+ FILE *fp = NULL;
+ void *packet;
+ IOTrace_packet *iopkt;
+ size_t sz;
+ unsigned pktSize;
+ if (NULL_PTR (fopen))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || filename == NULL)
+ {
+#if ARCH(Intel) && WSIZE(32)
+ return (real_fopen) (filename, mode);
+#else
+ return CALL_REAL (fopen)(filename, mode);
+#endif
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+
+#if ARCH(Intel) && WSIZE(32)
+ fp = (real_fopen) (filename, mode);
+#else
+ fp = CALL_REAL (fopen)(filename, mode);
+#endif
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return fp;
+ }
+ hrtime_t grnt = gethrtime ();
+ sz = collector_strlen (filename);
+ pktSize = sizeof (IOTrace_packet) + sz;
+ pktSize = collector_align_pktsize (pktSize);
+ Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize);
+ packet = collector_interface->allocCSize (io_heap, pktSize, 1);
+ if (packet != NULL)
+ {
+ iopkt = (IOTrace_packet *) packet;
+ collector_memset (iopkt, 0, pktSize);
+ iopkt->comm.tsize = pktSize;
+ iopkt->comm.tstamp = grnt;
+ iopkt->requested = reqt;
+ if (fp != NULL)
+ {
+ iopkt->iotype = OPEN_TRACE;
+ iopkt->fd = fileno (fp);
+ }
+ else
+ {
+ iopkt->iotype = OPEN_TRACE_ERROR;
+ iopkt->fd = -1;
+ }
+ iopkt->fstype = collector_fstype (filename);
+ collector_strncpy (&(iopkt->fname), filename, sz);
+
+#if ARCH(Intel) && WSIZE(32)
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt);
+#else
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+#endif
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt);
+ collector_interface->freeCSize (io_heap, packet, pktSize);
+ }
+ else
+ {
+ Tprintf (0, "iotrace: ERROR: fopen cannot allocate memory\n");
+ return NULL;
+ }
+ POP_REENTRANCE (guard);
+ return fp;
+}
+
+/*------------------------------------------------------------- fclose */
+// map interposed symbol versions
+#if ARCH(Intel) && WSIZE(32)
+
+static int
+__collector_fclose_symver (int(real_fclose) (), FILE *stream);
+
+int
+__collector_fclose_2_1 (FILE *stream)
+{
+ if (NULL_PTR (fclose))
+ init_io_intf ();
+ TprintfT (DBG_LTT, "iotrace: __collector_fclose_2_1@%p\n", CALL_REAL (fclose_2_1));
+ return __collector_fclose_symver (CALL_REAL (fclose_2_1), stream);
+}
+
+int
+__collector_fclose_2_0 (FILE *stream)
+{
+ if (NULL_PTR (fclose))
+ init_io_intf ();
+ TprintfT (DBG_LTT, "iotrace: __collector_fclose_2_0@%p\n", CALL_REAL (fclose_2_0));
+ return __collector_fclose_symver (CALL_REAL (fclose_2_0), stream);
+}
+
+__asm__(".symver __collector_fclose_2_1,fclose@@GLIBC_2.1");
+__asm__(".symver __collector_fclose_2_0,fclose@GLIBC_2.0");
+
+#endif
+
+#if ARCH(Intel) && WSIZE(32)
+
+static int
+__collector_fclose_symver (int(real_fclose) (), FILE *stream)
+{
+#else
+
+int
+fclose (FILE *stream)
+{
+#endif
+ int *guard;
+ int stat;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fclose))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ {
+#if ARCH(Intel) && WSIZE(32)
+ return (real_fclose) (stream);
+#else
+ return CALL_REAL (fclose)(stream);
+#endif
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+#if ARCH(Intel) && WSIZE(32)
+ stat = (real_fclose) (stream);
+#else
+ stat = CALL_REAL (fclose)(stream);
+#endif
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return stat;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (stat == 0)
+ iopkt.iotype = CLOSE_TRACE;
+ else
+ iopkt.iotype = CLOSE_TRACE_ERROR;
+ iopkt.fd = fileno (stream);
+
+#if ARCH(Intel) && WSIZE(32)
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt);
+#else
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+#endif
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return stat;
+}
+
+/*------------------------------------------------------------- fflush */
+int
+fflush (FILE *stream)
+{
+ int *guard;
+ int stat;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fflush))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (fflush)(stream);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ stat = CALL_REAL (fflush)(stream);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return stat;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (stat == 0)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ if (stream != NULL)
+ iopkt.fd = fileno (stream);
+ else
+ iopkt.fd = -1;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return stat;
+}
+
+/*------------------------------------------------------------- fdopen */
+// map interposed symbol versions
+#if ARCH(Intel) && WSIZE(32)
+
+static FILE*
+__collector_fdopen_symver (FILE*(real_fdopen) (), int fildes, const char *mode);
+
+FILE*
+__collector_fdopen_2_1 (int fildes, const char *mode)
+{
+ if (NULL_PTR (fdopen))
+ init_io_intf ();
+ TprintfT (DBG_LTT, "iotrace: __collector_fdopen_2_1@%p\n", CALL_REAL (fdopen_2_1));
+ return __collector_fdopen_symver (CALL_REAL (fdopen_2_1), fildes, mode);
+}
+
+FILE*
+__collector_fdopen_2_0 (int fildes, const char *mode)
+{
+ if (NULL_PTR (fdopen))
+ init_io_intf ();
+ TprintfT (DBG_LTT, "iotrace: __collector_fdopen_2_0@%p\n", CALL_REAL (fdopen_2_0));
+ return __collector_fdopen_symver (CALL_REAL (fdopen_2_0), fildes, mode);
+}
+
+__asm__(".symver __collector_fdopen_2_1,fdopen@@GLIBC_2.1");
+__asm__(".symver __collector_fdopen_2_0,fdopen@GLIBC_2.0");
+
+#endif
+
+#if ARCH(Intel) && WSIZE(32)
+static FILE*
+__collector_fdopen_symver (FILE*(real_fdopen) (), int fildes, const char *mode)
+{
+#else
+FILE*
+fdopen (int fildes, const char *mode)
+{
+#endif
+ int *guard;
+ FILE *fp = NULL;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fdopen))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ {
+#if ARCH(Intel) && WSIZE(32)
+ return (real_fdopen) (fildes, mode);
+#else
+ return CALL_REAL (fdopen)(fildes, mode);
+#endif
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+#if ARCH(Intel) && WSIZE(32)
+ fp = (real_fdopen) (fildes, mode);
+#else
+ fp = CALL_REAL (fdopen)(fildes, mode);
+#endif
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return fp;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (fp != NULL)
+ iopkt.iotype = OPEN_TRACE;
+ else
+ iopkt.iotype = OPEN_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.fstype = UNKNOWNFS_TYPE;
+#if ARCH(Intel) && WSIZE(32)
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt);
+#else
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+#endif
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return fp;
+}
+
+/*------------------------------------------------------------- dup */
+int
+dup (int fildes)
+{
+ int *guard;
+ int fd;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (dup))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (dup)(fildes);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ fd = CALL_REAL (dup)(fildes);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return fd;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (fd != -1)
+ iopkt.iotype = OPEN_TRACE;
+ else
+ iopkt.iotype = OPEN_TRACE_ERROR;
+
+ iopkt.fd = fd;
+ iopkt.ofd = fildes;
+ iopkt.fstype = UNKNOWNFS_TYPE;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return fd;
+}
+
+/*------------------------------------------------------------- dup2 */
+int
+dup2 (int fildes, int fildes2)
+{
+ int *guard;
+ int fd;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (dup2))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (dup2)(fildes, fildes2);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ fd = CALL_REAL (dup2)(fildes, fildes2);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return fd;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (fd != -1)
+ iopkt.iotype = OPEN_TRACE;
+ else
+ iopkt.iotype = OPEN_TRACE_ERROR;
+ iopkt.fd = fd;
+ iopkt.ofd = fildes;
+ iopkt.fstype = UNKNOWNFS_TYPE;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return fd;
+}
+
+/*------------------------------------------------------------- pipe */
+int
+pipe (int fildes[2])
+{
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (pipe))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (pipe)(fildes);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (pipe)(fildes);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret != -1)
+ iopkt.iotype = OPEN_TRACE;
+ else
+ iopkt.iotype = OPEN_TRACE_ERROR;
+ iopkt.fd = fildes[0];
+ iopkt.fstype = UNKNOWNFS_TYPE;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret != -1)
+ iopkt.iotype = OPEN_TRACE;
+ else
+ iopkt.iotype = OPEN_TRACE_ERROR;
+ iopkt.fd = fildes[1];
+ iopkt.fstype = UNKNOWNFS_TYPE;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- socket */
+int
+socket (int domain, int type, int protocol)
+{
+ int *guard;
+ int fd;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (socket))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (socket)(domain, type, protocol);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ fd = CALL_REAL (socket)(domain, type, protocol);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return fd;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (fd != -1)
+ iopkt.iotype = OPEN_TRACE;
+ else
+ iopkt.iotype = OPEN_TRACE_ERROR;
+ iopkt.fd = fd;
+ iopkt.fstype = UNKNOWNFS_TYPE;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return fd;
+}
+
+/*------------------------------------------------------------- read */
+ssize_t
+read (int fildes, void *buf, size_t nbyte)
+{
+ int *guard;
+ ssize_t ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (read))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (read)(fildes, buf, nbyte);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (read)(fildes, buf, nbyte);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret >= 0)
+ iopkt.iotype = READ_TRACE;
+ else
+ iopkt.iotype = READ_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.nbyte = ret;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- write */
+ssize_t
+write (int fildes, const void *buf, size_t nbyte)
+{
+ int *guard;
+ ssize_t ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (write))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (write)(fildes, buf, nbyte);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (write)(fildes, buf, nbyte);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret >= 0)
+ iopkt.iotype = WRITE_TRACE;
+ else
+ iopkt.iotype = WRITE_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.nbyte = ret;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- readv */
+ssize_t
+readv (int fildes, const struct iovec *iov, int iovcnt)
+{
+ int *guard;
+ ssize_t ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (readv))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (readv)(fildes, iov, iovcnt);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (readv)(fildes, iov, iovcnt);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret >= 0)
+ iopkt.iotype = READ_TRACE;
+ else
+ iopkt.iotype = READ_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.nbyte = ret;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- writev */
+ssize_t
+writev (int fildes, const struct iovec *iov, int iovcnt)
+{
+ int *guard;
+ ssize_t ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (writev))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (writev)(fildes, iov, iovcnt);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (writev)(fildes, iov, iovcnt);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret >= 0)
+ iopkt.iotype = WRITE_TRACE;
+ else
+ iopkt.iotype = WRITE_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.nbyte = ret;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- fread */
+size_t
+fread (void *ptr, size_t size, size_t nitems, FILE *stream)
+{
+ int *guard;
+ size_t ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fread))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ return CALL_REAL (fread)(ptr, size, nitems, stream);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (fread)(ptr, size, nitems, stream);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ferror (stream) == 0)
+ {
+ iopkt.iotype = READ_TRACE;
+ iopkt.nbyte = ret * size;
+ }
+ else
+ {
+ iopkt.iotype = READ_TRACE_ERROR;
+ iopkt.nbyte = 0;
+ }
+ iopkt.fd = fileno (stream);
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- fwrite */
+size_t
+fwrite (const void *ptr, size_t size, size_t nitems, FILE *stream)
+{
+ int *guard;
+ size_t ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fwrite))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ return CALL_REAL (fwrite)(ptr, size, nitems, stream);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (fwrite)(ptr, size, nitems, stream);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ferror (stream) == 0)
+ {
+ iopkt.iotype = WRITE_TRACE;
+ iopkt.nbyte = ret * size;
+ }
+ else
+ {
+ iopkt.iotype = WRITE_TRACE_ERROR;
+ iopkt.nbyte = 0;
+ }
+ iopkt.fd = fileno (stream);
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- pread */
+#if ARCH(Intel) && WSIZE(32)
+// map interposed symbol versions
+static int
+__collector_pread_symver (int(real_pread) (), int fildes, void *buf, size_t nbyte, off_t offset);
+
+int
+__collector_pread_2_2 (int fildes, void *buf, size_t nbyte, off_t offset)
+{
+ TprintfT (DBG_LTT, "iotrace: __collector_pread_2_2@%p(fildes=%d, buf=%p, nbyte=%lld, offset=%lld)\n",
+ CALL_REAL (pread_2_2), fildes, buf, (long long) nbyte, (long long) offset);
+ if (NULL_PTR (pread))
+ init_io_intf ();
+ return __collector_pread_symver (CALL_REAL (pread_2_2), fildes, buf, nbyte, offset);
+}
+
+int
+__collector_pread_2_1 (int fildes, void *buf, size_t nbyte, off_t offset)
+{
+ TprintfT (DBG_LTT, "iotrace: __collector_pread_2_1@%p(fildes=%d, buf=%p, nbyte=%lld, offset=%lld)\n",
+ CALL_REAL (pread_2_1), fildes, buf, (long long) nbyte, (long long) offset);
+ if (NULL_PTR (pread))
+ init_io_intf ();
+ return __collector_pread_symver (CALL_REAL (pread_2_1), fildes, buf, nbyte, offset);
+}
+
+__asm__(".symver __collector_pread_2_2,pread@@GLIBC_2.2");
+__asm__(".symver __collector_pread_2_1,pread@GLIBC_2.1");
+
+static int
+__collector_pread_symver (int(real_pread) (), int fildes, void *buf, size_t nbyte, off_t offset)
+{
+#else /* ^ARCH(Intel) && WSIZE(32) */
+
+ssize_t
+pread (int fildes, void *buf, size_t nbyte, off_t offset)
+{
+#endif
+ int *guard;
+ ssize_t ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (pread))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ {
+#if ARCH(Intel) && WSIZE(32)
+ return (real_pread) (fildes, buf, nbyte, offset);
+#else
+ return CALL_REAL (pread)(fildes, buf, nbyte, offset);
+#endif
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+#if ARCH(Intel) && WSIZE(32)
+ ret = (real_pread) (fildes, buf, nbyte, offset);
+#else
+ ret = CALL_REAL (pread)(fildes, buf, nbyte, offset);
+#endif
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret >= 0)
+ iopkt.iotype = READ_TRACE;
+ else
+ iopkt.iotype = READ_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.nbyte = ret;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- pwrite */
+#if ARCH(Intel) && WSIZE(32)
+// map interposed symbol versions
+static int
+__collector_pwrite_symver (int(real_pwrite) (), int fildes, const void *buf, size_t nbyte, off_t offset);
+
+int
+__collector_pwrite_2_2 (int fildes, const void *buf, size_t nbyte, off_t offset)
+{
+ TprintfT (DBG_LTT, "iotrace: __collector_pwrite_2_2@%p(fildes=%d, buf=%p, nbyte=%lld, offset=%lld)\n",
+ CALL_REAL (pwrite_2_2), fildes, buf, (long long) nbyte, (long long) offset);
+ if (NULL_PTR (pwrite))
+ init_io_intf ();
+ return __collector_pwrite_symver (CALL_REAL (pwrite_2_2), fildes, buf, nbyte, offset);
+}
+
+int
+__collector_pwrite_2_1 (int fildes, const void *buf, size_t nbyte, off_t offset)
+{
+ TprintfT (DBG_LTT, "iotrace: __collector_pwrite_2_1@%p(fildes=%d, buf=%p, nbyte=%lld, offset=%lld)\n",
+ CALL_REAL (pwrite_2_1), fildes, buf, (long long) nbyte, (long long) offset);
+ if (NULL_PTR (pwrite))
+ init_io_intf ();
+ return __collector_pwrite_symver (CALL_REAL (pwrite_2_1), fildes, buf, nbyte, offset);
+}
+
+__asm__(".symver __collector_pwrite_2_2,pwrite@@GLIBC_2.2");
+__asm__(".symver __collector_pwrite_2_1,pwrite@GLIBC_2.1");
+
+static int
+__collector_pwrite_symver (int(real_pwrite) (), int fildes, const void *buf, size_t nbyte, off_t offset)
+{
+#else /* ^ARCH(Intel) && WSIZE(32) */
+
+ssize_t
+pwrite (int fildes, const void *buf, size_t nbyte, off_t offset)
+{
+#endif /* ^ARCH(Intel) && WSIZE(32) */
+ int *guard;
+ ssize_t ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (pwrite))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ {
+#if ARCH(Intel) && WSIZE(32)
+ return (real_pwrite) (fildes, buf, nbyte, offset);
+#else
+ return CALL_REAL (pwrite)(fildes, buf, nbyte, offset);
+#endif
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+#if ARCH(Intel) && WSIZE(32)
+ ret = (real_pwrite) (fildes, buf, nbyte, offset);
+#else
+ ret = CALL_REAL (pwrite)(fildes, buf, nbyte, offset);
+#endif
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret >= 0)
+ iopkt.iotype = WRITE_TRACE;
+ else
+ iopkt.iotype = WRITE_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.nbyte = ret;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- pwrite64 */
+#if ARCH(Intel) && WSIZE(32)
+// map interposed symbol versions
+static int
+__collector_pwrite64_symver (int(real_pwrite64) (), int fildes, const void *buf, size_t nbyte, off64_t offset);
+
+int
+__collector_pwrite64_2_2 (int fildes, const void *buf, size_t nbyte, off64_t offset)
+{
+ TprintfT (DBG_LTT, "iotrace: __collector_pwrite64_2_2@%p(fildes=%d, buf=%p, nbyte=%lld, offset=%lld)\n",
+ CALL_REAL (pwrite64_2_2), fildes, buf, (long long) nbyte, (long long) offset);
+ if (NULL_PTR (pwrite64))
+ init_io_intf ();
+ return __collector_pwrite64_symver (CALL_REAL (pwrite64_2_2), fildes, buf, nbyte, offset);
+}
+
+int
+__collector_pwrite64_2_1 (int fildes, const void *buf, size_t nbyte, off64_t offset)
+{
+ TprintfT (DBG_LTT, "iotrace: __collector_pwrite64_2_1@%p(fildes=%d, buf=%p, nbyte=%lld, offset=%lld)\n",
+ CALL_REAL (pwrite64_2_1), fildes, buf, (long long) nbyte, (long long) offset);
+ if (NULL_PTR (pwrite64))
+ init_io_intf ();
+ return __collector_pwrite64_symver (CALL_REAL (pwrite64_2_1), fildes, buf, nbyte, offset);
+}
+
+__asm__(".symver __collector_pwrite64_2_2,pwrite64@@GLIBC_2.2");
+__asm__(".symver __collector_pwrite64_2_1,pwrite64@GLIBC_2.1");
+
+static int
+__collector_pwrite64_symver (int(real_pwrite64) (), int fildes, const void *buf, size_t nbyte, off64_t offset)
+{
+#else /* ^ARCH(Intel) && WSIZE(32) */
+
+ssize_t
+pwrite64 (int fildes, const void *buf, size_t nbyte, off64_t offset)
+{
+#endif /* ^ARCH(Intel) && WSIZE(32) */
+ int *guard;
+ ssize_t ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (pwrite64))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ {
+#if ARCH(Intel) && WSIZE(32)
+ return (real_pwrite64) (fildes, buf, nbyte, offset);
+#else
+ return CALL_REAL (pwrite64)(fildes, buf, nbyte, offset);
+#endif
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+#if ARCH(Intel) && WSIZE(32)
+ ret = (real_pwrite64) (fildes, buf, nbyte, offset);
+#else
+ ret = CALL_REAL (pwrite64)(fildes, buf, nbyte, offset);
+#endif
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret >= 0)
+ iopkt.iotype = WRITE_TRACE;
+ else
+ iopkt.iotype = WRITE_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.nbyte = ret;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- fgets */
+char*
+fgets (char *s, int n, FILE *stream)
+{
+ int *guard;
+ char *ptr;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fgets))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ return CALL_REAL (fgets)(s, n, stream);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ptr = CALL_REAL (fgets)(s, n, stream);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ptr;
+ }
+ int error = errno;
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ptr != NULL)
+ {
+ iopkt.iotype = READ_TRACE;
+ iopkt.nbyte = collector_strlen (ptr);
+ }
+ else if (ptr == NULL && error != EAGAIN && error != EBADF && error != EINTR &&
+ error != EIO && error != EOVERFLOW && error != ENOMEM && error != ENXIO)
+ {
+ iopkt.iotype = READ_TRACE;
+ iopkt.nbyte = 0;
+ }
+ else
+ iopkt.iotype = READ_TRACE_ERROR;
+ iopkt.fd = fileno (stream);
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ptr;
+}
+
+/*------------------------------------------------------------- fputs */
+int
+fputs (const char *s, FILE *stream)
+{
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fputs))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ return CALL_REAL (fputs)(s, stream);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (fputs)(s, stream);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret != EOF)
+ {
+ iopkt.iotype = WRITE_TRACE;
+ iopkt.nbyte = ret;
+ }
+ else
+ {
+ iopkt.iotype = WRITE_TRACE_ERROR;
+ iopkt.nbyte = 0;
+ }
+ iopkt.fd = fileno (stream);
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- fputc */
+int
+fputc (int c, FILE *stream)
+{
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fputc))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ return CALL_REAL (fputc)(c, stream);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (fputc)(c, stream);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret != EOF)
+ {
+ iopkt.iotype = WRITE_TRACE;
+ iopkt.nbyte = ret;
+ }
+ else
+ {
+ iopkt.iotype = WRITE_TRACE_ERROR;
+ iopkt.nbyte = 0;
+ }
+ iopkt.fd = fileno (stream);
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- fprintf */
+int
+fprintf (FILE *stream, const char *format, ...)
+{
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ va_list ap;
+ va_start (ap, format);
+ if (NULL_PTR (fprintf))
+ init_io_intf ();
+ if (NULL_PTR (vfprintf))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ return CALL_REAL (vfprintf)(stream, format, ap);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (vfprintf)(stream, format, ap);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret >= 0)
+ iopkt.iotype = WRITE_TRACE;
+ else
+ iopkt.iotype = WRITE_TRACE_ERROR;
+ iopkt.fd = fileno (stream);
+ iopkt.nbyte = ret;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- vfprintf */
+int
+vfprintf (FILE *stream, const char *format, va_list ap)
+{
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (vfprintf))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ return CALL_REAL (vfprintf)(stream, format, ap);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (vfprintf)(stream, format, ap);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret >= 0)
+ iopkt.iotype = WRITE_TRACE;
+ else
+ iopkt.iotype = WRITE_TRACE_ERROR;
+ iopkt.fd = fileno (stream);
+ iopkt.nbyte = ret;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- lseek */
+off_t
+lseek (int fildes, off_t offset, int whence)
+{
+ int *guard;
+ off_t ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (lseek))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (lseek)(fildes, offset, whence);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (lseek)(fildes, offset, whence);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret != -1)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- llseek */
+offset_t
+llseek (int fildes, offset_t offset, int whence)
+{
+ int *guard;
+ offset_t ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (llseek))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (llseek)(fildes, offset, whence);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (llseek)(fildes, offset, whence);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret != -1)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- chmod */
+int
+chmod (const char *path, mode_t mode)
+{
+ int *guard;
+ int ret;
+ void *packet;
+ IOTrace_packet *iopkt;
+ size_t sz;
+ unsigned pktSize;
+ if (NULL_PTR (chmod))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || path == NULL)
+ return CALL_REAL (chmod)(path, mode);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (chmod)(path, mode);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ sz = collector_strlen (path);
+ pktSize = sizeof (IOTrace_packet) + sz;
+ pktSize = collector_align_pktsize (pktSize);
+ Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize);
+ packet = collector_interface->allocCSize (io_heap, pktSize, 1);
+ if (packet != NULL)
+ {
+ iopkt = (IOTrace_packet *) packet;
+ collector_memset (iopkt, 0, pktSize);
+ iopkt->comm.tsize = pktSize;
+ iopkt->comm.tstamp = grnt;
+ iopkt->requested = reqt;
+ if (ret != -1)
+ iopkt->iotype = OTHERIO_TRACE;
+ else
+ iopkt->iotype = OTHERIO_TRACE_ERROR;
+ collector_strncpy (&(iopkt->fname), path, sz);
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt);
+ collector_interface->freeCSize (io_heap, packet, pktSize);
+ }
+ else
+ {
+ Tprintf (0, "iotrace: ERROR: chmod cannot allocate memory\n");
+ return 0;
+ }
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- access */
+int
+access (const char *path, int amode)
+{
+ int *guard;
+ int ret;
+ void *packet;
+ IOTrace_packet *iopkt;
+ size_t sz;
+ unsigned pktSize;
+ if (NULL_PTR (access))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || path == NULL)
+ return CALL_REAL (access)(path, amode);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (access)(path, amode);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ sz = collector_strlen (path);
+ pktSize = sizeof (IOTrace_packet) + sz;
+ pktSize = collector_align_pktsize (pktSize);
+ Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize);
+ packet = collector_interface->allocCSize (io_heap, pktSize, 1);
+ if (packet != NULL)
+ {
+ iopkt = (IOTrace_packet *) packet;
+ collector_memset (iopkt, 0, pktSize);
+ iopkt->comm.tsize = pktSize;
+ iopkt->comm.tstamp = grnt;
+ iopkt->requested = reqt;
+ if (ret != -1)
+ iopkt->iotype = OTHERIO_TRACE;
+ else
+ iopkt->iotype = OTHERIO_TRACE_ERROR;
+ collector_strncpy (&(iopkt->fname), path, sz);
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt);
+ collector_interface->freeCSize (io_heap, packet, pktSize);
+ }
+ else
+ {
+ Tprintf (0, "iotrace: ERROR: access cannot allocate memory\n");
+ return 0;
+ }
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- rename */
+int
+rename (const char *old, const char *new)
+{
+ int *guard;
+ int ret;
+ void *packet;
+ IOTrace_packet *iopkt;
+ size_t sz;
+ unsigned pktSize;
+ if (NULL_PTR (rename))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || new == NULL)
+ return CALL_REAL (rename)(old, new);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (rename)(old, new);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ sz = collector_strlen (new);
+ pktSize = sizeof (IOTrace_packet) + sz;
+ pktSize = collector_align_pktsize (pktSize);
+ Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize);
+ packet = collector_interface->allocCSize (io_heap, pktSize, 1);
+ if (packet != NULL)
+ {
+ iopkt = (IOTrace_packet *) packet;
+ collector_memset (iopkt, 0, pktSize);
+ iopkt->comm.tsize = pktSize;
+ iopkt->comm.tstamp = grnt;
+ iopkt->requested = reqt;
+ if (ret != -1)
+ iopkt->iotype = OTHERIO_TRACE;
+ else
+ iopkt->iotype = OTHERIO_TRACE_ERROR;
+ collector_strncpy (&(iopkt->fname), new, sz);
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt);
+ collector_interface->freeCSize (io_heap, packet, pktSize);
+ }
+ else
+ {
+ Tprintf (0, "iotrace: ERROR: rename cannot allocate memory\n");
+ return 0;
+ }
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- mkdir */
+int
+mkdir (const char *path, mode_t mode)
+{
+ int *guard;
+ int ret;
+ void *packet;
+ IOTrace_packet *iopkt;
+ size_t sz;
+ unsigned pktSize;
+ if (NULL_PTR (mkdir))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || path == NULL)
+ return CALL_REAL (mkdir)(path, mode);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (mkdir)(path, mode);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ sz = collector_strlen (path);
+ pktSize = sizeof (IOTrace_packet) + sz;
+ pktSize = collector_align_pktsize (pktSize);
+ Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize);
+ packet = collector_interface->allocCSize (io_heap, pktSize, 1);
+ if (packet != NULL)
+ {
+ iopkt = (IOTrace_packet *) packet;
+ collector_memset (iopkt, 0, pktSize);
+ iopkt->comm.tsize = pktSize;
+ iopkt->comm.tstamp = grnt;
+ iopkt->requested = reqt;
+ if (ret != -1)
+ iopkt->iotype = OTHERIO_TRACE;
+ else
+ iopkt->iotype = OTHERIO_TRACE_ERROR;
+ collector_strncpy (&(iopkt->fname), path, sz);
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt);
+ collector_interface->freeCSize (io_heap, packet, pktSize);
+ }
+ else
+ {
+ Tprintf (0, "iotrace: ERROR: mkdir cannot allocate memory\n");
+ return 0;
+ }
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- getdents */
+int
+getdents (int fildes, struct dirent *buf, size_t nbyte)
+{
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (getdents))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (getdents)(fildes, buf, nbyte);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (getdents)(fildes, buf, nbyte);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret != -1)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- unlink */
+int
+unlink (const char *path)
+{
+ int *guard;
+ int ret;
+ void *packet;
+ IOTrace_packet *iopkt;
+ size_t sz;
+ unsigned pktSize;
+ if (NULL_PTR (unlink))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || path == NULL)
+ return CALL_REAL (unlink)(path);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (unlink)(path);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ sz = collector_strlen (path);
+ pktSize = sizeof (IOTrace_packet) + sz;
+ pktSize = collector_align_pktsize (pktSize);
+ Tprintf (DBG_LT1, "iotrace allocating %u from io_heap\n", pktSize);
+ packet = collector_interface->allocCSize (io_heap, pktSize, 1);
+ if (packet != NULL)
+ {
+ iopkt = (IOTrace_packet *) packet;
+ collector_memset (iopkt, 0, pktSize);
+ iopkt->comm.tsize = pktSize;
+ iopkt->comm.tstamp = grnt;
+ iopkt->requested = reqt;
+ if (ret != -1)
+ iopkt->iotype = OTHERIO_TRACE;
+ else
+ iopkt->iotype = OTHERIO_TRACE_ERROR;
+ collector_strncpy (&(iopkt->fname), path, sz);
+ iopkt->comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt->comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) iopkt);
+ collector_interface->freeCSize (io_heap, packet, pktSize);
+ }
+ else
+ {
+ Tprintf (0, "iotrace: ERROR: unlink cannot allocate memory\n");
+ return 0;
+ }
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- fseek */
+int
+fseek (FILE *stream, long offset, int whence)
+{
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fseek))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ return CALL_REAL (fseek)(stream, offset, whence);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (fseek)(stream, offset, whence);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret != -1)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ iopkt.fd = fileno (stream);
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- rewind */
+void
+rewind (FILE *stream)
+{
+ int *guard;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (rewind))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ {
+ CALL_REAL (rewind)(stream);
+ return;
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ CALL_REAL (rewind)(stream);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ iopkt.iotype = OTHERIO_TRACE;
+ iopkt.fd = fileno (stream);
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+}
+
+/*------------------------------------------------------------- ftell */
+long
+ftell (FILE *stream)
+{
+ int *guard;
+ long ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (ftell))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ return CALL_REAL (ftell)(stream);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (ftell)(stream);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret != -1)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ iopkt.fd = fileno (stream);
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- fgetpos */
+// map interposed symbol versions
+#if ARCH(Intel) && WSIZE(32)
+static int
+__collector_fgetpos_symver (int(real_fgetpos) (), FILE *stream, fpos_t *pos);
+
+int
+__collector_fgetpos_2_2 (FILE *stream, fpos_t *pos)
+{
+ if (NULL_PTR (fgetpos))
+ init_io_intf ();
+ TprintfT (DBG_LTT, "iotrace: __collector_fgetpos_2_2@%p\n", CALL_REAL (fgetpos_2_2));
+ return __collector_fgetpos_symver (CALL_REAL (fgetpos_2_2), stream, pos);
+}
+
+int
+__collector_fgetpos_2_0 (FILE *stream, fpos_t *pos)
+{
+ if (NULL_PTR (fgetpos))
+ init_io_intf ();
+ TprintfT (DBG_LTT, "iotrace: __collector_fgetpos_2_0@%p\n", CALL_REAL (fgetpos_2_0));
+ return __collector_fgetpos_symver (CALL_REAL (fgetpos_2_0), stream, pos);
+}
+
+__asm__(".symver __collector_fgetpos_2_2,fgetpos@@GLIBC_2.2");
+__asm__(".symver __collector_fgetpos_2_0,fgetpos@GLIBC_2.0");
+#endif
+
+#if ARCH(Intel) && WSIZE(32)
+
+static int
+__collector_fgetpos_symver (int(real_fgetpos) (), FILE *stream, fpos_t *pos)
+{
+#else
+int
+fgetpos (FILE *stream, fpos_t *pos)
+{
+#endif
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fgetpos))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ {
+#if ARCH(Intel) && WSIZE(32)
+ return (real_fgetpos) (stream, pos);
+#else
+ return CALL_REAL (fgetpos)(stream, pos);
+#endif
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+#if ARCH(Intel) && WSIZE(32)
+ ret = (real_fgetpos) (stream, pos);
+#else
+ ret = CALL_REAL (fgetpos)(stream, pos);
+#endif
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret == 0)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ iopkt.fd = fileno (stream);
+
+#if ARCH(Intel) && WSIZE(32)
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt);
+#else
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+#endif
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+#if WSIZE(32)
+/*------------------------------------------------------------- fgetpos64 */
+#if ARCH(Intel)
+// map interposed symbol versions
+
+static int
+__collector_fgetpos64_symver (int(real_fgetpos64) (), FILE *stream, fpos64_t *pos);
+
+int
+__collector_fgetpos64_2_2 (FILE *stream, fpos64_t *pos)
+{
+ TprintfT (DBG_LTT, "iotrace: __collector_fgetpos64_2_2@%p(stream=%p, pos=%p)\n",
+ CALL_REAL (fgetpos64_2_2), stream, pos);
+ if (NULL_PTR (fgetpos64))
+ init_io_intf ();
+ return __collector_fgetpos64_symver (CALL_REAL (fgetpos64_2_2), stream, pos);
+}
+
+int
+__collector_fgetpos64_2_1 (FILE *stream, fpos64_t *pos)
+{
+ TprintfT (DBG_LTT, "iotrace: __collector_fgetpos64_2_1@%p(stream=%p, pos=%p)\n",
+ CALL_REAL (fgetpos64_2_1), stream, pos);
+ if (NULL_PTR (fgetpos64))
+ init_io_intf ();
+ return __collector_fgetpos64_symver (CALL_REAL (fgetpos64_2_1), stream, pos);
+}
+
+__asm__(".symver __collector_fgetpos64_2_2,fgetpos64@@GLIBC_2.2");
+__asm__(".symver __collector_fgetpos64_2_1,fgetpos64@GLIBC_2.1");
+
+static int
+__collector_fgetpos64_symver (int(real_fgetpos64) (), FILE *stream, fpos64_t *pos)
+{
+#else
+int
+fgetpos64 (FILE *stream, fpos64_t *pos)
+{
+#endif
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fgetpos64))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ {
+#if ARCH(Intel)
+ return (real_fgetpos64) (stream, pos);
+#else
+ return CALL_REAL (fgetpos64)(stream, pos);
+#endif
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+#if ARCH(Intel)
+ ret = (real_fgetpos64) (stream, pos);
+#else
+ ret = CALL_REAL (fgetpos64)(stream, pos);
+#endif
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret == 0)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ iopkt.fd = fileno (stream);
+#if ARCH(Intel)
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt);
+#else
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+#endif
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+#endif
+
+/*------------------------------------------------------------- fsetpos */
+// map interposed symbol versions
+#if ARCH(Intel) && WSIZE(32)
+static int
+__collector_fsetpos_symver (int(real_fsetpos) (), FILE *stream, const fpos_t *pos);
+
+int
+__collector_fsetpos_2_2 (FILE *stream, const fpos_t *pos)
+{
+ if (NULL_PTR (fsetpos))
+ init_io_intf ();
+ TprintfT (DBG_LTT, "iotrace: __collector_fsetpos_2_2@%p\n", CALL_REAL (fsetpos_2_2));
+ return __collector_fsetpos_symver (CALL_REAL (fsetpos_2_2), stream, pos);
+}
+
+int
+__collector_fsetpos_2_0 (FILE *stream, const fpos_t *pos)
+{
+ if (NULL_PTR (fsetpos))
+ init_io_intf ();
+ TprintfT (DBG_LTT, "iotrace: __collector_fsetpos_2_0@%p\n", CALL_REAL (fsetpos_2_0));
+ return __collector_fsetpos_symver (CALL_REAL (fsetpos_2_0), stream, pos);
+}
+
+__asm__(".symver __collector_fsetpos_2_2,fsetpos@@GLIBC_2.2");
+__asm__(".symver __collector_fsetpos_2_0,fsetpos@GLIBC_2.0");
+#endif
+
+#if ARCH(Intel) && WSIZE(32)
+
+static int
+__collector_fsetpos_symver (int(real_fsetpos) (), FILE *stream, const fpos_t *pos)
+{
+#else
+int
+fsetpos (FILE *stream, const fpos_t *pos)
+{
+#endif
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fsetpos))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ {
+#if ARCH(Intel) && WSIZE(32)
+ return (real_fsetpos) (stream, pos);
+#else
+ return CALL_REAL (fsetpos)(stream, pos);
+#endif
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+#if ARCH(Intel) && WSIZE(32)
+ ret = (real_fsetpos) (stream, pos);
+#else
+ ret = CALL_REAL (fsetpos)(stream, pos);
+#endif
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret == 0)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ iopkt.fd = fileno (stream);
+#if ARCH(Intel) && WSIZE(32)
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt);
+#else
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+#endif
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+#if WSIZE(32)
+/*------------------------------------------------------------- fsetpos64 */
+#if ARCH(Intel)
+// map interposed symbol versions
+static int
+__collector_fsetpos64_symver (int(real_fsetpos64) (), FILE *stream, const fpos64_t *pos);
+
+int
+__collector_fsetpos64_2_2 (FILE *stream, const fpos64_t *pos)
+{
+ TprintfT (DBG_LTT, "iotrace: __collector_fsetpos64_2_2@%p(stream=%p, pos=%p)\n",
+ CALL_REAL (fsetpos64_2_2), stream, pos);
+ if (NULL_PTR (fsetpos64))
+ init_io_intf ();
+ return __collector_fsetpos64_symver (CALL_REAL (fsetpos64_2_2), stream, pos);
+}
+
+int
+__collector_fsetpos64_2_1 (FILE *stream, const fpos64_t *pos)
+{
+ TprintfT (DBG_LTT, "iotrace: __collector_fsetpos64_2_1@%p(stream=%p, pos=%p)\n",
+ CALL_REAL (fsetpos64_2_1), stream, pos);
+ if (NULL_PTR (fsetpos64))
+ init_io_intf ();
+ return __collector_fsetpos64_symver (CALL_REAL (fsetpos64_2_1), stream, pos);
+}
+
+__asm__(".symver __collector_fsetpos64_2_2,fsetpos64@@GLIBC_2.2");
+__asm__(".symver __collector_fsetpos64_2_1,fsetpos64@GLIBC_2.1");
+
+static int
+__collector_fsetpos64_symver (int(real_fsetpos64) (), FILE *stream, const fpos64_t *pos)
+{
+#else
+int
+fsetpos64 (FILE *stream, const fpos64_t *pos)
+{
+#endif
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fsetpos64))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard) || stream == NULL)
+ {
+#if ARCH(Intel) && WSIZE(32)
+ return (real_fsetpos64) (stream, pos);
+#else
+ return CALL_REAL (fsetpos64)(stream, pos);
+#endif
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+#if ARCH(Intel) && WSIZE(32)
+ ret = (real_fsetpos64) (stream, pos);
+#else
+ ret = CALL_REAL (fsetpos64)(stream, pos);
+#endif
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret == 0)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ iopkt.fd = fileno (stream);
+#if ARCH(Intel)
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK_ARG, &iopkt);
+#else
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+#endif
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+#endif
+
+/*------------------------------------------------------------- fsync */
+int
+fsync (int fildes)
+{
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (fsync))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (fsync)(fildes);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (fsync)(fildes);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret == 0)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- readdir */
+struct dirent*
+readdir (DIR *dirp)
+{
+ int *guard;
+ struct dirent *ptr;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (readdir))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (readdir)(dirp);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ptr = CALL_REAL (readdir)(dirp);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ptr;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof ( IOTrace_packet));
+ iopkt.comm.tsize = sizeof ( IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ptr != NULL)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ptr;
+}
+
+/*------------------------------------------------------------- flock */
+int
+flock (int fd, int operation)
+{
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (flock))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (flock)(fd, operation);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (flock)(fd, operation);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret == 0)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ iopkt.fd = fd;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- lockf */
+int
+lockf (int fildes, int function, off_t size)
+{
+ int *guard;
+ int ret;
+ IOTrace_packet iopkt;
+ if (NULL_PTR (lockf))
+ init_io_intf ();
+ if (CHCK_REENTRANCE (guard))
+ return CALL_REAL (lockf)(fildes, function, size);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ ret = CALL_REAL (lockf)(fildes, function, size);
+ if (RECHCK_REENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ collector_memset (&iopkt, 0, sizeof (IOTrace_packet));
+ iopkt.comm.tsize = sizeof (IOTrace_packet);
+ iopkt.comm.tstamp = grnt;
+ iopkt.requested = reqt;
+ if (ret == 0)
+ iopkt.iotype = OTHERIO_TRACE;
+ else
+ iopkt.iotype = OTHERIO_TRACE_ERROR;
+ iopkt.fd = fildes;
+ iopkt.comm.frinfo = collector_interface->getFrameInfo (io_hndl, iopkt.comm.tstamp, FRINFO_FROM_STACK, &iopkt);
+ collector_interface->writeDataRecord (io_hndl, (Common_packet*) & iopkt);
+ POP_REENTRANCE (guard);
+ return ret;
+}
diff --git a/gprofng/libcollector/jprofile.c b/gprofng/libcollector/jprofile.c
new file mode 100644
index 0000000..9daaa5a
--- /dev/null
+++ b/gprofng/libcollector/jprofile.c
@@ -0,0 +1,1315 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "config.h"
+
+#if defined(GPROFNG_JAVA_PROFILING)
+#include <alloca.h>
+#include <dlfcn.h> /* dlsym() */
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/param.h> /* MAXPATHLEN */
+
+#include <jni.h>
+#include <jvmti.h>
+
+#include "gp-defs.h"
+#include "collector.h"
+#include "gp-experiment.h"
+#include "tsd.h"
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+
+/* ARCH_STRLEN is defined in dbe, copied here */
+#define ARCH_STRLEN(s) ((CALL_UTIL(strlen)(s) + 4 ) & ~0x3)
+
+/* call frame */
+typedef struct
+{
+ jint lineno; /* line number in the source file */
+ jmethodID method_id; /* method executed in this frame */
+} JVMPI_CallFrame;
+
+/* call trace */
+typedef struct
+{
+ JNIEnv *env_id; /* Env where trace was recorded */
+ jint num_frames; /* number of frames in this trace */
+ JVMPI_CallFrame *frames; /* frames */
+} JVMPI_CallTrace;
+
+extern void __collector_jprofile_enable_synctrace (void);
+int __collector_jprofile_start_attach (void);
+static int init_interface (CollectorInterface*);
+static int open_experiment (const char *);
+static int close_experiment (void);
+static int detach_experiment (void);
+static void jprof_find_asyncgetcalltrace (void);
+static char *apistr = NULL;
+
+static ModuleInterface module_interface = {
+ "*"SP_JCLASSES_FILE, /* description, exempt from limit */
+ init_interface, /* initInterface */
+ open_experiment, /* openExperiment */
+ NULL, /* startDataCollection */
+ NULL, /* stopDataCollection */
+ close_experiment, /* closeExperiment */
+ detach_experiment /* detachExperiment (fork child) */
+};
+
+static CollectorInterface *collector_interface = NULL;
+static CollectorModule jprof_hndl = COLLECTOR_MODULE_ERR;
+static int __collector_java_attach = 0;
+static JavaVM *jvm;
+static jmethodID getResource = NULL;
+static jmethodID toExternalForm = NULL;
+
+/* Java profiling thread specific data */
+typedef struct TSD_Entry
+{
+ JNIEnv *env;
+ hrtime_t tstamp;
+} TSD_Entry;
+
+static unsigned tsd_key = COLLECTOR_TSD_INVALID_KEY;
+static collector_mutex_t jclasses_lock = COLLECTOR_MUTEX_INITIALIZER;
+static int java_gc_on = 0;
+static int java_mem_mode = 0;
+static int java_sync_mode = 0;
+static int is_hotspot_vm = 0;
+static void get_jvm_settings ();
+static void rwrite (int fd, const void *buf, size_t nbyte);
+static void addToDynamicArchive (const char* name, const unsigned char* class_data, int class_data_len);
+static void (*AsyncGetCallTrace)(JVMPI_CallTrace*, jint, ucontext_t*) = NULL;
+static void (*collector_heap_record)(int, int, void*) = NULL;
+static void (*collector_jsync_begin)() = NULL;
+static void (*collector_jsync_end)(hrtime_t, void *) = NULL;
+
+#define gethrtime collector_interface->getHiResTime
+
+/*
+ * JVMTI declarations
+ */
+
+static jvmtiEnv *jvmti;
+static void jvmti_VMInit (jvmtiEnv*, JNIEnv*, jthread);
+static void jvmti_VMDeath (jvmtiEnv*, JNIEnv*);
+static void jvmti_ThreadStart (jvmtiEnv*, JNIEnv*, jthread);
+static void jvmti_ThreadEnd (jvmtiEnv*, JNIEnv*, jthread);
+static void jvmti_CompiledMethodLoad (jvmtiEnv*, jmethodID, jint, const void*,
+ jint, const jvmtiAddrLocationMap*, const void*);
+static void jvmti_CompiledMethodUnload (jvmtiEnv*, jmethodID, const void*);
+static void jvmti_DynamicCodeGenerated (jvmtiEnv*, const char*, const void*, jint);
+static void jvmti_ClassPrepare (jvmtiEnv*, JNIEnv*, jthread, jclass);
+static void jvmti_ClassLoad (jvmtiEnv*, JNIEnv*, jthread, jclass);
+//static void jvmti_ClassUnload( jvmtiEnv*, JNIEnv*, jthread, jclass );
+static void jvmti_MonitorEnter (jvmtiEnv *, JNIEnv*, jthread, jobject);
+static void jvmti_MonitorEntered (jvmtiEnv *, JNIEnv*, jthread, jobject);
+#if 0
+static void jvmti_MonitorWait (jvmtiEnv *, JNIEnv*, jthread, jobject, jlong);
+static void jvmti_MonitorWaited (jvmtiEnv *, JNIEnv*, jthread, jobject, jboolean);
+#endif
+static void jvmti_ClassFileLoadHook (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jclass class_being_redefined,
+ jobject loader, const char* name, jobject protection_domain,
+ jint class_data_len, const unsigned char* class_data,
+ jint* new_class_data_len, unsigned char** new_class_data);
+static void jvmti_GarbageCollectionStart (jvmtiEnv *);
+static void
+jvmti_GarbageCollectionFinish (jvmtiEnv *);
+jvmtiEventCallbacks callbacks = {
+ jvmti_VMInit, // 50 jvmtiEventVMInit;
+ jvmti_VMDeath, // 51 jvmtiEventVMDeath;
+ jvmti_ThreadStart, // 52 jvmtiEventThreadStart;
+ jvmti_ThreadEnd, // 53 jvmtiEventThreadEnd;
+ jvmti_ClassFileLoadHook, // 54 jvmtiEventClassFileLoadHook;
+ jvmti_ClassLoad, // 55 jvmtiEventClassLoad;
+ jvmti_ClassPrepare, // 56 jvmtiEventClassPrepare;
+ NULL, // 57 reserved57;
+ NULL, // 58 jvmtiEventException;
+ NULL, // 59 jvmtiEventExceptionCatch;
+ NULL, // 60 jvmtiEventSingleStep;
+ NULL, // 61 jvmtiEventFramePop;
+ NULL, // 62 jvmtiEventBreakpoint;
+ NULL, // 63 jvmtiEventFieldAccess;
+ NULL, // 64 jvmtiEventFieldModification;
+ NULL, // 65 jvmtiEventMethodEntry;
+ NULL, // 66 jvmtiEventMethodExit;
+ NULL, // 67 jvmtiEventNativeMethodBind;
+ jvmti_CompiledMethodLoad, // 68 jvmtiEventCompiledMethodLoad;
+ jvmti_CompiledMethodUnload, // 69 jvmtiEventCompiledMethodUnload;
+ jvmti_DynamicCodeGenerated, // 70 jvmtiEventDynamicCodeGenerated;
+ NULL, // 71 jvmtiEventDataDumpRequest;
+ NULL, // 72 jvmtiEventDataResetRequest;
+ NULL, /*jvmti_MonitorWait,*/ // 73 jvmtiEventMonitorWait;
+ NULL, /*jvmti_MonitorWaited,*/ // 74 jvmtiEventMonitorWaited;
+ jvmti_MonitorEnter, // 75 jvmtiEventMonitorContendedEnter;
+ jvmti_MonitorEntered, // 76 jvmtiEventMonitorContendedEntered;
+ NULL, // 77 jvmtiEventMonitorContendedExit;
+ NULL, // 78 jvmtiEventReserved;
+ NULL, // 79 jvmtiEventReserved;
+ NULL, // 80 jvmtiEventReserved;
+ jvmti_GarbageCollectionStart, // 81 jvmtiEventGarbageCollectionStart;
+ jvmti_GarbageCollectionFinish, // 82 jvmtiEventGarbageCollectionFinish;
+ NULL, // 83 jvmtiEventObjectFree;
+ NULL // 84 jvmtiEventVMObjectAlloc;
+};
+
+typedef jint (JNICALL JNI_GetCreatedJavaVMs_t)(JavaVM **, jsize, jsize *);
+
+int
+init_interface (CollectorInterface *_collector_interface)
+{
+ collector_interface = _collector_interface;
+ return COL_ERROR_NONE;
+}
+
+static int
+open_experiment (const char *exp)
+{
+ if (collector_interface == NULL)
+ return COL_ERROR_JAVAINIT;
+ TprintfT (0, "jprofile: open_experiment %s\n", exp);
+ const char *params = collector_interface->getParams ();
+ const char *args = params;
+ while (args)
+ {
+ if (__collector_strStartWith (args, "j:") == 0)
+ {
+ args += 2;
+ break;
+ }
+ args = CALL_UTIL (strchr)(args, ';');
+ if (args)
+ args++;
+ }
+ if (args == NULL) /* Java profiling not specified */
+ return COL_ERROR_JAVAINIT;
+ tsd_key = collector_interface->createKey (sizeof ( TSD_Entry), NULL, NULL);
+ if (tsd_key == (unsigned) - 1)
+ {
+ TprintfT (0, "jprofile: TSD key create failed.\n");
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_JAVAINIT);
+ return COL_ERROR_JAVAINIT;
+ }
+ else
+ Tprintf (DBG_LT2, "jprofile: TSD key create succeeded %d.\n", tsd_key);
+
+ args = params;
+ while (args)
+ {
+ if (__collector_strStartWith (args, "H:") == 0)
+ {
+ java_mem_mode = 1;
+ collector_heap_record = (void(*)(int, int, void*))dlsym (RTLD_DEFAULT, "__collector_heap_record");
+ }
+#if 0
+ else if (__collector_strStartWith (args, "s:") == 0)
+ {
+ java_sync_mode = 1;
+ collector_jsync_begin = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_begin");
+ collector_jsync_end = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_end");
+ }
+#endif
+ args = CALL_UTIL (strchr)(args, ';');
+ if (args)
+ args++;
+ }
+
+ /* synchronization tracing is enabled by the synctrace module, later in initialization */
+ __collector_java_mode = 1;
+ java_gc_on = 1;
+ return COL_ERROR_NONE;
+}
+
+/* routine called from the syntrace module to enable Java-API synctrace */
+void
+__collector_jprofile_enable_synctrace ()
+{
+ if (__collector_java_mode == 0)
+ {
+ TprintfT (DBG_LT1, "jprofile: not turning on Java synctrace; Java mode not enabled\n");
+ return;
+ }
+ java_sync_mode = 1;
+ collector_jsync_begin = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_begin");
+ collector_jsync_end = (void(*)(hrtime_t, void *))dlsym (RTLD_DEFAULT, "__collector_jsync_end");
+ TprintfT (DBG_LT1, "jprofile: turning on Java synctrace, and requesting events\n");
+}
+
+int
+__collector_jprofile_start_attach (void)
+{
+ if (!__collector_java_mode || __collector_java_asyncgetcalltrace_loaded)
+ return 0;
+ void *g_sHandle = RTLD_DEFAULT;
+ /* Now get the function addresses */
+ JNI_GetCreatedJavaVMs_t *pfnGetCreatedJavaVMs;
+ pfnGetCreatedJavaVMs = (JNI_GetCreatedJavaVMs_t *) dlsym (g_sHandle, "JNI_GetCreatedJavaVMs");
+ if (pfnGetCreatedJavaVMs != NULL)
+ {
+ TprintfT (0, "jprofile attach: pfnGetCreatedJavaVMs is detected.\n");
+ JavaVM * vmBuf[1]; // XXXX only detect on jvm
+ jsize nVMs = 0;
+ (*pfnGetCreatedJavaVMs)(vmBuf, 1, &nVMs);
+ if (vmBuf[0] != NULL && nVMs > 0)
+ {
+ jvm = vmBuf[0];
+ JNIEnv* jni_env = NULL;
+ (*jvm)->AttachCurrentThread (jvm, (void **) &jni_env, NULL);
+ Agent_OnLoad (jvm, NULL, NULL);
+ if ((*jvm)->GetEnv (jvm, (void **) &jni_env, JNI_VERSION_1_2) >= 0 && jni_env && jvmti)
+ {
+ jthread thread;
+ (*jvmti)->GetCurrentThread (jvmti, &thread);
+#ifdef DEBUG
+ collector_thread_t tid;
+ tid = __collector_thr_self ();
+ TprintfT (0, "jprofile attach: AttachCurrentThread: thread: %lu jni_env=%p jthread=%p\n",
+ (unsigned long) tid, jni_env, thread);
+#endif /* DEBUG */
+ jvmti_VMInit (jvmti, jni_env, thread);
+ (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD);
+ (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_DYNAMIC_CODE_GENERATED);
+ __collector_java_attach = 1;
+ (*jvm)->DetachCurrentThread (jvm);
+ }
+ }
+ }
+ return 0;
+}
+
+static int
+close_experiment (void)
+{
+ /* fixme XXXXX add content here */
+ /* see detach_experiment() */
+ __collector_java_mode = 0;
+ __collector_java_asyncgetcalltrace_loaded = 0;
+ __collector_java_attach = 0;
+ java_gc_on = 0;
+ java_mem_mode = 0;
+ java_sync_mode = 0;
+ is_hotspot_vm = 0;
+ __collector_mutex_init (&jclasses_lock);
+ tsd_key = COLLECTOR_TSD_INVALID_KEY;
+ TprintfT (0, "jprofile: experiment closed.\n");
+ return 0;
+}
+
+static int
+detach_experiment (void)
+/* fork child. Clean up state but don't write to experiment */
+{
+ __collector_java_mode = 0;
+ java_gc_on = 0;
+ jvm = NULL;
+ java_mem_mode = 0;
+ java_sync_mode = 0;
+ is_hotspot_vm = 0;
+ jvmti = NULL;
+ apistr = NULL;
+ __collector_mutex_init (&jclasses_lock);
+ tsd_key = COLLECTOR_TSD_INVALID_KEY;
+ TprintfT (0, "jprofile: detached from experiment.\n");
+ return 0;
+}
+
+JNIEXPORT jint JNICALL
+JVM_OnLoad (JavaVM *vm, char *options, void *reserved)
+{
+ jvmtiError err;
+ int use_jvmti = 0;
+ if (!__collector_java_mode)
+ {
+ TprintfT (DBG_LT1, "jprofile: JVM_OnLoad invoked with java mode disabled\n");
+ return JNI_OK;
+ }
+ else
+ TprintfT (DBG_LT1, "jprofile: JVM_OnLoad invoked\n");
+ jvm = vm;
+ jvmti = NULL;
+ if ((*jvm)->GetEnv (jvm, (void **) &jvmti, JVMTI_VERSION_1_0) >= 0 && jvmti)
+ {
+ TprintfT (DBG_LT1, "jprofile: JVMTI found\n");
+ use_jvmti = 1;
+ }
+ if (!use_jvmti)
+ {
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
+ SP_JCMD_CERROR, COL_ERROR_JVMNOTSUPP);
+ return JNI_ERR;
+ }
+ else
+ {
+ Tprintf (DBG_LT0, "\tjprofile: Initializing for JVMTI\n");
+ apistr = "JVMTI 1.0";
+
+ // setup JVMTI
+ jvmtiCapabilities cpblts;
+ err = (*jvmti)->GetPotentialCapabilities (jvmti, &cpblts);
+ if (err == JVMTI_ERROR_NONE)
+ {
+ jvmtiCapabilities cpblts_set;
+ CALL_UTIL (memset)(&cpblts_set, 0, sizeof (cpblts_set));
+
+ /* Add only those capabilities that are among potential ones */
+ cpblts_set.can_get_source_file_name = cpblts.can_get_source_file_name;
+ Tprintf (DBG_LT1, "\tjprofile: adding can_get_source_file_name capability: %u\n", cpblts.can_get_source_file_name);
+
+ cpblts_set.can_generate_compiled_method_load_events = cpblts.can_generate_compiled_method_load_events;
+ Tprintf (DBG_LT1, "\tjprofile: adding can_generate_compiled_method_load_events capability: %u\n", cpblts.can_generate_compiled_method_load_events);
+
+ if (java_sync_mode)
+ {
+ cpblts_set.can_generate_monitor_events = cpblts.can_generate_monitor_events;
+ Tprintf (DBG_LT1, "\tjprofile: adding can_generate_monitor_events capability: %u\n", cpblts.can_generate_monitor_events);
+ }
+ if (java_gc_on)
+ {
+ cpblts_set.can_generate_garbage_collection_events = cpblts.can_generate_garbage_collection_events;
+ Tprintf (DBG_LT1, "\tjprofile: adding can_generate_garbage_collection_events capability: %u\n", cpblts.can_generate_garbage_collection_events);
+ }
+ err = (*jvmti)->AddCapabilities (jvmti, &cpblts_set);
+ Tprintf (DBG_LT1, "\tjprofile: AddCapabilities() returns: %d\n", err);
+ }
+ err = (*jvmti)->SetEventCallbacks (jvmti, &callbacks, sizeof ( callbacks));
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_DEATH, NULL);
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL);
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL);
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_LOAD, NULL);
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_COMPILED_METHOD_UNLOAD, NULL);
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_DYNAMIC_CODE_GENERATED, NULL);
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_START, NULL);
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_THREAD_END, NULL);
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
+ if (java_gc_on)
+ {
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_START, NULL);
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL);
+ }
+ if (java_mem_mode)
+ {
+ // err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, <no event for heap tracing> , NULL );
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
+ SP_JCMD_CWARN, COL_WARN_NO_JAVA_HEAP);
+ java_mem_mode = 0;
+ }
+ if (java_sync_mode)
+ {
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, NULL);
+ err = (*jvmti)->SetEventNotificationMode (jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTERED, NULL);
+ //err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAIT, NULL );
+ //err = (*jvmti)->SetEventNotificationMode( jvmti, JVMTI_ENABLE, JVMTI_EVENT_MONITOR_WAITED, NULL );
+ }
+ Tprintf (DBG_LT0, "\tjprofile: JVMTI initialized\n");
+ }
+
+ /* JVM still uses collector API on Solaris to notify us about dynamically generated code.
+ * If we ask it to generate events we'll end up with duplicate entries in the
+ * map file.
+ */
+ if (use_jvmti)
+ {
+ err = (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_DYNAMIC_CODE_GENERATED);
+ err = (*jvmti)->GenerateEvents (jvmti, JVMTI_EVENT_COMPILED_METHOD_LOAD);
+ }
+ Tprintf (DBG_LT1, "\tjprofile: JVM_OnLoad ok\n");
+ return JNI_OK;
+}
+
+/* This is currently just a placeholder */
+JNIEXPORT jint JNICALL
+Agent_OnLoad (JavaVM *vm, char *options, void *reserved)
+{
+ return JVM_OnLoad (vm, options, reserved);
+}
+
+static void
+rwrite (int fd, const void *buf, size_t nbyte)
+{
+ size_t left = nbyte;
+ size_t res;
+ char *ptr = (char*) buf;
+ while (left > 0)
+ {
+ res = CALL_UTIL (write)(fd, ptr, left);
+ if (res == -1)
+ {
+ /* XXX: we can't write this record, we probably
+ * can't write anything else. Ignore.
+ */
+ return;
+ }
+ left -= res;
+ ptr += res;
+ }
+}
+
+void
+get_jvm_settings ()
+{
+ jint res;
+ JNIEnv *jni;
+ jclass jcls;
+ jmethodID jmid;
+ jstring jstrin;
+ jstring jstrout;
+ const char *str;
+ res = (*jvm)->GetEnv (jvm, (void **) &jni, JNI_VERSION_1_2);
+ if (res < 0)
+ return;
+
+ /* I'm not checking if results are valid as JVM is extremely
+ * sensitive to exceptions that might occur during these JNI calls
+ * and will die with a fatal error later anyway.
+ */
+ jcls = (*jni)->FindClass (jni, "java/lang/System");
+ jmid = (*jni)->GetStaticMethodID (jni, jcls, "getProperty", "(Ljava/lang/String;)Ljava/lang/String;");
+ jstrin = (*jni)->NewStringUTF (jni, "java.class.path");
+ jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
+ str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
+ if (str)
+ {
+ collector_interface->writeLog ("<setting %s=\"%s\"/>\n", SP_JCMD_SRCHPATH, str);
+ (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
+ }
+ jstrin = (*jni)->NewStringUTF (jni, "sun.boot.class.path");
+ jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
+ str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
+ if (str)
+ {
+ collector_interface->writeLog ("<setting %s=\"%s\"/>\n", SP_JCMD_SRCHPATH, str);
+ (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
+ }
+ jstrin = (*jni)->NewStringUTF (jni, "java.home");
+ jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
+ str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
+ if (str)
+ {
+ collector_interface->writeLog ("<setting %s=\"%s/../src.zip\"/>\n", SP_JCMD_SRCHPATH, str);
+ (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
+ }
+ jstrin = (*jni)->NewStringUTF (jni, "java.vm.version");
+ jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
+ str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
+ if (str)
+ {
+ (void) collector_interface->writeLog ("<profile name=\"jprofile\" %s=\"%s\" %s=\"%s\"/>\n",
+ SP_JCMD_JVERSION, str, "api", apistr != NULL ? apistr : "N/A");
+ if (__collector_strStartWith (str, "1.4.2_02") < 0)
+ {
+ (void) collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\"/>\n",
+ SP_JCMD_CWARN, COL_WARN_OLDJAVA);
+ }
+ (*jni)->ReleaseStringUTFChars (jni, jstrout, str);
+ }
+ is_hotspot_vm = 0;
+ jstrin = (*jni)->NewStringUTF (jni, "sun.management.compiler");
+ jstrout = (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin);
+ str = jstrout ? (*jni)->GetStringUTFChars (jni, jstrout, NULL) : NULL;
+ if (str && __collector_strncmp (str, "HotSpot", 7) == 0)
+ is_hotspot_vm = 1;
+
+ /* Emulate System.setProperty( "collector.init", "true") */
+ jmid = (*jni)->GetStaticMethodID (jni, jcls, "setProperty",
+ "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
+ jstrin = (*jni)->NewStringUTF (jni, "collector.init");
+ jstrout = (*jni)->NewStringUTF (jni, "true");
+ (*jni)->CallStaticObjectMethod (jni, jcls, jmid, jstrin, jstrout);
+}
+
+/*
+ * JVMTI code
+ */
+
+static void
+jvmti_VMInit (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread)
+{
+ jint class_count = 0;
+ jclass *classes = NULL;
+ int i;
+ TprintfT (DBG_LT1, "jprofile: jvmti_VMInit called\n");
+ get_jvm_settings ();
+
+ /* determine loaded classes */
+ (*jvmti_env)->GetLoadedClasses (jvmti_env, &class_count, &classes);
+ TprintfT (DBG_LT1, "jprofile: jvmti_VMInit initializing %d classes\n", class_count);
+ for (i = 0; i < class_count; i++)
+ {
+ // PushLocalFrame
+ jvmti_ClassPrepare (jvmti_env, jni_env, NULL, classes[i]);
+ // PopLocalFrame
+ // DeleteLocalRef( classes[i] );
+ }
+ (*jvmti_env)->Deallocate (jvmti_env, (unsigned char*) classes);
+ getResource = (*jni_env)->GetMethodID (jni_env, (*jni_env)->FindClass (jni_env, "java/lang/ClassLoader"), "getResource", "(Ljava/lang/String;)Ljava/net/URL;");
+ toExternalForm = (*jni_env)->GetMethodID (jni_env, (*jni_env)->FindClass (jni_env, "java/net/URL"), "toExternalForm", "()Ljava/lang/String;");
+
+ /* find the stack unwind routine */
+ jprof_find_asyncgetcalltrace ();
+}
+
+static void
+jvmti_VMDeath (jvmtiEnv *jvmti_env, JNIEnv* jni_env)
+{
+ __collector_java_mode = 0;
+ TprintfT (DBG_LT1, "jprofile: jvmti_VMDeath event received\n");
+}
+
+static void
+jvmti_ThreadStart (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread)
+{
+ jvmtiError err;
+ jvmtiThreadInfo t_info;
+ char *thread_name, *group_name, *parent_name;
+ hrtime_t hrt;
+ collector_thread_t tid;
+ thread_name = group_name = parent_name = NULL;
+ hrt = gethrtime ();
+ tid = __collector_thr_self ();
+ TprintfT (DBG_LT1, "jprofile: jvmti_ThreadStart: thread: %lu jni_env=%p jthread=%p\n",
+ (unsigned long) tid, jni_env, thread);
+ err = (*jvmti_env)->GetThreadInfo (jvmti_env, thread, &t_info);
+ if (err == JVMTI_ERROR_NONE)
+ {
+ jvmtiThreadGroupInfo g_info;
+ thread_name = t_info.name;
+ if (t_info.thread_group)
+ {
+ err = (*jvmti_env)->GetThreadGroupInfo (jvmti_env, t_info.thread_group, &g_info);
+ if (err == JVMTI_ERROR_NONE)
+ {
+ group_name = g_info.name;
+ if (g_info.parent)
+ {
+ jvmtiThreadGroupInfo p_info;
+ err = (*jvmti_env)->GetThreadGroupInfo (jvmti_env, g_info.parent, &p_info);
+ if (err == JVMTI_ERROR_NONE)
+ {
+ parent_name = p_info.name;
+ // DeleteLocalRef( p_info.parent );
+ }
+ // DeleteLocalRef( g_info.parent );
+ }
+ }
+ }
+ // DeleteLocalRef( t_info.thread_group );
+ // DeleteLocalRef( t_info.context_class_loader );
+ }
+ if (thread_name == NULL)
+ thread_name = "";
+ if (group_name == NULL)
+ group_name = "";
+ if (parent_name == NULL)
+ parent_name = "";
+ collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\" name=\"%s\" grpname=\"%s\" prntname=\"%s\" tid=\"%lu\" jthr=\"0x%lx\" jenv=\"0x%lx\"/>\n",
+ SP_JCMD_JTHRSTART,
+ (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
+ thread_name,
+ group_name,
+ parent_name,
+ (unsigned long) tid,
+ thread,
+ jni_env
+ );
+ TSD_Entry *tsd = collector_interface->getKey (tsd_key);
+ if (tsd)
+ tsd->env = jni_env;
+}
+
+static void
+jvmti_ThreadEnd (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread)
+{
+ hrtime_t hrt = gethrtime ();
+ collector_thread_t tid = __collector_thr_self ();
+ TprintfT (DBG_LT1, "jprofile: jvmti_ThreadEnd: thread: %lu jni_env=%p jthread=%p\n",
+ (unsigned long) tid, jni_env, thread);
+
+ collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\" tid=\"%lu\" jthr=\"0x%lx\" jenv=\"0x%lx\"/>\n",
+ SP_JCMD_JTHREND,
+ (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
+ (unsigned long) tid,
+ thread,
+ jni_env
+ );
+ TSD_Entry *tsd = collector_interface->getKey (tsd_key);
+ if (tsd)
+ tsd->env = NULL;
+}
+
+/* The following definitions are borrowed from file jvmticmlr.h, part of jdk7 */
+typedef enum
+{
+ JVMTI_CMLR_DUMMY = 1,
+ JVMTI_CMLR_INLINE_INFO = 2
+} jvmtiCMLRKind;
+
+/*
+ * Record that represents arbitrary information passed through JVMTI
+ * CompiledMethodLoadEvent void pointer.
+ */
+typedef struct _jvmtiCompiledMethodLoadRecordHeader
+{
+ jvmtiCMLRKind kind; /* id for the kind of info passed in the record */
+ jint majorinfoversion; /* major and minor info version values. Init'ed */
+ jint minorinfoversion; /* to current version value in jvmtiExport.cpp. */
+ struct _jvmtiCompiledMethodLoadRecordHeader* next;
+} jvmtiCompiledMethodLoadRecordHeader;
+
+/*
+ * Record that gives information about the methods on the compile-time
+ * stack at a specific pc address of a compiled method. Each element in
+ * the methods array maps to same element in the bcis array.
+ */
+typedef struct _PCStackInfo
+{
+ void* pc; /* the pc address for this compiled method */
+ jint numstackframes; /* number of methods on the stack */
+ jmethodID* methods; /* array of numstackframes method ids */
+ jint* bcis; /* array of numstackframes bytecode indices */
+} PCStackInfo;
+
+/*
+ * Record that contains inlining information for each pc address of
+ * an nmethod.
+ */
+typedef struct _jvmtiCompiledMethodLoadInlineRecord
+{
+ jvmtiCompiledMethodLoadRecordHeader header; /* common header for casting */
+ jint numpcs; /* number of pc descriptors in this nmethod */
+ PCStackInfo* pcinfo; /* array of numpcs pc descriptors */
+} jvmtiCompiledMethodLoadInlineRecord;
+
+static void
+jvmti_CompiledMethodLoad (jvmtiEnv *jvmti_env, jmethodID method,
+ jint code_size, const void *code_addr, jint map_length,
+ const jvmtiAddrLocationMap *map,
+ const void *compile_info)
+{
+ TprintfT (DBG_LT2, "jprofile: jvmti_CompiledMethodLoad: mid=0x%lx addr=%p sz=0x%lu map=%p info=%p\n",
+ (unsigned long) method, code_addr, (long) code_size, map, compile_info);
+ char name[32];
+ CALL_UTIL (snprintf)(name, sizeof (name), "0x%lx", (unsigned long) method);
+
+ /* Parse compile_info to get pc -> bci mapping.
+ * Don't interpret compile_info from JVMs other than HotSpot.
+ */
+ int lntsize = 0;
+ DT_lineno *lntable = NULL;
+ if (compile_info != NULL && is_hotspot_vm)
+ {
+ Tprintf (DBG_LT2, "Mapping from compile_info:\n");
+ jvmtiCompiledMethodLoadRecordHeader *currec =
+ (jvmtiCompiledMethodLoadRecordHeader*) compile_info;
+ while (currec != NULL)
+ {
+ if (currec->kind == JVMTI_CMLR_INLINE_INFO)
+ {
+ jvmtiCompiledMethodLoadInlineRecord *inrec =
+ (jvmtiCompiledMethodLoadInlineRecord*) currec;
+ if (inrec->numpcs <= 0)
+ break;
+ lntsize = inrec->numpcs;
+ lntable = (DT_lineno*) alloca (lntsize * sizeof (DT_lineno));
+ PCStackInfo *pcrec = inrec->pcinfo;
+ DT_lineno *lnorec = lntable;
+ for (int i = 0; i < lntsize; ++i)
+ {
+ for (int j = pcrec->numstackframes - 1; j >= 0; --j)
+ if (pcrec->methods[j] == method)
+ {
+ lnorec->offset = (char*) pcrec->pc - (char*) code_addr;
+ lnorec->lineno = pcrec->bcis[j];
+ Tprintf (DBG_LT2, " pc: 0x%lx bci: 0x%lx\n",
+ (long) lnorec->offset, (long) lnorec->lineno);
+ ++lnorec;
+ break;
+ }
+ ++pcrec;
+ }
+ break;
+ }
+ currec = currec->next;
+ }
+ }
+ else if (map != NULL)
+ {
+ Tprintf (DBG_LT2, "Mapping from jvmtiAddrLocationMap:\n");
+ lntsize = map_length;
+ lntable = (DT_lineno*) alloca (lntsize * sizeof (DT_lineno));
+ DT_lineno *lnorec = lntable;
+ for (int i = 0; i < map_length; ++i)
+ {
+ lnorec->offset = (char*) map[i].start_address - (char*) code_addr;
+ lnorec->lineno = (unsigned int) map[i].location;
+ Tprintf (DBG_LT2, " pc: 0x%lx bci: 0x%lx\n",
+ (long) lnorec->offset, (long) lnorec->lineno);
+ ++lnorec;
+ }
+ }
+ __collector_int_func_load (DFUNC_JAVA, name, NULL, (void*) code_addr,
+ code_size, lntsize, lntable);
+}
+
+static void
+jvmti_CompiledMethodUnload (jvmtiEnv *jvmti_env, jmethodID method, const void* code_addr)
+{
+ __collector_int_func_unload (DFUNC_API, (void*) code_addr);
+}
+
+static void
+jvmti_DynamicCodeGenerated (jvmtiEnv *jvmti_env, const char*name, const void *code_addr, jint code_size)
+{
+ __collector_int_func_load (DFUNC_API, (char*) name, NULL, (void*) code_addr,
+ code_size, 0, NULL);
+}
+
+static void
+addToDynamicArchive (const char* name, const unsigned char* class_data, int class_data_len)
+{
+ char path[MAXPATHLEN + 1];
+ mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ mode_t dmode = fmode | S_IXUSR | S_IXGRP | S_IXOTH;
+ if (name == NULL)
+ name = "";
+ const char *expdir = collector_interface->getExpDir ();
+ if (CALL_UTIL (strlen)(expdir) +
+ CALL_UTIL (strlen)(SP_DYNAMIC_CLASSES) +
+ CALL_UTIL (strlen)(name) + 8 > sizeof (path))
+ return;
+ CALL_UTIL (snprintf)(path, sizeof (path), "%s/%s/%s.class", expdir, SP_DYNAMIC_CLASSES, name);
+
+ /* Create all path components step by step starting with SP_DYNAMIC_CLASSES */
+ char *str = path + CALL_UTIL (strlen)(expdir) + 1 + CALL_UTIL (strlen)(SP_DYNAMIC_CLASSES);
+ while (str)
+ {
+ *str = '\0';
+ if (CALL_UTIL (mkdir)(path, dmode) != 0)
+ {
+ /* Checking for EEXIST is not enough, access() is more reliable */
+ if (CALL_UTIL (access)(path, F_OK) != 0)
+ {
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_MKDIR, errno, path);
+ return;
+ }
+ }
+ *str++ = '/';
+ str = CALL_UTIL (strchr)(str, '/');
+ }
+
+ int fd = CALL_UTIL (open)(path, O_WRONLY | O_CREAT | O_TRUNC, fmode);
+ if (fd < 0)
+ {
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_OVWOPEN, errno, path);
+ return;
+ }
+ rwrite (fd, class_data, class_data_len);
+ CALL_UTIL (close)(fd);
+}
+
+static void
+jvmti_ClassFileLoadHook (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jclass class_being_redefined,
+ jobject loader, const char* name, jobject protection_domain, jint class_data_len,
+ const unsigned char* class_data, jint* new_class_data_len, unsigned char** new_class_data)
+{
+ jclass loaderlass;
+ int err;
+ jvmtiPhase phase_ptr;
+ char *cname = NULL;
+ (*jvmti_env)->GetPhase (jvmti_env, &phase_ptr);
+
+ /* skip non live phases */
+ if (phase_ptr != JVMTI_PHASE_LIVE)
+ return;
+
+ /* skip system class loaders */
+ if (!loader)
+ return;
+ loaderlass = (*jni_env)->GetObjectClass (jni_env, loader);
+ err = (*jvmti_env)->GetClassSignature (jvmti_env, loaderlass, &cname, NULL);
+ if (err != JVMTI_ERROR_NONE || !cname || *cname == (char) 0)
+ return;
+
+ /* skip classes loaded with AppClassLoader (java.class.path) */
+ if (__collector_strcmp (cname, "Lsun/misc/Launcher$AppClassLoader;") == 0)
+ return;
+ addToDynamicArchive (name, class_data, (int) class_data_len);
+}
+
+#define NO_CLASS_NAME "<noname>"
+#define NO_SOURCE_FILE "<Unknown>"
+
+static void
+record_jclass (uint64_t class_id, hrtime_t hrt, const char *cname, const char *sname)
+{
+ size_t clen = ARCH_STRLEN (cname);
+ size_t slen = ARCH_STRLEN (sname);
+ size_t sz = sizeof (ARCH_jclass) + clen + slen;
+ ARCH_jclass *jcls = (ARCH_jclass*) alloca (sz);
+ jcls->comm.tsize = sz;
+ jcls->comm.type = ARCH_JCLASS;
+ jcls->class_id = class_id;
+ jcls->tstamp = hrt;
+ char *str = (char*) (jcls + 1);
+ size_t i = CALL_UTIL (strlcpy)(str, cname, clen);
+ str += i;
+ while (i++ < clen)
+ *str++ = (char) 0; /* pad with 0's */
+ i = CALL_UTIL (strlcpy)(str, sname, slen);
+ str += i;
+ while (i++ < slen)
+ *str++ = (char) 0; /* pad with 0's */
+ collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jcls);
+}
+
+static void
+record_jmethod (uint64_t class_id, uint64_t method_id,
+ const char *mname, const char *msign)
+{
+ size_t mnlen = mname ? ARCH_STRLEN (mname) : 0;
+ size_t mslen = msign ? ARCH_STRLEN (msign) : 0;
+ size_t sz = sizeof (ARCH_jmethod) + mnlen + mslen;
+ ARCH_jmethod *jmth = (ARCH_jmethod*) alloca (sz);
+ if (jmth == NULL)
+ {
+ TprintfT (DBG_LT1, "jprofile: record_jmethod ERROR: failed to alloca(%ld)\n", (long) sz);
+ return;
+ }
+ jmth->comm.tsize = sz;
+ jmth->comm.type = ARCH_JMETHOD;
+ jmth->class_id = class_id;
+ jmth->method_id = method_id;
+ char *str = (char*) (jmth + 1);
+ if (mname)
+ {
+ size_t i = CALL_UTIL (strlcpy)(str, mname, mnlen);
+ str += i;
+ while (i++ < mnlen)
+ *str++ = (char) 0; /* pad with 0's */
+ }
+ if (msign)
+ {
+ size_t i = CALL_UTIL (strlcpy)(str, msign, mslen);
+ str += i;
+ while (i++ < mslen)
+ *str++ = (char) 0; /* pad with 0's */
+ }
+ collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jmth);
+}
+
+static void
+jvmti_ClassPrepare (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
+ jthread thread, jclass klass)
+{
+ hrtime_t hrt;
+ jint mnum;
+ jmethodID *mptr;
+ char *cname, *sname;
+ char *str1 = NULL;
+ int err = (*jvmti_env)->GetClassSignature (jvmti_env, klass, &str1, NULL);
+ if (err != JVMTI_ERROR_NONE || str1 == NULL || *str1 == (char) 0)
+ cname = NO_CLASS_NAME;
+ else
+ cname = str1;
+ if (*cname != 'L')
+ {
+ DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassPrepare: GetClassSignature failed. err=%d cname=%s\n", err, cname);
+ return;
+ }
+ char *str2 = NULL;
+ err = (*jvmti_env)->GetSourceFileName (jvmti_env, klass, &str2);
+ if (err != JVMTI_ERROR_NONE || str2 == NULL || *str2 == (char) 0)
+ sname = NO_SOURCE_FILE;
+ else
+ sname = str2;
+ DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassPrepare: cname=%s sname=%s\n", STR (cname), STR (sname));
+
+ /* Lock the whole file */
+ __collector_mutex_lock (&jclasses_lock);
+ hrt = gethrtime ();
+ record_jclass ((unsigned long) klass, hrt, cname, sname);
+ (*jvmti_env)->Deallocate (jvmti_env, (unsigned char *) str1);
+ (*jvmti_env)->Deallocate (jvmti_env, (unsigned char *) str2);
+ err = (*jvmti_env)->GetClassMethods (jvmti_env, klass, &mnum, &mptr);
+ if (err == JVMTI_ERROR_NONE)
+ {
+ for (int i = 0; i < mnum; i++)
+ {
+ char *mname, *msign;
+ err = (*jvmti_env)->GetMethodName (jvmti_env, mptr[i], &mname, &msign, NULL);
+ if (err != JVMTI_ERROR_NONE)
+ continue;
+ record_jmethod ((unsigned long) klass, (unsigned long) mptr[i], mname, msign);
+ // DeleteLocalRef( mptr[i] );
+ }
+ (*jvmti_env)->Deallocate (jvmti_env, (unsigned char*) mptr);
+ }
+ /* Unlock the file */
+ __collector_mutex_unlock (&jclasses_lock);
+}
+
+/*
+ * The CLASS_LOAD event is enabled to enable AsyncGetCallTrace
+ */
+static void
+jvmti_ClassLoad (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread, jclass klass)
+{
+ char *cname;
+ char *str1 = NULL;
+ int err = (*jvmti_env)->GetClassSignature (jvmti_env, klass, &str1, NULL);
+ if (err != JVMTI_ERROR_NONE || str1 == NULL || *str1 == (char) 0)
+ cname = NO_CLASS_NAME;
+ else
+ cname = str1;
+ jstring str = NULL;
+ const char* resourceName;
+ jobject classLoader = NULL;
+ err = (*jvmti)->GetClassLoader (jvmti, klass, &classLoader);
+ DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jprofile: jvmti_ClassLoad err=%d cname=%s\n", err, STR (cname));
+ if (err == 0)
+ {
+ if (classLoader == NULL)
+ {
+ // bootstrap class loader
+ resourceName = "";
+ }
+ else
+ {
+ char* name = (char *) alloca ((CALL_UTIL (strlen)(str1) + 32) * sizeof (char));
+ CALL_UTIL (strlcpy)(name, str1 + 1, CALL_UTIL (strlen)(str1));
+ name[CALL_UTIL (strlen)(name) - 1] = '\0'; // remove the last ';'
+ char* p;
+ for (p = name; *p != '\0'; p++)
+ if (*p == '.')
+ *p = '/';
+ CALL_UTIL (strlcat)(name, ".class", CALL_UTIL (strlen)(name) + CALL_UTIL (strlen)(".class") + 1);
+ if (getResource == NULL || toExternalForm == NULL)
+ {
+ resourceName = "";
+ DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: class %s failed to get path with method missing\n", STR (cname));
+ }
+ else
+ {
+ jobject url = (*jni_env)->CallObjectMethod (jni_env, classLoader, getResource, (*jni_env)->NewStringUTF (jni_env, name));
+ if (url == NULL)
+ {
+ resourceName = "";
+ DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: class %s failed to get path\n", STR (cname));
+ }
+ else
+ {
+ str = (jstring) (*jni_env)->CallObjectMethod (jni_env, url, toExternalForm);
+ resourceName = (*jni_env)->GetStringUTFChars (jni_env, str, NULL);
+ DprintfT (SP_DUMP_JAVA | SP_DUMP_TIME, "jvmti_ClassLoad: ARCH_JCLASS_LOCATION(Ox%x) class_id=0x%lx className='%s' fileName '%s'\n",
+ (int) ARCH_JCLASS_LOCATION, (unsigned long) klass, STR (cname), STR (resourceName));
+ size_t clen = ARCH_STRLEN (cname);
+ size_t slen = ARCH_STRLEN (resourceName);
+ size_t sz = sizeof (ARCH_jclass) + clen + slen;
+ ARCH_jclass_location *jcls = (ARCH_jclass_location*) alloca (sz);
+ jcls->comm.tsize = sz;
+ jcls->comm.type = ARCH_JCLASS_LOCATION;
+ jcls->class_id = (unsigned long) klass;
+ char *str = (char*) (jcls + 1);
+ size_t i = CALL_UTIL (strlcpy)(str, cname, clen);
+ str += i;
+ while (i++ < clen)
+ {
+ *str++ = (char) 0; /* pad with 0's */
+ }
+ i = CALL_UTIL (strlcpy)(str, resourceName, slen);
+ str += i;
+ while (i++ < slen)
+ {
+ *str++ = (char) 0; /* pad with 0's */
+ }
+ /* Lock the whole file */
+ __collector_mutex_lock (&jclasses_lock);
+ collector_interface->writeDataPacket (jprof_hndl, (CM_Packet*) jcls);
+ /* Unlock the file */
+ __collector_mutex_unlock (&jclasses_lock);
+ }
+ }
+ }
+ }
+}
+
+static void
+jvmti_MonitorEnter (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
+ jthread thread, jobject object)
+{
+ if (collector_jsync_begin)
+ collector_jsync_begin ();
+ TSD_Entry *tsd = collector_interface->getKey (tsd_key);
+ if (tsd == NULL)
+ return;
+ tsd->tstamp = gethrtime ();
+}
+
+static void
+jvmti_MonitorEntered (jvmtiEnv *jvmti_env, JNIEnv* jni_env,
+ jthread thread, jobject object)
+{
+ TSD_Entry *tsd = collector_interface->getKey (tsd_key);
+ if (tsd == NULL)
+ return;
+ if (collector_jsync_end)
+ collector_jsync_end (tsd->tstamp, object);
+}
+
+static void
+jvmti_GarbageCollectionStart (jvmtiEnv *jvmti_env)
+{
+ hrtime_t hrt = gethrtime ();
+ collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n",
+ SP_JCMD_GCSTART,
+ (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC)
+ );
+ TprintfT (DBG_LT1, "jprofile: jvmti_GarbageCollectionStart.\n");
+}
+
+static void
+jvmti_GarbageCollectionFinish (jvmtiEnv *jvmti_env)
+{
+ hrtime_t hrt = gethrtime ();
+ collector_interface->writeLog ("<event kind=\"%s\" tstamp=\"%u.%09u\"/>\n",
+ SP_JCMD_GCEND,
+ (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC)
+ );
+ TprintfT (DBG_LT1, "jprofile: jvmti_GarbageCollectionFinish.\n");
+}
+
+#if 0
+static void
+jvmti_MonitorWait (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
+ jobject object, jlong timed_out)
+{
+ if (collector_sync_begin)
+ collector_sync_begin ();
+ TSD_Entry *tsd = collector_interface->getKey (tsd_key);
+ if (tsd == NULL)
+ return;
+ tsd->tstamp = gethrtime ();
+}
+
+static void
+jvmti_MonitorWaited (jvmtiEnv *jvmti_env, JNIEnv* jni_env, jthread thread,
+ jobject object, jboolean timed_out)
+{
+ TSD_Entry *tsd = collector_interface->getKey (tsd_key);
+ if (tsd == NULL)
+ return;
+ if (collector_sync_end)
+ collector_sync_end (tsd->tstamp, object);
+}
+#endif
+
+static void
+jprof_find_asyncgetcalltrace ()
+{
+ void *jvmhandle;
+ if (__collector_VM_ReadByteInstruction == NULL)
+ __collector_VM_ReadByteInstruction = (int(*)()) dlsym (RTLD_DEFAULT, "Async_VM_ReadByteInstruction");
+
+ /* look for stack unwind function using default path */
+ AsyncGetCallTrace = (void (*)(JVMPI_CallTrace*, jint, ucontext_t*))
+ dlsym (RTLD_DEFAULT, "AsyncGetCallTrace");
+ if (AsyncGetCallTrace != NULL)
+ {
+ __collector_java_asyncgetcalltrace_loaded = 1;
+ TprintfT (DBG_LT1, "jprofile: AsyncGetCallTrace found with RTLD_DEFAULT\n");
+ }
+ else
+ {
+ /* not found there, find libjvm.so, and ask again */
+ jvmhandle = dlopen ("libjvm.so", RTLD_LAZY | RTLD_NOLOAD);
+ if (jvmhandle != NULL)
+ {
+ AsyncGetCallTrace = (void (*)(JVMPI_CallTrace*, jint, ucontext_t*))
+ dlsym (jvmhandle, "AsyncGetCallTrace");
+ }
+ }
+
+ if (AsyncGetCallTrace == NULL)
+ {
+ /* we could not find it -- write collector error */
+ TprintfT (0, "jprofile: ERROR -- AsyncGetCallTrace not found in address space\n");
+ char *err = dlerror ();
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_JVMNOJSTACK, err ? err : "");
+ __collector_java_mode = 0;
+ }
+ else
+ {
+ __collector_java_asyncgetcalltrace_loaded = 1;
+ TprintfT (DBG_LT1, "jprofile: AsyncGetCallTrace initialized in jprof_jvmpi_init_done_event\n");
+ }
+}
+
+int
+__collector_ext_jstack_unwind (char *ptr, int sz, ucontext_t *uc)
+{
+ if (AsyncGetCallTrace == NULL)
+ {
+ TprintfT (DBG_LT0, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace is NULL\n");
+ return 0;
+ }
+
+ TSD_Entry *tsd = collector_interface->getKey (tsd_key);
+ if (tsd == NULL)
+ {
+ TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd is NULL\n");
+ return 0;
+ }
+ if (__collector_java_attach && tsd->env == NULL && jvmti != NULL && jvm != NULL)
+ {
+ TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd->env is NULL under attach\n");
+ JNIEnv* jni_env = NULL;
+ (*jvm)->GetEnv (jvm, (void **) &jni_env, JNI_VERSION_1_2);
+ tsd->env = jni_env;
+ }
+ if (tsd->env == NULL)
+ {
+ TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: tsd->env is NULL\n");
+ return 0;
+ }
+
+ /* skip the Java stack whenever another signal handler is present */
+ if (uc->uc_link)
+ {
+ TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: uc->uc_link is non-NULL\n");
+ return 0;
+ }
+ /* we don't expect Java frames in signal handlers, so
+ * unroll the list of saved contexts to the topmost one
+ */
+ while (uc->uc_link)
+ uc = uc->uc_link;
+ Java_info *jinfo = (Java_info*) ptr;
+ jinfo->kind = JAVA_INFO;
+ jinfo->hsize = sizeof (Java_info);
+ ptr += sizeof (Java_info);
+ sz -= sizeof (Java_info);
+
+ JVMPI_CallTrace jtrace;
+ jtrace.env_id = tsd->env;
+ jtrace.frames = (JVMPI_CallFrame*) ptr;
+
+ /* nframes is how many frames we have room for */
+ jint nframes = sz / sizeof (JVMPI_CallFrame);
+
+#if WSIZE(64)
+ /* bug 6909545: garbage in 64-bit JAVA_INFO */
+ CALL_UTIL (memset)(jtrace.frames, 0, nframes * sizeof (JVMPI_CallFrame));
+#endif
+
+#if ARCH(SPARC)
+ // 21328946 JDK bug 8129933 causes <no java callstack recorded> on sparc-Linux
+ // convert from ucontext_t to sigcontext
+ struct sigcontext sctx;
+ sctx.sigc_regs.tpc = uc->uc_mcontext.mc_gregs[MC_PC];
+ __collector_memcpy (sctx.sigc_regs.u_regs, &uc->uc_mcontext.mc_gregs[3], sizeof (sctx.sigc_regs.u_regs));
+ uc = (ucontext_t *) (&sctx);
+#endif /* SPARC */
+ AsyncGetCallTrace (&jtrace, nframes, uc);
+
+ if (jtrace.num_frames == nframes)
+ {
+ JVMPI_CallFrame *last = &jtrace.frames[nframes - 1];
+ last->method_id = (jmethodID) SP_TRUNC_STACK_MARKER;
+ last->lineno = 0;
+ }
+
+ /* nframes is how many frames we actually got */
+ nframes = jtrace.num_frames;
+ TprintfT (DBG_LT3, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace jtrace.numframes = %d\n", nframes);
+ if (nframes <= 0)
+ {
+ /* negative values are error codes */
+ TprintfT (0, "jprofile: __collector_ext_jstack_unwind: AsyncGetCallTrace returned error: jtrace.numframes = %d\n", nframes);
+ nframes = 1;
+ JVMPI_CallFrame *err = (JVMPI_CallFrame*) ptr;
+ err->lineno = jtrace.num_frames; // bci = error code
+ err->method_id = 0; // artificial method id
+ }
+ jinfo->hsize += nframes * sizeof (JVMPI_CallFrame);
+ return jinfo->hsize;
+}
+
+/*
+ * Collector Java API implementation
+ */
+void
+Java_com_sun_forte_st_collector_CollectorAPI__1sample(JNIEnv *jEnv, jclass jCls, jstring jName)
+{
+ JNIEnv *jni;
+ jint res = (*jvm)->GetEnv (jvm, (void **) &jni, JNI_VERSION_1_2);
+ if (res < 0)
+ return;
+ const char *name = jName ? (*jni)->GetStringUTFChars (jni, jName, NULL) : NULL;
+ __collector_sample ((char*) name);
+}
+
+void
+Java_com_sun_forte_st_collector_CollectorAPI__1pause(JNIEnv *jEnv, jclass jCls)
+{
+ __collector_pause_m ("JAPI");
+}
+
+void
+Java_com_sun_forte_st_collector_CollectorAPI__1resume(JNIEnv *jEnv, jclass jCls)
+{
+ __collector_resume ();
+}
+
+void
+Java_com_sun_forte_st_collector_CollectorAPI__1terminate(JNIEnv *jEnv, jclass jCls)
+{
+ __collector_terminate_expt ();
+}
+#endif /* GPROFNG_JAVA_PROFILING */
+
+static void init_module () __attribute__ ((constructor));
+static void
+init_module ()
+{
+#if defined(GPROFNG_JAVA_PROFILING)
+ __collector_dlsym_guard = 1;
+ RegModuleFunc reg_module = (RegModuleFunc) dlsym (RTLD_DEFAULT, "__collector_register_module");
+ __collector_dlsym_guard = 0;
+ if (reg_module)
+ {
+ jprof_hndl = reg_module (&module_interface);
+ TprintfT (0, "jprofile: init_module.\n");
+ }
+#endif /* GPROFNG_JAVA_PROFILING */
+}
+
+int __collector_java_mode = 0;
+int __collector_java_asyncgetcalltrace_loaded = 0;
diff --git a/gprofng/libcollector/libcol-i386-dis.c b/gprofng/libcollector/libcol-i386-dis.c
new file mode 100644
index 0000000..9b3882a
--- /dev/null
+++ b/gprofng/libcollector/libcol-i386-dis.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 2022 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#if defined(__i386__) || defined(__x86_64)
+#include "opcodes/i386-dis.c"
+
+#undef _
+#undef M
+#include "libiberty/safe-ctype.c"
+#endif
+
diff --git a/gprofng/libcollector/libcol_hwcdrv.c b/gprofng/libcollector/libcol_hwcdrv.c
new file mode 100644
index 0000000..f3bd932
--- /dev/null
+++ b/gprofng/libcollector/libcol_hwcdrv.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "config.h"
+#include "collector.h" /* Tprintf*() */
+
+#define LIBCOLLECTOR_SRC
+#include "hwcdrv.c"
diff --git a/gprofng/libcollector/libcol_hwcfuncs.c b/gprofng/libcollector/libcol_hwcfuncs.c
new file mode 100644
index 0000000..1f5ad68
--- /dev/null
+++ b/gprofng/libcollector/libcol_hwcfuncs.c
@@ -0,0 +1,27 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "config.h"
+#include "collector.h" /* Tprintf*() */
+
+#define LIBCOLLECTOR_SRC
+#include "hwcfuncs.c"
+
+
diff --git a/gprofng/libcollector/libcol_util.c b/gprofng/libcollector/libcol_util.c
new file mode 100644
index 0000000..c709b3c
--- /dev/null
+++ b/gprofng/libcollector/libcol_util.c
@@ -0,0 +1,1693 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "config.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include "gp-defs.h"
+#include "collector.h"
+#include "libcol_util.h"
+#include "gp-experiment.h"
+#include "Emsgnum.h"
+#include "memmgr.h" // __collector_allocCSize, __collector_freeCSize
+#include "tsd.h"
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+
+/*
+ * This file is intended for collector's own implementation of
+ * various routines to avoid interaction with libc and other
+ * libraries.
+ */
+
+/* ------- libc interface ----------------- */
+CollectorUtilFuncs __collector_util_funcs = {NULL};
+int __collector_dlsym_guard = 0;
+int(*__collector_sscanfp)(const char *restrict s, const char *restrict fmt, ...);
+
+/*
+ * We have calls on Solaris to get the thread ID.
+ * On Linux, there is a gettid() system call.
+ * From user space, we have to use syscall(__NR_gettid).
+ * The call is probably fast (with the tid in vdso), but dbx intercepts the syscall.
+ * 7182047 syscall() has large overhead under dbx on linux
+ * One option is to use an assembly call to get the tid.
+ * We know how to do this on x86, but not on SPARC.
+ * So another option is to do the syscall once and cache the result in thread-local storage.
+ * This solves the SPARC case.
+ * On x86 we could use one or both strategies. So there are opportunities here to simplify the code.
+ */
+static unsigned gettid_key = COLLECTOR_TSD_INVALID_KEY;
+
+void
+__collector_ext_gettid_tsd_create_key ()
+{
+ gettid_key = __collector_tsd_create_key (sizeof (pid_t), NULL, NULL);
+}
+
+pid_t
+__collector_gettid ()
+{
+ pid_t *tid_ptr = (pid_t *) __collector_tsd_get_by_key (gettid_key);
+ // check if we have a thread-specific tid and if it's been initialized
+ // (it's 0 before initialization and cannot be 0 after since pid 0 is the boot process)
+ if (tid_ptr && *tid_ptr > 0)
+ return *tid_ptr;
+ pid_t r;
+
+#if ARCH(Intel)
+#if WSIZE(32)
+#define syscall_instr "int $0x80"
+#define syscall_clobber "memory"
+#else //WSIZE(64)
+#define syscall_instr "syscall"
+#define syscall_clobber "rcx", "r11", "memory"
+#endif
+ __asm__ __volatile__(syscall_instr
+ : "=a" (r) : "0" (__NR_gettid)
+ : syscall_clobber);
+#else
+ r = syscall (__NR_gettid);
+#endif
+ if (tid_ptr)
+ *tid_ptr = r;
+ return r;
+}
+
+static inline int
+atomic_swap (volatile int * p, int v)
+{
+#if ARCH(Intel)
+ int r;
+ __asm__ __volatile__("xchg %1, %2" : "=r" (r) : "m" (*p), "0" (v));
+ return r;
+#else
+ /* Since the inline templates perfan/libcollector/src/inline.*.il all
+ * have implementations for __collector_cas_32(), how about we just
+ * use that interface for Intel as well and drop the "#if ARCH()" stuff here?
+ *
+ * As it is, we're using an atomic swap on Intel and
+ * compare-and-swap on SPARC. The semantics are different
+ * (cas requires an expected "compare" value and swaps ONLY
+ * if we match that value). Nevertheless, the results of the
+ * two operations
+ * Intel: atomic_swap(&lock, 1)
+ * SPARC: cas(&lock,0,1)
+ * happen to be the same for the two cases we're interested in:
+ * if lock==0 lock=1 return 0
+ * if lock==1 lock=1 return 1
+ * You CANNOT always simply substitute cas for swap.
+ */
+ return __collector_cas_32 ((volatile uint32_t *)p, 0, v);
+#endif
+}
+
+int
+__collector_mutex_lock (collector_mutex_t *lock_var)
+{
+ volatile unsigned int i; /* xxxx volatile may not be honored on amd64 -x04 */
+
+ if (!(*lock_var) && !atomic_swap (lock_var, 1))
+ return 0;
+
+ do
+ {
+ while ((collector_mutex_t) (*lock_var) == 1)
+ i++;
+ }
+ while (atomic_swap (lock_var, 1));
+ return 0;
+}
+
+int
+__collector_mutex_trylock (collector_mutex_t *lock_var)
+{
+ if (!(*lock_var) && !atomic_swap (lock_var, 1))
+ return 0;
+ return EBUSY;
+}
+
+int
+__collector_mutex_unlock (collector_mutex_t *lock_var)
+{
+ (*lock_var) = 0;
+ return 0;
+}
+
+#if ARCH(SPARC)
+void
+__collector_inc_32 (volatile uint32_t *mem)
+{
+ uint32_t t1, t2;
+ __asm__ __volatile__(" ld %2,%0 \n"
+ "1: add %0,1,%1 \n"
+ " cas %2,%0,%1 \n"
+ " cmp %0,%1 \n"
+ " bne,a 1b \n"
+ " mov %1,%0 \n"
+ : "=&r" (t1), "=&r" (t2)
+ : "m" (*mem)
+ : "cc"
+ );
+}
+
+void
+__collector_dec_32 (volatile uint32_t *mem)
+{
+ uint32_t t1, t2;
+ __asm__ __volatile__(" ld %2,%0 \n"
+ "1: sub %0,1,%1 \n"
+ " cas %2,%0,%1 \n"
+ " cmp %0,%1 \n"
+ " bne,a 1b \n"
+ " mov %1,%0 \n"
+ : "=&r" (t1), "=&r" (t2)
+ : "m" (*mem)
+ : "cc"
+ );
+}
+
+uint32_t
+__collector_cas_32 (volatile uint32_t *mem, uint32_t old, uint32_t new)
+{
+ __asm__ __volatile__("cas [%1],%2,%0"
+ : "+r" (new)
+ : "r" (mem), "r" (old));
+ return new;
+}
+
+uint32_t
+__collector_subget_32 (volatile uint32_t *mem, uint32_t val)
+{
+ uint32_t t1, t2;
+ __asm__ __volatile__(" ld %2,%0 \n"
+ "1: sub %0,%3,%1 \n"
+ " cas %2,%0,%1 \n"
+ " cmp %0,%1 \n"
+ " bne,a 1b \n"
+ " mov %1,%0 \n"
+ " sub %0,%3,%1 \n"
+ : "=&r" (t1), "=&r" (t2)
+ : "m" (*mem), "r" (val)
+ : "cc"
+ );
+ return t2;
+}
+
+#if WSIZE(32)
+
+void *
+__collector_cas_ptr (volatile void *mem, void *old, void *new)
+{
+ __asm__ __volatile__("cas [%1],%2,%0"
+ : "+r" (new)
+ : "r" (mem), "r" (old));
+ return new;
+}
+
+uint64_t
+__collector_cas_64p (volatile uint64_t *mem, uint64_t *old, uint64_t *new)
+{
+ uint64_t t;
+ __asm__ __volatile__(" ldx [%2],%2 \n"
+ " ldx [%3],%3 \n"
+ " casx [%1],%2,%3 \n"
+ " stx %3,%0 \n"
+ : "=m" (t)
+ : "r" (mem), "r" (old), "r" (new)
+ );
+ return t;
+}
+
+#elif WSIZE(64)
+
+void *
+__collector_cas_ptr (volatile void *mem, void *old, void *new)
+{
+ __asm__ __volatile__("casx [%1],%2,%0"
+ : "+r" (new)
+ : "r" (mem), "r" (old));
+ return new;
+}
+
+uint64_t
+__collector_cas_64p (volatile uint64_t *mem, uint64_t *old, uint64_t *new)
+{
+ uint64_t t;
+ __asm__ __volatile__(" ldx [%2],%2 \n"
+ " ldx [%3],%3 \n"
+ " casx [%1],%2,%3 \n"
+ " mov %3,%0 \n"
+ : "=&r" (t)
+ : "r" (mem), "r" (old), "r" (new)
+ );
+ return t;
+}
+
+#endif /* WSIZE() */
+#endif /* ARCH() */
+
+void *
+__collector_memcpy (void *s1, const void *s2, size_t n)
+{
+ char *cp1 = (char*) s1;
+ char *cp2 = (char*) s2;
+ while (n--)
+ *cp1++ = *cp2++;
+ return s1;
+}
+
+static void *
+collector_memset (void *s, int c, size_t n)
+{
+ unsigned char *s1 = s;
+ while (n--)
+ *s1++ = (unsigned char) c;
+ return s;
+}
+
+int
+__collector_strcmp (const char *s1, const char *s2)
+{
+ for (;;)
+ {
+ if (*s1 != *s2)
+ return *s1 - *s2;
+ if (*s1 == 0)
+ return 0;
+ s1++;
+ s2++;
+ }
+}
+
+int
+__collector_strncmp (const char *s1, const char *s2, size_t n)
+{
+ while (n > 0)
+ {
+ if (*s1 != *s2)
+ return *s1 - *s2;
+ if (*s1 == 0)
+ return 0;
+ s1++;
+ s2++;
+ n--;
+ }
+ return 0;
+}
+
+char *
+__collector_strstr (const char *s1, const char *s2)
+{
+ if (s2 == NULL || *s2 == 0)
+ return NULL;
+ size_t len = __collector_strlen (s2);
+ for (char c = *s2; *s1; s1++)
+ if (c == *s1 && __collector_strncmp (s1, s2, len) == 0)
+ return (char *) s1;
+ return NULL;
+}
+
+char *
+__collector_strchr (const char *str, int chr)
+{
+ if (chr == '\0')
+ return (char *) (str + __collector_strlen (str));
+ for (; *str; str++)
+ if (chr == (int) *str)
+ return (char *) str;
+ return NULL;
+}
+
+char *
+__collector_strrchr (const char *str, int chr)
+{
+ const char *p = str + __collector_strlen (str);
+ for (; p - str >= 0; p--)
+ if (chr == *p)
+ return (char *) p;
+ return NULL;
+}
+
+int
+__collector_strStartWith (const char *s1, const char *s2)
+{
+ size_t slen = __collector_strlen (s2);
+ return __collector_strncmp (s1, s2, slen);
+}
+
+size_t
+__collector_strlen (const char *s)
+{
+ int len = -1;
+ while (s[++len] != '\0')
+ ;
+ return len;
+}
+
+size_t
+__collector_strlcpy (char *dst, const char *src, size_t dstsize)
+{
+ size_t srcsize = 0;
+ size_t n = dstsize - 1;
+ char c;
+ while ((c = *src++) != 0)
+ if (srcsize++ < n)
+ *dst++ = c;
+ if (dstsize > 0)
+ *dst = '\0';
+ return srcsize;
+}
+
+size_t
+__collector_strncpy (char *dst, const char *src, size_t dstsize)
+{
+ size_t i;
+ for (i = 0; i < dstsize; i++)
+ {
+ dst[i] = src[i];
+ if (src[i] == '\0')
+ break;
+ }
+ return i;
+}
+
+char *
+__collector_strcat (char *dst, const char *src)
+{
+ size_t sz = __collector_strlen (dst);
+ for (size_t i = 0;; i++)
+ {
+ dst[sz + i] = src[i];
+ if (src[i] == '\0')
+ break;
+ }
+ return dst;
+}
+
+size_t
+__collector_strlcat (char *dst, const char *src, size_t dstsize)
+{
+ size_t sz = __collector_strlen (dst);
+ return sz + __collector_strlcpy (dst + sz, src, dstsize - sz);
+}
+
+void *
+__collector_malloc (size_t size)
+{
+ void * ptr = __collector_allocCSize (__collector_heap, size, 0);
+ return ptr;
+}
+
+void *
+__collector_calloc (size_t nelem, size_t elsize)
+{
+ size_t n = nelem * elsize;
+ void * ptr = __collector_malloc (n);
+ if (NULL == ptr)
+ return NULL;
+ collector_memset (ptr, 0, n);
+ return ptr;
+}
+
+char *
+__collector_strdup (const char * str)
+{
+ if (NULL == str)
+ return NULL;
+ size_t size = __collector_strlen (str);
+ char * dst = (char *) __collector_malloc (size + 1);
+ if (NULL == dst)
+ return NULL;
+ __collector_strncpy (dst, str, size + 1);
+ return dst;
+}
+
+#define C_FMT 1
+#define C_STR 2
+static char
+Printable[256] = {//characters should be escaped by xml: "'<>&
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, /* ................ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
+ 3, 3, 1, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, /* !"#$%&'()*+,-./ */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 1, 3, /* 0123456789:;<=>? */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* @ABCDEFGHIJKLMNO */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* PQRSTUVWXYZ[\]^_ */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* `abcdefghijklmno */
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, /* pqrstuvwxyz{|}~. */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ................ */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* ................ */
+};
+static char hex[17] = "0123456789abcdef";
+static char HEX[17] = "0123456789ABCDEF";
+
+int
+__collector_xml_snprintf (char *s, size_t n, const char *format, ...)
+{
+ va_list args;
+ va_start (args, format);
+ int res = __collector_xml_vsnprintf (s, n, format, args);
+ va_end (args);
+ return res;
+}
+
+int
+__collector_xml_vsnprintf (char *s, size_t n, const char *format, va_list args)
+{
+ const char *src = format;
+ char *dst = s;
+ int cnt = 0;
+ unsigned char c;
+ while ((c = *src) != 0)
+ {
+ if (c == '%')
+ {
+ char numbuf[32];
+ int done = 0;
+ int jflag = 0;
+ int lflag = 0;
+ int zflag = 0;
+ int width = 0;
+ src++;
+ while (!done)
+ {
+ c = *src;
+ switch (c)
+ {
+ case '%':
+ {
+ if (cnt++ < n - 1)
+ *dst++ = '%';
+ if (cnt++ < n - 1)
+ *dst++ = hex[c / 16];
+ if (cnt++ < n - 1)
+ *dst++ = hex[c % 16];
+ if (cnt++ < n - 1)
+ *dst++ = '%';
+ src++;
+ done = 1;
+ break;
+ }
+ case '-':
+ {
+ if (jflag != 0)
+ done = 1;
+ else
+ {
+ jflag = 1;
+ src++;
+ }
+ break;
+ }
+ case 'l':
+ {
+ if (lflag != 0)
+ done = 1;
+ else
+ {
+ lflag = 1;
+ c = *++src;
+ if (c == 'l')
+ {
+ lflag++;
+ src++;
+ }
+ }
+ break;
+ }
+ case 'c':
+ {
+ unsigned char c1 = (unsigned char) va_arg (args, int);
+ if ((Printable[(int) c1] & C_STR) == 0)
+ {
+ if (c1 == '"')
+ {//&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
index 0000000..4384d47
--- /dev/null
+++ b/gprofng/libcollector/libcol_util.h
@@ -0,0 +1,321 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#ifndef _LIBCOL_UTIL_H
+#define _LIBCOL_UTIL_H
+
+#include <stdarg.h>
+#include <pthread.h>
+#include <signal.h>
+
+// LIBCOLLECTOR NOT I18N
+#define NTXT(x) x
+#define STXT(x) x
+
+extern int __collector_tracelevel;
+
+/* Initialization function */
+extern int __collector_util_init();
+extern void __collector_libkstat_funcs_init();
+extern void __collector_libscf_funcs_init();
+
+/* ------- functions from libcol_util.c ----------------- */
+extern void * __collector_memcpy (void *s1, const void *s2, size_t n);
+extern int (*__collector_sscanfp)(const char *restrict s, const char *restrict fmt, ...);
+extern char * __collector_strcat (char *s1, const char *s2);
+extern char * __collector_strchr (const char *s1, int chr);
+extern size_t __collector_strlcpy (char *dst, const char *src, size_t dstsize);
+extern char* __collector_strrchr (const char *str, int chr);
+extern size_t __collector_strlen (const char *s);
+extern size_t __collector_strlcat (char *dst, const char *src, size_t dstsize);
+extern char* __collector_strchr (const char *str, int chr);
+extern int __collector_strcmp (const char *s1, const char *s2);
+extern int __collector_strncmp (const char *s1, const char *s2, size_t n);
+extern char * __collector_strstr (const char *s1, const char *s2);
+extern size_t __collector_strncpy (char *dst, const char *src, size_t dstsize);
+extern size_t __collector_strncat (char *dst, const char *src, size_t dstsize);
+extern void * __collector_malloc (size_t size);
+extern void * __collector_calloc (size_t nelem, size_t elsize);
+extern char * __collector_strdup (const char * str);
+extern int __collector_strStartWith (const char *s1, const char *s2);
+extern int __collector_xml_snprintf (char *s, size_t n, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
+extern int __collector_xml_vsnprintf (char *s, size_t n, const char *format, va_list args);
+
+/* ------- collector_thread ----------------- */
+pid_t __collector_gettid ();
+extern void __collector_ext_gettid_tsd_create_key ();
+#define collector_thread_t pthread_t // not using pid_t, since tid is defined as pthread_t in package structures, and other codes assume this type
+#define statvfs_t struct statvfs
+#define __collector_lwp_self() (collector_thread_t)__collector_gettid() // not using pthread_self()
+#define __collector_thr_self() (collector_thread_t)__collector_gettid() // not using pthread_self()
+
+/* ------- collector_mutex ----------------- */
+/*
+ * mutex_init is defined in libthread. If we don't want to interact
+ * with libthread we should use memset to initialize mutexes
+ */
+
+typedef volatile int collector_mutex_t;
+#define COLLECTOR_MUTEX_INITIALIZER 0
+extern int __collector_mutex_lock (collector_mutex_t *mp);
+extern int __collector_mutex_unlock (collector_mutex_t *mp);
+extern int __collector_mutex_trylock (collector_mutex_t *mp);
+
+#define __collector_mutex_init(xx) \
+ do { collector_mutex_t tmp=COLLECTOR_MUTEX_INITIALIZER; *(xx)=tmp; } while(0)
+
+void __collector_sample (char *name);
+void __collector_terminate_expt ();
+void __collector_pause ();
+void __collector_pause_m ();
+void __collector_resume ();
+
+struct DT_lineno;
+
+typedef enum
+{
+ DFUNC_API = 1, /* dynamic function declared with API */
+ DFUNC_JAVA, /* dynamically compiled java method */
+ DFUNC_KERNEL /* dynamic code mapped by the kernel (Linux) */
+} dfunc_mode_t;
+
+extern void __collector_int_func_load (dfunc_mode_t mode, char *name,
+ char *sourcename, void *vaddr,
+ int size, int lntsize,
+ struct DT_lineno *lntable);
+extern void __collector_int_func_unload (dfunc_mode_t mode, void *vaddr);
+
+extern int __collector_sigaction (int sig, const struct sigaction *nact,
+ struct sigaction *oact);
+extern void __collector_SIGDFL_handler (int sig);
+extern int __collector_ext_itimer_set (int period);
+
+#if ARCH(Intel)
+/* Atomic functions on x86/x64 */
+
+/**
+ * This function enables the inrementing (by one) of the value stored in target
+ * to occur in an atomic manner.
+ */
+static __attribute__ ((always_inline)) inline void
+__collector_inc_32 (uint32_t *ptr)
+{
+ __asm__ __volatile__("lock; incl %0"
+ : // "=m" (*ptr) // output
+ : "m" (*ptr)); // input
+}
+
+/**
+ * This function enables the decrementing (by one) of the value stored in target
+ * to occur in an atomic manner.
+ */
+static __attribute__ ((always_inline)) inline void
+__collector_dec_32 (volatile uint32_t *ptr)
+{
+ __asm__ __volatile__("lock; decl %0"
+ : // "=m" (*ptr) // output
+ : "m" (*ptr)); // input
+}
+/**
+ * This function subtrackts the value "off" of the value stored in target
+ * to occur in an atomic manner, and returns new value stored in target.
+ */
+static __attribute__ ((always_inline)) inline uint32_t
+__collector_subget_32 (uint32_t *ptr, uint32_t off)
+{
+ uint32_t r;
+ uint32_t offset = off;
+ __asm__ __volatile__("movl %2, %0; negl %0; lock; xaddl %0, %1"
+ : "=r" (r), "=m" (*ptr) /* output */
+ : "a" (off), "r" (*ptr) /* input */
+ );
+ return (r - offset);
+}
+/**
+ * This function returns the value of the stack pointer register
+ */
+static __attribute__ ((always_inline)) inline void *
+__collector_getsp ()
+{
+ void *r;
+#if WSIZE(64)
+ __asm__ __volatile__("movq %%rsp, %0"
+#else
+ __asm__ __volatile__("movl %%esp, %0"
+#endif
+ : "=r" (r)); // output
+ return r;
+}
+/**
+ * This function returns the value of the frame pointer register
+ */
+static __attribute__ ((always_inline)) inline void *
+__collector_getfp ()
+{
+ void *r;
+#if WSIZE(64)
+ __asm__ __volatile__("movq %%rbp, %0"
+#else
+ __asm__ __volatile__("movl %%ebp, %0"
+#endif
+ : "=r" (r)); // output
+ return r;
+}
+/**
+ * This function returns the value of the processor counter register
+ */
+static __attribute__ ((always_inline)) inline void *
+__collector_getpc ()
+{
+ void *r;
+ __asm__ __volatile__(
+#if WSIZE(32)
+ " call 1f \n"
+ "1: popl %0 \n"
+#else
+ " call 1f \n"
+ "1: popq %0 \n"
+#endif
+ : "=r" (r)); // output
+ return r;
+}
+
+/**
+ * This function enables a compare and swap operation to occur atomically.
+ * The 32-bit value stored in target is compared with "old". If these values
+ * are equal, the value stored in target is replaced with "new". The old
+ * 32-bit value stored in target is returned by the function whether or not
+ * the replacement occurred.
+ */
+static __attribute__ ((always_inline)) inline uint32_t
+__collector_cas_32 (volatile uint32_t *pdata, uint32_t old, uint32_t new)
+{
+ uint32_t r;
+ __asm__ __volatile__("lock; cmpxchgl %2, %1"
+ : "=a" (r), "=m" (*pdata) : "r" (new),
+ "a" (old), "m" (*pdata));
+ return r;
+}
+/**
+ * This function enables a compare and swap operation to occur atomically.
+ * The 64-bit value stored in target is compared with "old". If these values
+ * are equal, the value stored in target is replaced with "new". The old
+ * 64-bit value stored in target is returned by the function whether or not
+ * the replacement occurred.
+ */
+static __attribute__ ((always_inline)) inline uint64_t
+__collector_cas_64p (volatile uint64_t *mem, uint64_t *old, uint64_t * new)
+{
+ uint64_t r;
+#if WSIZE(32)
+ uint32_t old1 = (uint32_t) (*old & 0xFFFFFFFFL);
+ uint32_t old2 = (uint32_t) ((*old >> 32) & 0xFFFFFFFFL);
+ uint32_t new1 = (uint32_t) (*new & 0xFFFFFFFFL);
+ uint32_t new2 = (uint32_t) ((*new >> 32) & 0xFFFFFFFFL);
+ uint32_t res1 = 0;
+ uint32_t res2 = 0;
+ __asm__ __volatile__(
+ "movl %3, %%esi; lock; cmpxchg8b (%%esi); movl %%edx, %2; movl %%eax, %1"
+ : "=m" (r), "=m" (res1), "=m" (res2) /* output */
+ : "m" (mem), "a" (old1), "d" (old2), "b" (new1), "c" (new2) /* input */
+ : "memory", "cc", "esi" //, "edx", "ecx", "ebx", "eax" /* clobbered register */
+ );
+ r = (((uint64_t) res2) << 32) | ((uint64_t) res1);
+#else
+ __asm__ __volatile__( "lock; cmpxchgq %2, %1"
+ : "=a" (r), "=m" (*mem) /* output */
+ : "r" (*new), "a" (*old), "m" (*mem) /* input */
+ : "%rcx", "rdx" /* clobbered register */
+ );
+#endif
+ return r;
+}
+/**
+ * This function enables a compare and swap operation to occur atomically.
+ * The 32-/64-bit value stored in target is compared with "cmp". If these values
+ * are equal, the value stored in target is replaced with "new".
+ * The old value stored in target is returned by the function whether or not
+ * the replacement occurred.
+ */
+static __attribute__ ((always_inline)) inline void *
+__collector_cas_ptr (void *mem, void *cmp, void *new)
+{
+ void *r;
+#if WSIZE(32)
+ r = (void *) __collector_cas_32 ((volatile uint32_t *)mem, (uint32_t) cmp, (uint32_t)new);
+#else
+ __asm__ __volatile__("lock; cmpxchgq %2, (%1)"
+ : "=a" (r), "=b" (mem) /* output */
+ : "r" (new), "a" (cmp), "b" (mem) /* input */
+ );
+#endif
+ return r;
+}
+
+#elif ARCH(Aarch64)
+static __attribute__ ((always_inline)) inline uint32_t
+__collector_inc_32 (volatile uint32_t *ptr)
+{
+ return __sync_add_and_fetch (ptr, 1);
+}
+
+static __attribute__ ((always_inline)) inline uint32_t
+__collector_dec_32 (volatile uint32_t *ptr)
+{
+ return __sync_sub_and_fetch (ptr, 1);
+}
+
+static __attribute__ ((always_inline)) inline uint32_t
+__collector_subget_32 (volatile uint32_t *ptr, uint32_t off)
+{
+ return __sync_sub_and_fetch (ptr, off);
+}
+
+static __attribute__ ((always_inline)) inline uint32_t
+__collector_cas_32 (volatile uint32_t *ptr, uint32_t old, uint32_t new)
+{
+ return __sync_val_compare_and_swap (ptr, old, new);
+}
+
+static __attribute__ ((always_inline)) inline uint64_t
+__collector_cas_64p (volatile uint64_t *ptr, uint64_t *old, uint64_t * new)
+{
+ return __sync_val_compare_and_swap (ptr, *old, *new);
+}
+
+static __attribute__ ((always_inline)) inline void *
+__collector_cas_ptr (void *ptr, void *old, void *new)
+{
+ return (void *) __sync_val_compare_and_swap ((unsigned long *) ptr, (unsigned long) old, (unsigned long) new);
+}
+
+#else
+extern void __collector_flushw (); /* defined for SPARC only */
+extern void* __collector_getpc ();
+extern void* __collector_getsp ();
+extern void* __collector_getfp ();
+extern void __collector_inc_32 (volatile uint32_t *);
+extern void __collector_dec_32 (volatile uint32_t *);
+extern void* __collector_cas_ptr (volatile void *, void *, void *);
+extern uint32_t __collector_cas_32 (volatile uint32_t *, uint32_t, uint32_t);
+extern uint32_t __collector_subget_32 (volatile uint32_t *, uint32_t);
+extern uint64_t __collector_cas_64p (volatile uint64_t *, uint64_t *, uint64_t *);
+#endif /* ARCH() */
+#endif /* _LIBCOL_UTIL_H */
diff --git a/gprofng/libcollector/linetrace.c b/gprofng/libcollector/linetrace.c
new file mode 100644
index 0000000..970d68c
--- /dev/null
+++ b/gprofng/libcollector/linetrace.c
@@ -0,0 +1,2005 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/*
+ * Lineage events for process fork, exec, etc.
+ */
+
+#include "config.h"
+#include <string.h>
+#include <elf.h>
+#include <regex.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include "descendants.h"
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LTT 0 // for interposition on GLIBC functions
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+
+#define LT_MAXNAMELEN 1024
+#define LT_MAXPATHLEN 1024
+
+int __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
+int dbg_current_mode = FOLLOW_NONE; /* for debug only */
+unsigned line_key = COLLECTOR_TSD_INVALID_KEY;
+line_mode_t line_mode = LM_DORMANT;
+int user_follow_mode = FOLLOW_ON;
+int java_mode = 0;
+
+static char *user_follow_spec;
+static char new_lineage[LT_MAXNAMELEN];
+static char curr_lineage[LT_MAXNAMELEN];
+static char linetrace_exp_dir_name[LT_MAXPATHLEN + 1]; // experiment directory
+
+/* lineage tracking for descendants of this process */
+
+static int fork_linenum = 0;
+static int line_initted = 0;
+static collector_mutex_t fork_lineage_lock = COLLECTOR_MUTEX_INITIALIZER;
+static collector_mutex_t clone_lineage_lock = COLLECTOR_MUTEX_INITIALIZER;
+
+/* interposition */
+#define CALL_REAL(x) (*(int(*)())__real_##x)
+#define CALL_REALC(x) (*(char*(*)())__real_##x)
+#define CALL_REALF(x) (*(FILE*(*)())__real_##x)
+#define NULL_PTR(x) ( __real_##x == NULL )
+
+// For a given Linux, which lib functions have more than one GLIBC version? Do this:
+// objdump -T `find /lib /lib64 -name "*.so*"` | grep GLIBC | grep text | grep \(
+static void *__real_fork = NULL;
+static void *__real_vfork = NULL;
+static void *__real_execve = NULL;
+static void *__real_execvp = NULL;
+static void *__real_execv = NULL;
+static void *__real_execle = NULL;
+static void *__real_execlp = NULL;
+static void *__real_execl = NULL;
+static void *__real_clone = NULL;
+static void *__real_grantpt = NULL;
+static void *__real_ptsname = NULL;
+static void *__real_popen = NULL;
+static int clone_linenum = 0;
+#if ARCH(Intel)
+#if WSIZE(32)
+static void *__real_popen_2_1 = NULL;
+static void *__real_popen_2_0 = NULL;
+static void *__real_posix_spawn_2_15 = NULL;
+static void *__real_posix_spawnp_2_15 = NULL;
+static void *__real_posix_spawn_2_2 = NULL;
+static void *__real_posix_spawnp_2_2 = NULL;
+#elif WSIZE(64)
+static void *__real_posix_spawn_2_15 = NULL;
+static void *__real_posix_spawnp_2_15 = NULL;
+static void *__real_posix_spawn_2_2_5 = NULL;
+static void *__real_posix_spawnp_2_2_5 = NULL;
+#endif /* WSIZE() */
+#endif /* ARCH(Intel) */
+static void *__real_system = NULL;
+static void *__real_posix_spawn = NULL;
+static void *__real_posix_spawnp = NULL;
+static void *__real_setuid = NULL;
+static void *__real_seteuid = NULL;
+static void *__real_setreuid = NULL;
+static void *__real_setgid = NULL;
+static void *__real_setegid = NULL;
+static void *__real_setregid = NULL;
+static void linetrace_dormant ();
+static int check_follow_fork ();
+static int check_follow_exec (const char *execfile);
+static int check_follow_combo (const char *execfile);
+static int path_collectable (const char *execfile);
+static char * build_experiment_path (char *instring, size_t instring_sz, const char *lineage_str);
+static int init_lineage_intf ();
+
+/* ------- "Previously dbx-visible" function prototypes ----------------- */
+static int linetrace_follow_experiment (const char *follow_spec, const char *lineage_str, const char *execfile);
+static char *lineage_from_expname (char *lineage_str, size_t lstr_sz, const char *expname);
+static void linetrace_ext_fork_prologue (const char *variant, char * new_lineage, int *following_fork);
+static void linetrace_ext_fork_epilogue (const char *variant, const pid_t ret, char * new_lineage, int *following_fork);
+static char **linetrace_ext_exec_prologue (const char *variant,
+ const char* path, char *const argv[], char *const envp[], int *following_exec);
+static void linetrace_ext_exec_epilogue (const char *variant, char *const envp[], const int ret, int *following_exec);
+static void linetrace_ext_combo_prologue (const char *variant, const char *cmd, int *following_combo);
+static void linetrace_ext_combo_epilogue (const char *variant, const int ret, int *following_combo);
+
+#ifdef DEBUG
+static int
+get_combo_flag ()
+{
+ int * guard = NULL;
+ int combo_flag = ((line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0);
+ return combo_flag;
+}
+#endif /* DEBUG */
+
+/* must be called for potentially live experiment */
+int
+__collector_ext_line_init (int *precord_this_experiment,
+ const char * progspec, const char * progname)
+{
+ *precord_this_experiment = 1;
+ TprintfT (DBG_LT0, "__collector_ext_line_init(%s)\n", progspec);
+ if (NULL_PTR (fork))
+ if (init_lineage_intf ())
+ {
+ TprintfT (DBG_LT0, "__collector_ext_line_init() ERROR: initialization failed.\n");
+ return COL_ERROR_LINEINIT;
+ }
+ /* check the follow spec */
+ user_follow_spec = CALL_UTIL (getenv)(SP_COLLECTOR_FOLLOW_SPEC);
+ if (user_follow_spec != NULL)
+ {
+ TprintfT (DBG_LT0, "collector: %s=%s\n", SP_COLLECTOR_FOLLOW_SPEC, user_follow_spec);
+ if (!linetrace_follow_experiment (user_follow_spec, curr_lineage, progname))
+ {
+ *precord_this_experiment = 0;
+ TprintfT (DBG_LT0, "collector: -F =<regex> does not match, will NOT be followed\n");
+ }
+ else
+ TprintfT (DBG_LT0, "collector: -F =<regex> matches, will be followed\n");
+ user_follow_mode = FOLLOW_ALL;
+ }
+ __collector_env_save_preloads ();
+ TprintfT (DBG_LT0, "__collector_ext_line_init(), progname=%s, followspec=%s, followthis=%d\n",
+ progname, user_follow_spec ? user_follow_spec : "NULL",
+ *precord_this_experiment);
+ line_mode = LM_TRACK_LINEAGE; /* even if we don't follow, we report the interposition */
+ line_initted = 1;
+ return COL_ERROR_NONE;
+}
+
+/*
+ * int __collector_ext_line_install(args)
+ * Check args to determine which line events to follow.
+ * Create tsd key for combo flag.
+ */
+int
+__collector_ext_line_install (char *args, const char * expname)
+{
+ if (!line_initted)
+ {
+ TprintfT (DBG_LT0, "__collector_ext_line_install(%s) ERROR: init hasn't be called yet\n", args);
+ return COL_ERROR_EXPOPEN;
+ }
+ TprintfT (DBG_LT0, "__collector_ext_line_install(%s, %s)\n", args, expname);
+ line_key = __collector_tsd_create_key (sizeof (int), NULL, NULL);
+
+ /* determine experiment name */
+ __collector_strlcpy (linetrace_exp_dir_name, expname, sizeof (linetrace_exp_dir_name));
+ lineage_from_expname (curr_lineage, sizeof (curr_lineage), linetrace_exp_dir_name);
+ user_follow_mode = CALL_UTIL (atoi)(args);
+ TprintfT (DBG_LT0, "__collector_ext_line_install() user_follow_mode=0x%X, linetrace_exp_dir_name=%s\n",
+ user_follow_mode, linetrace_exp_dir_name);
+
+ // determine java mode
+ char * java_follow_env = CALL_UTIL (getenv)(JAVA_TOOL_OPTIONS);
+ if (java_follow_env != NULL && CALL_UTIL (strstr)(java_follow_env, COLLECTOR_JVMTI_OPTION))
+ java_mode = 1;
+
+ // backup collector specific env
+ if (sp_env_backup == NULL)
+ {
+ sp_env_backup = __collector_env_backup ();
+ TprintfT (DBG_LT0, "__collector_ext_line_install creating sp_env_backup -- 0x%p\n", sp_env_backup);
+ }
+ else
+ TprintfT (DBG_LT0, "__collector_ext_line_install existing sp_env_backup -- 0x%p\n", sp_env_backup);
+ if (user_follow_mode == FOLLOW_NONE)
+ __collector_env_unset (NULL);
+
+ char logmsg[256];
+ logmsg[0] = '\0';
+ if (user_follow_mode != FOLLOW_NONE)
+ CALL_UTIL (strlcat)(logmsg, "fork|exec|combo", sizeof (logmsg));
+ size_t slen = __collector_strlen (logmsg);
+ if (slen > 0)
+ logmsg[slen] = '\0';
+ else
+ CALL_UTIL (strlcat)(logmsg, "none", sizeof (logmsg));
+
+ /* report which line events are followed */
+ (void) __collector_log_write ("<setting %s=\"%s\"/>\n", SP_JCMD_LINETRACE, logmsg);
+ TprintfT (DBG_LT0, "__collector_ext_line_install(%s): %s \n", expname, logmsg);
+ return COL_ERROR_NONE;
+}
+
+char *
+lineage_from_expname (char *lineage_str, size_t lstr_sz, const char *expname)
+{
+ TprintfT (DBG_LT0, "lineage_from_expname(%s, %s)\n", lineage_str, expname);
+ char *p = NULL;
+ if (lstr_sz < 1 || !lineage_str || !expname)
+ {
+ TprintfT (DBG_LT0, "lineage_from_expname(): ERROR, null string\n");
+ return NULL;
+ }
+ /* determine lineage from experiment name */
+ p = __collector_strrchr (expname, '/');
+ if ((p == NULL) || (*++p != '_'))
+ {
+ lineage_str[0] = 0;
+ TprintfT (DBG_LT2, "lineage_from_expname(): expt=%s lineage=\".\" (founder)\n", expname);
+ }
+ else
+ {
+ size_t tmp = __collector_strlcpy (lineage_str, p, lstr_sz);
+ if (tmp >= lstr_sz)
+ TprintfT (DBG_LT0, "lineage_from_expname(): ERROR: expt=%s lineage=\"%s\" truncated %ld characters\n",
+ expname, lineage_str, (long) (tmp - lstr_sz));
+ lineage_str[lstr_sz - 1] = 0;
+ p = __collector_strchr (lineage_str, '.');
+ if (p != NULL)
+ *p = '\0';
+ TprintfT (DBG_LT2, "lineage_from_expname(): expt=%s lineage=\"%s\"\n", expname, lineage_str);
+ }
+ return lineage_str;
+}
+
+/*
+ * void __collector_line_cleanup (void)
+ * Disable logging. Clear backup ENV.
+ */
+void
+__collector_line_cleanup (void)
+{
+ if (line_mode == LM_CLOSED)
+ {
+ TprintfT (DBG_LT0, "__collector_line_cleanup(): WARNING, line is already closed\n");
+ return;
+ }
+ else if (line_mode == LM_DORMANT)
+ TprintfT (DBG_LT0, "__collector_line_cleanup(): ERROR, line is DORMANT\n");
+ else
+ TprintfT (DBG_LT0, "__collector_line_cleanup()\n");
+ line_mode = LM_CLOSED;
+ user_follow_mode = FOLLOW_NONE;
+ dbg_current_mode = FOLLOW_NONE; /* for debug only */
+ line_key = COLLECTOR_TSD_INVALID_KEY;
+ java_mode = 0;
+ if (sp_env_backup != NULL)
+ {
+ __collector_env_backup_free ();
+ sp_env_backup = NULL;
+ }
+ return;
+}
+
+/*
+ * void __collector_ext_line_close (void)
+ * Disable logging. Cleans ENV vars. Clear backup ENV.
+ */
+void
+__collector_ext_line_close (void)
+{
+ TprintfT (DBG_LT0, "__collector_ext_line_close()\n");
+ __collector_line_cleanup ();
+ __collector_env_unset (NULL);
+ return;
+}
+
+/*
+ * void linetrace_dormant(void)
+ * Disable logging. Preserve ENV vars.
+ */
+static void
+linetrace_dormant (void)
+{
+ if (line_mode == LM_DORMANT)
+ {
+ TprintfT (DBG_LT0, "linetrace_dormant() -- already dormant\n");
+ return;
+ }
+ else if (line_mode == LM_CLOSED)
+ {
+ TprintfT (DBG_LT0, "linetrace_dormant(): ERROR, line is already CLOSED\n");
+ return;
+ }
+ else
+ TprintfT (DBG_LT0, "linetrace_dormant()\n");
+ line_mode = LM_DORMANT;
+ return;
+}
+
+static int
+check_follow_fork ()
+{
+ int follow = (user_follow_mode != FOLLOW_NONE);
+ TprintfT (DBG_LT0, "check_follow_fork()=%d\n", follow);
+ return follow;
+}
+
+static int
+check_follow_exec (const char *execfile)
+{
+ int follow = (user_follow_mode != FOLLOW_NONE);
+ if (follow)
+ {
+ /* revise based on collectability of execfile */
+ follow = path_collectable (execfile);
+ }
+ TprintfT (DBG_LT0, "check_follow_exec(%s)=%d\n", execfile, follow);
+ return follow;
+}
+
+static int
+check_follow_combo (const char *execfile)
+{
+ int follow = (user_follow_mode != FOLLOW_NONE);
+ TprintfT (DBG_LT0, "check_follow_combo(%s)=%d\n", execfile, follow);
+ return follow;
+}
+
+static int
+check_fd_dynamic (int fd)
+{
+ TprintfT (DBG_LT0, "check_fd_dynamic(%d)\n", fd);
+ off_t off = CALL_UTIL (lseek)(fd, (off_t) 0, SEEK_END);
+ size_t sz = (size_t) 8192; /* one page should suffice */
+ if (sz > off)
+ sz = off;
+ char *p = CALL_UTIL (mmap64)((char *) 0, sz, PROT_READ, MAP_PRIVATE, fd, (off64_t) 0);
+ if (p == MAP_FAILED)
+ {
+ TprintfT (DBG_LT0, "check_fd_dynamic(): ERROR/WARNING: mmap failed for `%d'\n", fd);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
+ COL_WARN_NOFOLLOW, "mmap-failed");
+ return 0;
+ }
+ char elfclass = p[EI_CLASS];
+ if ((p[EI_MAG0] != ELFMAG0) ||
+ (p[EI_MAG1] != ELFMAG1) ||
+ (p[EI_MAG2] != ELFMAG2) ||
+ (p[EI_MAG3] != ELFMAG3) ||
+ (elfclass != ELFCLASS32 && elfclass != ELFCLASS64)
+ )
+ {
+ TprintfT (DBG_LT0, "check_fd_dynamic(): WARNING: Command `%d' is not executable ELF!\n", fd);
+ CALL_UTIL (munmap)(p, sz);
+ return 1;
+ }
+ Elf32_Ehdr *ehdr32 = (Elf32_Ehdr*) p;
+ Elf64_Ehdr *ehdr64 = (Elf64_Ehdr*) p;
+ Elf64_Off e_phoff;
+ Elf64_Half e_phnum;
+ Elf64_Half e_phentsize;
+ if (elfclass == ELFCLASS32)
+ {
+ e_phoff = ehdr32->e_phoff;
+ e_phnum = ehdr32->e_phnum;
+ e_phentsize = ehdr32->e_phentsize;
+ }
+ else
+ {
+ e_phoff = ehdr64->e_phoff;
+ e_phnum = ehdr64->e_phnum;
+ e_phentsize = ehdr64->e_phentsize;
+ }
+ if ((sizeof (Elf32_Ehdr) > sz) ||
+ (sizeof (Elf64_Ehdr) > sz) ||
+ (e_phoff + e_phentsize * (e_phnum - 1) > sz))
+ {
+ TprintfT (DBG_LT0, "check_fd_dynamic(): WARNING: Command `%d' ELF file did not fit in page!\n", fd);
+#if 0
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
+ COL_WARN_RISKYFOLLOW, "ELF header size");
+#endif
+ CALL_UTIL (munmap)(p, sz);
+ return 1;
+ }
+ TprintfT (DBG_LT2, "check_fd_dynamic(): elfclass=%d, e_phoff=%lu e_phnum=%lu e_phentsize=%lu\n",
+ (int) elfclass, (unsigned long) e_phoff, (unsigned long) e_phnum,
+ (unsigned long) e_phentsize);
+ int dynamic = 0;
+ Elf64_Half i;
+ for (i = 0; i < e_phnum; i++)
+ {
+ if (elfclass == ELFCLASS32)
+ {
+ if (PT_DYNAMIC ==
+ ((Elf32_Phdr*) (p + e_phoff + e_phentsize * i))->p_type)
+ {
+ dynamic = 1;
+ break;
+ }
+ }
+ else
+ {
+ if (PT_DYNAMIC ==
+ ((Elf64_Phdr*) (p + e_phoff + e_phentsize * i))->p_type)
+ {
+ dynamic = 1;
+ break;
+ }
+ }
+ }
+ if (!dynamic)
+ {
+ TprintfT (DBG_LT0, "check_fd_dynamic(): ERROR/WARNING: Command `%d' is not a dynamic executable!\n", fd);
+#if 0
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
+ COL_WARN_NOFOLLOW, "!dynamic");
+#endif
+ }
+ else
+ TprintfT (DBG_LT2, "check_fd_dynamic(): Command `%d' is a dynamic executable!\n", fd);
+ CALL_UTIL (munmap)(p, sz);
+ return dynamic;
+}
+
+static int
+check_dynamic (const char *execfile)
+{
+ TprintfT (DBG_LT2, "check_dynamic(%s)\n", execfile);
+ int fd = CALL_UTIL (open)(execfile, O_RDONLY);
+ if (fd == -1)
+ {
+ TprintfT (DBG_LT0, "check_dynamic(): ERROR/WARNING: Command `%s' could not be opened!\n", execfile);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
+ COL_WARN_RISKYFOLLOW, "open");
+ return 1; /* follow, though exec will presumably fail */
+ }
+ int ret = check_fd_dynamic (fd);
+ CALL_UTIL (close)(fd);
+ return ret;
+}
+
+static int
+path_collectable (const char *execfile)
+{
+ TprintfT (DBG_LT0, "path_collectable(%s)\n", execfile);
+ /* Check that execfile exists and is a collectable executable */
+ /* logging warning when collection is likely to be unsuccessful */
+ /* (if check isn't accurate, generally best not to include it) */
+
+ if (execfile && !__collector_strchr (execfile, '/'))
+ { /* got an unqualified name */
+ /* XXXX locate execfile on PATH to be able to check it */
+ TprintfT (DBG_LT0, "path_collectable(): WARNING: Can't check unqualified executable `%s'\n", execfile);
+#if 0
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
+ COL_WARN_RISKYFOLLOW, "path");
+#endif
+ return 1; /* follow unqualified execfile unchecked */
+ }
+ struct stat sbuf;
+ if (stat (execfile, &sbuf))
+ { /* can't stat it */
+ TprintfT (DBG_LT0, "path_collectable(): WARNING: Can't stat `%s'\n", execfile);
+#if 0
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
+ COL_WARN_RISKYFOLLOW, "stat");
+#endif
+ return 1; /* follow, though exec will probably fail */
+ }
+ TprintfT (DBG_LT2, "path_collectable(%s) mode=0%o uid=%d gid=%d\n",
+ execfile, sbuf.st_mode, sbuf.st_uid, sbuf.st_gid);
+ if (((sbuf.st_mode & S_IXUSR) == 0) || ((sbuf.st_mode & S_IFMT) == S_IFDIR))
+ {
+ TprintfT (DBG_LT0, "path_collectable(): WARNING: Command `%s' is NOT an executable file!\n", execfile);
+#if 0
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
+ COL_WARN_RISKYFOLLOW, "mode");
+#endif
+ return 1; /* follow, though exec will presumably fail */
+ }
+ /* XXXX setxid(root) is OK iff libcollector is registered as secure */
+ /* XXXX setxid(non-root) is OK iff umask is accomodating */
+ if (((sbuf.st_mode & S_ISUID) != 0) || ((sbuf.st_mode & S_ISGID) != 0))
+ {
+ TprintfT (DBG_LT0, "path_collectable(): WARNING: Command `%s' is SetXID!\n", execfile);
+#if 0
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
+ COL_WARN_RISKYFOLLOW, "setxid");
+#endif
+ return 1; /* follow, though collection may be unreliable */
+ }
+ if (!check_dynamic (execfile))
+ {
+ TprintfT (DBG_LT0, "path_collectable(%s) WARNING/ERROR: not dynamic, not collectng!\n", execfile);
+ return 0; /* don't follow, collection will fail unpredictably */
+ }
+ TprintfT (DBG_LT2, "path_collectable(%s) OK!\n", execfile);
+ return 1; /* OK to follow */
+}
+
+static char *
+build_experiment_path (char * instring, size_t instring_sz, const char *lineage_str)
+{
+ TprintfT (DBG_LT0, "build_experiment_path(,%ld, %s)\n",
+ (long) instring_sz, lineage_str);
+ const char *p = CALL_UTIL (strstr)(linetrace_exp_dir_name, DESCENDANT_EXPT_KEY);
+ int basedir_sz;
+ if (p)
+ basedir_sz = p - linetrace_exp_dir_name + 4; /* +3 because of DESCENDANT_EXPT_KEY */
+ else
+ basedir_sz = __collector_strlen (linetrace_exp_dir_name) + 1;
+ int additional_sz = __collector_strlen (lineage_str) + 4;
+ if (basedir_sz + additional_sz > instring_sz)
+ {
+ TprintfT (DBG_LT0, "build_experiment_path(%s,%s): ERROR: path too long: %d > %ld\n",
+ linetrace_exp_dir_name, lineage_str,
+ basedir_sz + additional_sz, (long) instring_sz);
+ *instring = 0;
+ return NULL;
+ }
+ __collector_strlcpy (instring, linetrace_exp_dir_name, basedir_sz);
+ size_t slen = __collector_strlen (instring);
+ CALL_UTIL (snprintf)(instring + slen, instring_sz - slen, "/%s.er", lineage_str);
+ assert (__collector_strlen (instring) + 1 == basedir_sz + additional_sz);
+ return instring;
+}
+
+static void
+check_reuid_change (uid_t ruid, uid_t euid)
+{
+ uid_t curr_ruid = getuid ();
+ uid_t curr_euid = geteuid ();
+ mode_t curr_umask = umask (0);
+ umask (curr_umask); /* restore original umask */
+ int W_oth = !(curr_umask & S_IWOTH);
+ TprintfT (DBG_LT0, "check_reuid_change(%d,%d): umask=%03o\n", ruid, euid, curr_umask);
+ TprintfT (DBG_LT0, "check_reuid_change(): umask W usr=%d grp=%d oth=%d\n",
+ (int) (!(curr_umask & S_IWUSR)), (int) (!(curr_umask & S_IWGRP)), W_oth);
+ if (ruid != -1)
+ {
+ TprintfT (DBG_LT0, "check_reuid_change(%d->%d)\n", curr_ruid, ruid);
+ if ((curr_euid == 0) && (ruid != 0) && !W_oth)
+ {
+ /* changing to non-root ID, with umask blocking writes by other */
+ TprintfT (DBG_LT0, "check_reuid_change(): ERROR/WARNING: umask blocks write other after ruid change (%d->%d)\n",
+ curr_ruid, ruid);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o ruid %d->%d</event>\n",
+ SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_ruid, ruid);
+ }
+ }
+ if (euid != -1)
+ {
+ TprintfT (DBG_LT0, "check_reuid_change(%d->%d)\n", curr_euid, euid);
+ if ((curr_euid == 0) && (euid != 0) && !W_oth)
+ {
+ /* changing to non-root ID, with umask blocking writes by other */
+ TprintfT (DBG_LT0, "check_reuid_change(): ERROR/WARNING: umask blocks write other after euid change (%d->%d)\n",
+ curr_euid, euid);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o euid %d->%d</event>\n",
+ SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_euid, euid);
+ }
+ }
+}
+
+static void
+check_regid_change (gid_t rgid, gid_t egid)
+{
+ gid_t curr_rgid = getgid ();
+ gid_t curr_egid = getegid ();
+ uid_t curr_euid = geteuid ();
+ mode_t curr_umask = umask (0);
+ umask (curr_umask); /* restore original umask */
+ int W_oth = !(curr_umask & S_IWOTH);
+ TprintfT (DBG_LT0, "check_regid_change(%d,%d): umask=%03o euid=%d\n",
+ rgid, egid, curr_umask, curr_euid);
+ TprintfT (DBG_LT0, "umask W usr=%d grp=%d oth=%d\n",
+ (int) (!(curr_umask & S_IWUSR)), (int) (!(curr_umask & S_IWGRP)), W_oth);
+ if (rgid != -1)
+ {
+ TprintfT (DBG_LT0, "check_regid_change(%d->%d)\n", curr_rgid, rgid);
+ if ((curr_euid == 0) && (rgid != 0) && !W_oth)
+ {
+ /* changing to non-root ID, with umask blocking writes by other */
+ TprintfT (DBG_LT0, "check_regid_change(): WARNING/ERROR: umask blocks write other after rgid change (%d->%d)\n",
+ curr_rgid, rgid);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o rgid %d->%d</event>\n",
+ SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_rgid, rgid);
+ }
+ }
+ if (egid != -1)
+ {
+ TprintfT (DBG_LT0, "check_regid_change(): check_egid_change(%d->%d)\n", curr_egid, egid);
+ if ((curr_euid == 0) && (egid != 0) && !W_oth)
+ {
+ /* changing to non-root ID, with umask blocking writes by other */
+ TprintfT (DBG_LT0, "check_regid_change(): WARNING/ERROR: umask blocks write other after egid change (%d->%d)\n",
+ curr_egid, egid);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">umask %03o egid %d->%d</event>\n",
+ SP_JCMD_CWARN, COL_WARN_IDCHNG, curr_umask, curr_egid, egid);
+ }
+ }
+}
+
+static int
+init_lineage_intf ()
+{
+ void *dlflag;
+ TprintfT (DBG_LT2, "init_lineage_intf()\n");
+
+ static int nesting_check = 0;
+ if (nesting_check >= 2)
+ {
+ /* segv before stack blows up */
+ nesting_check /= (nesting_check - 2);
+ }
+ nesting_check++;
+
+ __real_fork = dlsym (RTLD_NEXT, "fork");
+ if (__real_fork == NULL)
+ {
+ __real_fork = dlsym (RTLD_DEFAULT, "fork");
+ if (__real_fork == NULL)
+ return 1;
+ dlflag = RTLD_DEFAULT;
+ }
+ else
+ dlflag = RTLD_NEXT;
+ TprintfT (DBG_LT2, "init_lineage_intf() using RTLD_%s\n",
+ dlflag == RTLD_DEFAULT ? "DEFAULT" : "NEXT");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_fork\n", __real_fork);
+ __real_vfork = dlsym (dlflag, "vfork");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_vfork\n", __real_vfork);
+ __real_execve = dlsym (dlflag, "execve");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execve\n", __real_execve);
+ __real_execvp = dlsym (dlflag, "execvp");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execvp\n", __real_execvp);
+ __real_execv = dlsym (dlflag, "execv");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execv\n", __real_execv);
+ __real_execle = dlsym (dlflag, "execle");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execle\n", __real_execle);
+ __real_execlp = dlsym (dlflag, "execlp");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execlp\n", __real_execlp);
+ __real_execl = dlsym (dlflag, "execl");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_execl\n", __real_execl);
+ __real_clone = dlsym (dlflag, "clone");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_clone\n", __real_clone);
+ __real_posix_spawn = dlsym (dlflag, "posix_spawn");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_posix_spawn\n",
+ __real_posix_spawn);
+ __real_posix_spawnp = dlsym (dlflag, "posix_spawnp");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_posix_spawnp\n",
+ __real_posix_spawnp);
+ __real_popen = dlvsym (dlflag, "popen", SYS_POPEN_VERSION);
+ TprintfT (DBG_LT2, "init_lineage_intf()[%s] @0x%p __real_popen\n",
+ SYS_POPEN_VERSION, __real_popen);
+#if ARCH(Intel)
+ __real_posix_spawn_2_15 = dlvsym (dlflag, "posix_spawn", SYS_POSIX_SPAWN_VERSION);
+ __real_posix_spawnp_2_15 = dlvsym (dlflag, "posix_spawnp", SYS_POSIX_SPAWN_VERSION);
+#if WSIZE(32)
+ __real_popen_2_1 = __real_popen;
+ __real_popen_2_0 = dlvsym (dlflag, "popen", "GLIBC_2.0");
+ __real_posix_spawn_2_2 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.2");
+ __real_posix_spawnp_2_2 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.2");
+#elif WSIZE(64)
+ __real_posix_spawn_2_2_5 = dlvsym (dlflag, "posix_spawn", "GLIBC_2.2.5");
+ __real_posix_spawnp_2_2_5 = dlvsym (dlflag, "posix_spawnp", "GLIBC_2.2.5");
+#endif /* WSIZE() */
+#endif /* ARCH(Intel) */
+ __real_grantpt = dlsym (dlflag, "grantpt");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_grantpt\n", __real_grantpt);
+ __real_ptsname = dlsym (dlflag, "ptsname");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_ptsname\n", __real_ptsname);
+ __real_system = dlsym (dlflag, "system");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_system\n", __real_system);
+ __real_setuid = dlsym (dlflag, "setuid");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setuid\n", __real_setuid);
+ __real_seteuid = dlsym (dlflag, "seteuid");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_seteuid\n", __real_seteuid);
+ __real_setreuid = dlsym (dlflag, "setreuid");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setreuid\n", __real_setreuid);
+ __real_setgid = dlsym (dlflag, "setgid");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setgid\n", __real_setgid);
+ __real_setegid = dlsym (dlflag, "setegid");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setegid\n", __real_setegid);
+ __real_setregid = dlsym (dlflag, "setregid");
+ TprintfT (DBG_LT2, "init_lineage_intf() @0x%p __real_setregid\n", __real_setregid);
+ return 0;
+}
+
+/*------------------------------------------------------------------------ */
+/* Note: The following _prologue and _epilogue functions used to be dbx-visible.
+
+ They are used to appropriately manage lineage-changing events, by
+ quiescing and re-enabling/re-setting experiment collection before and after,
+ and logging the lineage-change in the process/experiment undertaking it.
+ As shown by the interposition functions for fork, exec, etc., which follow,
+ the _prologue should be called immediately prior (such as a breakpoint
+ action defined at function entry) and the _epilogue called immediately
+ after (such as a breakpoint action defined at function return).
+ */
+
+/*
+ Notes on MT from Solaris 10 man pthread_atfork:
+
+ All multithreaded applications that call fork() in a POSIX
+ threads program and do more than simply call exec(2) in the
+ child of the fork need to ensure that the child is protected
+ from deadlock.
+
+ Since the "fork-one" model results in duplicating only the
+ thread that called fork(), it is possible that at the time
+ of the call another thread in the parent owns a lock. This
+ thread is not duplicated in the child, so no thread will
+ unlock this lock in the child. Deadlock occurs if the sin-
+ gle thread in the child needs this lock.
+
+ The problem is more serious with locks in libraries. Since
+ a library writer does not know if the application using the
+ library calls fork(), the library must protect itself from
+ such a deadlock scenario. If the application that links
+ with this library calls fork() and does not call exec() in
+ the child, and if it needs a library lock that may be held
+ by some other thread in the parent that is inside the
+ library at the time of the fork, the application deadlocks
+ inside the library.
+ */
+
+static void
+linetrace_ext_fork_prologue (const char *variant, char * n_lineage, int *following_fork)
+{
+ TprintfT (DBG_LT0, "linetrace_ext_fork_prologue; variant=%s; new_lineage=%s; follow=%d\n",
+ variant, n_lineage, *following_fork);
+ __collector_env_print ("fork_prologue start");
+ if (dbg_current_mode != FOLLOW_NONE)
+ TprintfT (DBG_LT0, "linetrace_ext_fork_prologue(%s) ERROR: dbg_current_mode=%d, changing to FOLLOW_FORK!\n",
+ variant, dbg_current_mode);
+ dbg_current_mode = FOLLOW_ON;
+ if (__collector_strncmp ((char *) variant, "clone", sizeof ("clone") - 1) == 0)
+ {
+ __collector_mutex_lock (&clone_lineage_lock);
+ CALL_UTIL (snprintf)(n_lineage, LT_MAXNAMELEN, "%s_C%d", curr_lineage, ++clone_linenum);
+ __collector_mutex_unlock (&clone_lineage_lock);
+ }
+ else
+ {
+ __collector_mutex_lock (&fork_lineage_lock);
+ CALL_UTIL (snprintf)(n_lineage, LT_MAXNAMELEN, "%s_f%d", curr_lineage, ++fork_linenum);
+ __collector_mutex_unlock (&fork_lineage_lock);
+ }
+ *following_fork = check_follow_fork ();
+
+ /* write message before suspending, or it won't be written */
+ hrtime_t ts = GETRELTIME ();
+ TprintfT (DBG_LT0, "linetrace_ext_fork_prologue; variant=%s; new_lineage=%s; follow=%d\n",
+ variant, n_lineage, *following_fork);
+ __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\"/>\n",
+ SP_JCMD_DESC_START,
+ (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
+ variant, n_lineage, *following_fork);
+ __collector_ext_dispatcher_thread_timer_suspend ();
+ __collector_ext_hwc_lwp_suspend ();
+ __collector_env_print ("fork_prologue end");
+}
+
+static void
+linetrace_ext_fork_epilogue (const char *variant, const pid_t ret, char * n_lineage, int *following_fork)
+{
+ if (dbg_current_mode == FOLLOW_NONE)
+ TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) ERROR: dbg_current_mode=%d!\n",
+ variant, dbg_current_mode);
+ /* compute descendant experiment name */
+ char new_exp_name[LT_MAXPATHLEN];
+ /* save exp_name to global var */
+ if (!build_experiment_path (new_exp_name, sizeof (new_exp_name), n_lineage))
+ TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s): ERROR SP_COLLECTOR_EXPNAME not set\n", n_lineage);
+ TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s):%d() returned %d %s; child experiment name = %s\n",
+ variant, *following_fork, ret, (ret ? "parent" : "child"), new_exp_name);
+ if (ret == 0)
+ {
+ /* *************************************child */
+ __collector_env_print ("fork_epilogue child at start");
+ /* start a new line */
+ fork_linenum = 0;
+ __collector_mutex_init (&fork_lineage_lock);
+ clone_linenum = 0;
+ __collector_mutex_init (&clone_lineage_lock);
+ __collector_env_update (NULL);
+ __collector_env_print ("fork_epilogue child after env_update");
+ __collector_clean_state ();
+ __collector_env_print ("fork_epilogue child after clean_slate");
+ __collector_line_cleanup ();
+ __collector_env_print ("fork_epilogue child after line_cleanup");
+ if (*following_fork)
+ {
+ /* stop recording this experiment, but preserve env vars */
+ linetrace_dormant ();
+ __collector_env_print ("fork_epilogue child after linetrace_dormant");
+
+ //static char exp_name_env[LT_MAXPATHLEN];
+ char * exp_name_env = CALL_UTIL (calloc)(LT_MAXPATHLEN, 1);
+ CALL_UTIL (snprintf)(exp_name_env, LT_MAXPATHLEN, "%s=%s", SP_COLLECTOR_EXPNAME, new_exp_name);
+ CALL_UTIL (putenv)(exp_name_env);
+
+ const char *params = CALL_UTIL (getenv)(SP_COLLECTOR_PARAMS);
+ int ret;
+ if (new_exp_name == NULL)
+ TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: getenv(%s) undefined -- new expt aborted!\n",
+ SP_COLLECTOR_EXPNAME);
+ else if (params == NULL)
+ TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: getenv(%s) undefined -- new expt aborted!\n",
+ SP_COLLECTOR_PARAMS);
+ else if ((ret = __collector_open_experiment (new_exp_name, params, SP_ORIGIN_FORK)))
+ TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: ERROR: '%s' open failed, ret=%d\n",
+ new_exp_name, ret);
+ else
+ TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue: opened(%s)\n", new_exp_name);
+ TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) returning to *child*\n", variant);
+ }
+ else
+ {
+ /* disable current and further linetrace experiment resumption */
+ TprintfT (DBG_LT0, "linetrace_ext_fork_epilogue(%s) child calling line_close\n", variant);
+ __collector_ext_line_close ();
+ }
+ __collector_env_print ("fork_epilogue child at end");
+ /* *************************************end child */
+ }
+ else
+ {
+ /* *************************************parent */
+ __collector_env_print ("fork_epilogue parent at start");
+ __collector_ext_dispatcher_thread_timer_resume ();
+ __collector_ext_hwc_lwp_resume ();
+ hrtime_t ts = GETRELTIME ();
+ char msg[256 + LT_MAXPATHLEN];
+ if (ret >= 0)
+ CALL_UTIL (snprintf)(msg, sizeof (msg), "pid=%d", ret);
+ else
+ {
+ /* delete stillborn experiment? */
+ char errmsg[256];
+ strerror_r (errno, errmsg, sizeof (errmsg));
+ CALL_UTIL (snprintf)(msg, sizeof (msg), "err %s", errmsg);
+ }
+ __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
+ SP_JCMD_DESC_STARTED,
+ (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
+ variant, n_lineage, *following_fork, msg);
+ /* environment remains set for collection */
+ __collector_env_print ("fork_epilogue parent at end");
+ /* *************************************end parent */
+ }
+ dbg_current_mode = FOLLOW_NONE;
+ *following_fork = 0;
+}
+
+static char**
+linetrace_ext_exec_prologue_end (const char *variant, const char* cmd_string,
+ char *const envp[], int following_exec)
+{
+ char **coll_env;
+ TprintfT (DBG_LT0, "linetrace_ext_exec_prologue_end; variant=%s; cmd_string=%s; follow=%d\n",
+ variant, cmd_string, following_exec);
+ /* write message before suspending, or it won't be written */
+ hrtime_t ts = GETRELTIME ();
+ __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
+ SP_JCMD_EXEC_START,
+ (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
+ variant, new_lineage, following_exec, cmd_string);
+ if (following_exec)
+ {
+ coll_env = __collector_env_allocate (envp, 0);
+ __collector_env_update (coll_env);
+ extern char **environ; /* the process' actual environment */
+ if (environ == envp) /* user selected process environment */
+ environ = coll_env;
+ }
+ else
+ coll_env = (char**) envp;
+ __collector_env_printall ("linetrace_ext_exec_prologue_end", coll_env);
+ if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
+ {
+ __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
+ __collector_suspend_experiment ("suspend_for_exec");
+ __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
+ }
+ if (CALL_UTIL (strstr)(variant, "posix_spawn"))
+ {
+ __collector_ext_dispatcher_thread_timer_suspend ();
+ __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
+ __collector_ext_hwc_lwp_suspend ();
+ __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
+ }
+ return (coll_env);
+}
+
+static char**
+linetrace_ext_exec_prologue (const char *variant,
+ const char* path, char *const argv[],
+ char *const envp[], int *following_exec)
+{
+ char cmd_string[_POSIX_ARG_MAX] = {'\0'};
+
+ if (dbg_current_mode != FOLLOW_NONE)
+ TprintfT (DBG_LT0, "linetrace_ext_exec_prologue() ERROR: dbg_current_mode=%d, changing to FOLLOW_EXEC!\n", dbg_current_mode);
+ dbg_current_mode = FOLLOW_ON;
+ *following_exec = check_follow_exec (path);
+ if (path != NULL)
+ {
+ /* escape any newline, " or \ characters in the exec command */
+ TprintfT (DBG_LT3, "linetrace_ext_exec_prologue(): arg0=%s\n", path);
+ /* leave space in log message for terminator (and header) */
+ __collector_strlcpy (cmd_string, path, sizeof (cmd_string));
+ size_t len;
+ unsigned argn = 0;
+ if (argv[0])
+ {
+ char *p;
+ while (((p = argv[++argn]) != 0) &&
+ (len = __collector_strlen (cmd_string)) < sizeof (cmd_string) - 2)
+ {
+ cmd_string[len++] = ' ';
+ __collector_strlcpy (cmd_string + len, p, sizeof (cmd_string) - len);
+ }
+ }
+ }
+ TprintfT (DBG_LT0, "linetrace_ext_exec_prologue(%s), lineage=%s, follow=%d, prog=%s, path=%s \n",
+ variant, new_lineage, *following_exec, cmd_string, path);
+ return linetrace_ext_exec_prologue_end (variant, cmd_string, envp, *following_exec);
+}
+
+static void
+linetrace_ext_exec_epilogue (const char *variant, char *const envp[], const int ret, int *following_exec)
+{
+ /* For exec, this routine is only entered if the exec failed */
+ /* However, posix_spawn() is expected to return */
+ if (dbg_current_mode == FOLLOW_NONE)
+ TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue() ERROR: dbg_current_mode=%d!\n", dbg_current_mode);
+ TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue(%s):%d returned: %d, errno=%d\n",
+ variant, *following_exec, ret, errno);
+ if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
+ {
+ __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
+ __collector_resume_experiment ();
+ __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
+ }
+ if (CALL_UTIL (strstr)(variant, "posix_spawn"))
+ {
+ __collector_ext_dispatcher_thread_timer_resume ();
+ __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
+ __collector_ext_hwc_lwp_resume ();
+ __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
+ }
+ hrtime_t ts = GETRELTIME ();
+ char msg[256];
+ if (ret)
+ {
+ char errmsg[256];
+ strerror_r (errno, errmsg, sizeof (errmsg));
+ CALL_UTIL (snprintf)(msg, sizeof (msg), "err %s", errmsg);
+ }
+ else
+ CALL_UTIL (snprintf)(msg, sizeof (msg), "rc=%d", ret);
+ if (!CALL_UTIL (strstr)(variant, "posix_spawn"))
+ __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
+ SP_JCMD_EXEC_ERROR,
+ (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
+ variant, new_lineage, *following_exec, msg);
+ if (envp == NULL)
+ TprintfT (DBG_LT0, "linetrace_ext_exec_epilogue() ERROR: envp NULL after %s!\n", variant);
+ dbg_current_mode = FOLLOW_NONE;
+ *following_exec = 0;
+}
+
+static void
+linetrace_ext_combo_prologue (const char *variant, const char *cmd, int *following_combo)
+{
+ char cmd_string[_POSIX_ARG_MAX] = {'\0'};
+ char execfile[_POSIX_ARG_MAX] = {'\0'};
+
+ if (dbg_current_mode != FOLLOW_NONE)
+ TprintfT (DBG_LT0, "linetrace_ext_combo_prologue() ERROR: dbg_current_mode=%d! changing to FOLLOW_ON\n",
+ dbg_current_mode);
+ dbg_current_mode = FOLLOW_ON;
+ if (cmd != NULL)
+ {
+ /* extract executable name from combo command */
+ unsigned len = strcspn (cmd, " ");
+ __collector_strlcpy (execfile, cmd, len + 1);
+
+ /* escape any newline, " or \ characters in the combo command */
+ /* leave space in log message for terminator (and header) */
+ __collector_strlcpy (cmd_string, cmd, sizeof (cmd_string));
+ }
+
+ *following_combo = check_follow_combo (execfile);
+ TprintfT (DBG_LT0, "linetrace_ext_combo_prologue(%s) follow=%d, prog=%s\n\n",
+ variant, *following_combo, cmd_string);
+
+ /* Construct the lineage string for the new image */
+ new_lineage[0] = 0;
+ __collector_strcat (new_lineage, "XXX");
+
+ /* write message before suspending, or it won't be written */
+ hrtime_t ts = GETRELTIME ();
+ __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" lineage=\"%s\" follow=\"%d\" msg=\"%s\"/>\n",
+ SP_JCMD_DESC_START,
+ (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
+ variant, new_lineage, *following_combo, cmd_string);
+ if (*following_combo)
+ {
+ __collector_env_update (NULL);
+ TprintfT (DBG_LT0, "linetrace_ext_combo_prologue(): Following %s(\"%s\")\n", variant, execfile);
+ }
+ __collector_ext_dispatcher_thread_timer_suspend ();
+ __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
+ __collector_ext_hwc_lwp_suspend ();
+ __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
+}
+
+static void
+linetrace_ext_combo_epilogue (const char *variant, const int ret, int *following_combo)
+{
+ if (dbg_current_mode == FOLLOW_NONE)
+ TprintfT (DBG_LT0, "linetrace_ext_combo_epilogue() ERROR: dbg_current_mode=FOLLOW_NONE\n");
+ TprintfT (DBG_LT0, "linetrace_ext_combo_epilogue(%s):%d() returned %d\n",
+ variant, *following_combo, ret);
+ __collector_ext_dispatcher_thread_timer_resume ();
+ __collector_linetrace_shutdown_hwcs_6830763_XXXX = 1;
+ __collector_ext_hwc_lwp_resume ();
+ __collector_linetrace_shutdown_hwcs_6830763_XXXX = 0;
+ hrtime_t ts = GETRELTIME ();
+ __collector_log_write ("<event kind=\"%s\" tstamp=\"%u.%09u\" variant=\"%s\" follow=\"%d\" msg=\"rc=%d\"/>\n",
+ SP_JCMD_DESC_STARTED,
+ (unsigned) (ts / NANOSEC), (unsigned) (ts % NANOSEC),
+ variant, *following_combo, ret);
+
+ dbg_current_mode = FOLLOW_NONE;
+ *following_combo = 0;
+}
+
+/*------------------------------------------------------------- fork */
+pid_t fork () __attribute__ ((weak, alias ("__collector_fork")));
+pid_t _fork () __attribute__ ((weak, alias ("__collector_fork")));
+
+pid_t
+__collector_fork (void)
+{
+ pid_t ret;
+ if (NULL_PTR (fork))
+ {
+ TprintfT (DBG_LT0, "__collector_fork() calling init_lineage_intf()\n");
+ init_lineage_intf ();
+ }
+ __collector_env_print ("__collector_fork start");
+ int * guard = NULL;
+ int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
+ TprintfT (DBG_LT0, "__collector_fork() interposition: line_mode=%d combo=%d\n",
+ line_mode, combo_flag);
+ if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
+ {
+ TprintfT (DBG_LT0, "__collector_fork() not following, returning CALL_REAL(fork)()\n");
+ return CALL_REAL (fork)();
+ }
+ int following_fork = 0;
+ linetrace_ext_fork_prologue ("fork", new_lineage, &following_fork);
+
+ /* since libpthread/fork ends up calling fork1, it's a combo */
+ PUSH_REENTRANCE (guard);
+ ret = CALL_REAL (fork)();
+ POP_REENTRANCE (guard);
+ linetrace_ext_fork_epilogue ("fork", ret, new_lineage, &following_fork);
+ return ret;
+}
+
+/*------------------------------------------------------------- vfork */
+/* vfork interposition in the usual sense is not possible, since vfork(2)
+ relies on specifics of the stack frames in the parent and child which
+ only work when the child's exec (or _exit) are in the same stack frame
+ as the vfork: this isn't the case when there's interposition on exec.
+ As a workaround, the interposing vfork calls fork1 instead of the real
+ vfork. Note that fork1 is somewhat less efficient than vfork, and requires
+ additional memory, which may result in a change of application behaviour
+ when libcollector is loaded (even when collection is not active),
+ affecting not only direct use of vfork by the subject application,
+ but also indirect use through system, popen, and the other combos.
+ */
+pid_t vfork () __attribute__ ((weak, alias ("__collector_vfork")));
+pid_t _vfork () __attribute__ ((weak, alias ("__collector_vfork")));
+
+pid_t
+__collector_vfork (void)
+{
+ if (NULL_PTR (vfork))
+ init_lineage_intf ();
+
+ int * guard = NULL;
+ int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
+
+ TprintfT (DBG_LT0, "__collector_vfork() interposing: line_mode=%d combo=%d\n",
+ line_mode, combo_flag);
+ if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
+ return CALL_REAL (fork)();
+
+ /* this warning is also appropriate for combos which use vfork,
+ however, let's assume this is achieved elsewhere */
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\">%s</event>\n", SP_JCMD_CWARN,
+ COL_WARN_VFORK, "fork");
+
+ char new_lineage[LT_MAXNAMELEN];
+ new_lineage[0] = 0;
+ int following_fork = 0;
+ linetrace_ext_fork_prologue ("vfork", new_lineage, &following_fork);
+
+ pid_t ret = CALL_REAL (fork)();
+ linetrace_ext_fork_epilogue ("vfork", ret, new_lineage, &following_fork);
+ return ret;
+}
+
+/*------------------------------------------------------------- execve */
+int execve () __attribute__ ((weak, alias ("__collector_execve")));
+
+int
+__collector_execve (const char* path, char *const argv[], char *const envp[])
+{
+ static char **coll_env = NULL; /* environment for collection */
+ if (NULL_PTR (execve))
+ init_lineage_intf ();
+ int * guard = NULL;
+ int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
+ TprintfT (DBG_LT0,
+ "__collector_execve(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n",
+ path ? path : "NULL",
+ argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
+ envp ? (envp[0] ? envp[0] : "NULL") : "NULL",
+ line_mode, combo_flag);
+ if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
+ __collector_env_unset ((char**) envp);
+ if (line_mode != LM_TRACK_LINEAGE || combo_flag)
+ return CALL_REAL (execve)(path, argv, envp);
+
+ int following_exec = 0;
+ coll_env = linetrace_ext_exec_prologue ("execve", path, argv, envp, &following_exec);
+ TprintfT (DBG_LT2, "__collector_execve(): coll_env=0x%p\n", coll_env);
+ __collector_env_printall ("__collector_execve", coll_env);
+ int ret = CALL_REAL (execve)(path, argv, coll_env);
+ linetrace_ext_exec_epilogue ("execve", envp, ret, &following_exec);
+ return ret;
+}
+
+int execvp () __attribute__ ((weak, alias ("__collector_execvp")));
+
+int
+__collector_execvp (const char* file, char *const argv[])
+{
+ extern char **environ; /* the process' actual environment */
+ char ** envp = environ;
+ if (NULL_PTR (execvp))
+ init_lineage_intf ();
+ int * guard = NULL;
+ int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
+ TprintfT (DBG_LT0,
+ "__collector_execvp(file=%s, argv[0]=%s) interposing: line_mode=%d combo=%d\n",
+ file ? file : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
+ line_mode, combo_flag);
+ if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
+ __collector_env_unset ((char**) envp);
+ if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
+ return CALL_REAL (execvp)(file, argv);
+
+ int following_exec = 0;
+#ifdef DEBUG
+ char **coll_env = /* environment for collection */
+#endif /* DEBUG */
+ linetrace_ext_exec_prologue ("execvp", file, argv, envp, &following_exec);
+ TprintfT (DBG_LT0, "__collector_execvp(): coll_env=0x%p\n", coll_env);
+
+ int ret = CALL_REAL (execvp)(file, argv);
+ linetrace_ext_exec_epilogue ("execvp", envp, ret, &following_exec);
+ return ret;
+}
+
+int execv () __attribute__ ((weak, alias ("__collector_execv")));
+
+int
+__collector_execv (const char* path, char *const argv[])
+{
+ int ret;
+ extern char **environ; /* the process' actual environment */
+ char ** envp = environ;
+ TprintfT (DBG_LT0, "__collector_execv(path=%s, argv[0]=%s) interposing: line_mode=%d combo=%d\n",
+ path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
+ line_mode, get_combo_flag ());
+
+ ret = __collector_execve (path, argv, envp);
+ return ret;
+}
+
+int execle (const char* path, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execle")));
+
+int
+__collector_execle (const char* path, const char *arg0, ...)
+{
+ TprintfT (DBG_LT0,
+ "__collector_execle(path=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
+ path ? path : "NULL", arg0 ? arg0 : "NULL",
+ line_mode, get_combo_flag ());
+
+ char **argp;
+ va_list args;
+ char **argvec;
+ register char **environmentp;
+ int nargs = 0;
+ char *nextarg;
+
+ va_start (args, arg0);
+ while (va_arg (args, char *) != (char *) 0)
+ nargs++;
+
+ /*
+ * save the environment pointer, which is at the end of the
+ * variable argument list
+ */
+ environmentp = va_arg (args, char **);
+ va_end (args);
+
+ /*
+ * load the arguments in the variable argument list
+ * into the argument vector, and add the terminating null pointer
+ */
+ va_start (args, arg0);
+ /* workaround for bugid 1242839 */
+ argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
+ argp = argvec;
+ *argp++ = (char *) arg0;
+ while ((nextarg = va_arg (args, char *)) != (char *) 0)
+ *argp++ = nextarg;
+ va_end (args);
+ *argp = (char *) 0;
+ return __collector_execve (path, argvec, environmentp);
+}
+
+int execlp (const char* file, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execlp")));
+
+int
+__collector_execlp (const char* file, const char *arg0, ...)
+{
+ TprintfT (DBG_LT0,
+ "__collector_execlp(file=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
+ file ? file : "NULL", arg0 ? arg0 : "NULL",
+ line_mode, get_combo_flag ());
+ char **argp;
+ va_list args;
+ char **argvec;
+ int nargs = 0;
+ char *nextarg;
+
+ va_start (args, arg0);
+ while (va_arg (args, char *) != (char *) 0)
+ nargs++;
+ va_end (args);
+
+ /*
+ * load the arguments in the variable argument list
+ * into the argument vector and add the terminating null pointer
+ */
+ va_start (args, arg0);
+
+ /* workaround for bugid 1242839 */
+ argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
+ argp = argvec;
+ *argp++ = (char *) arg0;
+ while ((nextarg = va_arg (args, char *)) != (char *) 0)
+ *argp++ = nextarg;
+ va_end (args);
+ *argp = (char *) 0;
+ return __collector_execvp (file, argvec);
+}
+
+int execl (const char* path, const char *arg0, ...) __attribute__ ((weak, alias ("__collector_execl")));
+
+int
+__collector_execl (const char* path, const char *arg0, ...)
+{
+ TprintfT (DBG_LT0,
+ "__collector_execl(path=%s, arg0=%s) interposing: line_mode=%d combo=%d\n",
+ path ? path : "NULL", arg0 ? arg0 : "NULL",
+ line_mode, get_combo_flag ());
+ char **argp;
+ va_list args;
+ char **argvec;
+ extern char **environ;
+ int nargs = 0;
+ char *nextarg;
+ va_start (args, arg0);
+ while (va_arg (args, char *) != (char *) 0)
+ nargs++;
+ va_end (args);
+
+ /*
+ * load the arguments in the variable argument list
+ * into the argument vector and add the terminating null pointer
+ */
+ va_start (args, arg0);
+
+ /* workaround for bugid 1242839 */
+ argvec = (char **) alloca ((size_t) ((nargs + 2) * sizeof (char *)));
+ argp = argvec;
+ *argp++ = (char *) arg0;
+ while ((nextarg = va_arg (args, char *)) != (char *) 0)
+ *argp++ = nextarg;
+ va_end (args);
+ *argp = (char *) 0;
+ return __collector_execve (path, argvec, environ);
+}
+
+#include <spawn.h>
+
+/*-------------------------------------------------------- posix_spawn */
+#if ARCH(Intel)
+// map interposed symbol versions
+static int
+__collector_posix_spawn_symver (int(real_posix_spawn) (),
+ pid_t *pidp, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp,
+ char *const argv[], char *const envp[]);
+
+int
+__collector_posix_spawn_2_15 (pid_t *pidp, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp,
+ char *const argv[], char *const envp[])
+{
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawn_2_15@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
+ CALL_REAL (posix_spawn_2_15), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
+ if (NULL_PTR (posix_spawn))
+ init_lineage_intf ();
+ return __collector_posix_spawn_symver (CALL_REAL (posix_spawn_2_15), pidp,
+ path, file_actions, attrp, argv, envp);
+}
+
+__asm__(".symver __collector_posix_spawn_2_15,posix_spawn@@GLIBC_2.15");
+
+#if WSIZE(32)
+int
+__collector_posix_spawn_2_2 (pid_t *pidp, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp,
+ char *const argv[], char *const envp[])
+{
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawn_2_2@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
+ CALL_REAL (posix_spawn_2_2), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
+ if (NULL_PTR (posix_spawn))
+ init_lineage_intf ();
+ return __collector_posix_spawn_symver (CALL_REAL (posix_spawn_2_2), pidp,
+ path, file_actions, attrp, argv, envp);
+}
+
+__asm__(".symver __collector_posix_spawn_2_2,posix_spawn@GLIBC_2.2");
+
+#else /* ^WSIZE(32) */
+int
+__collector_posix_spawn_2_2_5 (pid_t *pidp, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp,
+ char *const argv[], char *const envp[])
+{
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawn_2_2_5@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
+ CALL_REAL (posix_spawn_2_2_5), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
+ if (NULL_PTR (posix_spawn))
+ init_lineage_intf ();
+ return __collector_posix_spawn_symver (CALL_REAL (posix_spawn_2_2_5), pidp,
+ path, file_actions, attrp, argv, envp);
+}
+
+__asm__(".symver __collector_posix_spawn_2_2_5,posix_spawn@GLIBC_2.2.5");
+#endif /* ^WSIZE(32) */
+
+static int
+__collector_posix_spawn_symver (int(real_posix_spawn) (),
+#else /* ^ARCH(Intel) */
+int
+__collector_posix_spawn (
+#endif /* ARCH() */
+ pid_t *pidp, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp,
+ char *const argv[], char *const envp[])
+{
+ int ret;
+ static char **coll_env = NULL; /* environment for collection */
+ if (NULL_PTR (posix_spawn))
+ init_lineage_intf ();
+ if (NULL_PTR (posix_spawn))
+ {
+ TprintfT (DBG_LT0, "__collector_posix_spawn(path=%s) interposing: ERROR, posix_spawn() not found by dlsym\n",
+ path ? path : "NULL");
+ return -1; /* probably should set errno */
+ }
+ int * guard = NULL;
+ int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
+ TprintfT (DBG_LT0, "__collector_posix_spawn(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n",
+ path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL", line_mode, combo_flag);
+ if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
+ __collector_env_unset ((char**) envp);
+
+ if ((line_mode != LM_TRACK_LINEAGE) || combo_flag)
+ {
+#if ARCH(Intel)
+ return (real_posix_spawn) (pidp, path, file_actions, attrp, argv, envp);
+#else
+ return CALL_REAL (posix_spawn)(pidp, path, file_actions, attrp, argv, envp);
+#endif
+ }
+ int following_exec = 0;
+ coll_env = linetrace_ext_exec_prologue ("posix_spawn", path, argv, envp, &following_exec);
+ TprintfT (DBG_LT0, "__collector_posix_spawn(): coll_env=0x%p\n", coll_env);
+ __collector_env_printall ("__collector_posix_spawn", coll_env);
+ PUSH_REENTRANCE (guard);
+#if ARCH(Intel)
+ ret = (real_posix_spawn) (pidp, path, file_actions, attrp, argv, coll_env);
+#else
+ ret = CALL_REAL (posix_spawn)(pidp, path, file_actions, attrp, argv, coll_env);
+#endif
+ POP_REENTRANCE (guard);
+ linetrace_ext_exec_epilogue ("posix_spawn", envp, ret, &following_exec);
+ return ret;
+}
+
+/*-------------------------------------------------------- posix_spawnp */
+#if ARCH(Intel)
+// map interposed symbol versions
+
+static int
+__collector_posix_spawnp_symver (int(real_posix_spawnp) (), pid_t *pidp,
+ const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp,
+ char *const argv[], char *const envp[]);
+
+int // Common interposition
+__collector_posix_spawnp_2_15 (pid_t *pidp, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp,
+ char *const argv[], char *const envp[])
+{
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawnp_2_15@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
+ CALL_REAL (posix_spawnp_2_15), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
+ if (NULL_PTR (posix_spawnp))
+ init_lineage_intf ();
+ return __collector_posix_spawnp_symver (CALL_REAL (posix_spawnp_2_15), pidp,
+ path, file_actions, attrp, argv, envp);
+}
+
+__asm__(".symver __collector_posix_spawnp_2_15,posix_spawnp@@GLIBC_2.15");
+
+#if WSIZE(32)
+
+int
+__collector_posix_spawnp_2_2 (pid_t *pidp, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp,
+ char *const argv[], char *const envp[])
+{
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawnp_2_2@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
+ CALL_REAL (posix_spawnp_2_2), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
+ if (NULL_PTR (posix_spawnp))
+ init_lineage_intf ();
+ return __collector_posix_spawnp_symver (CALL_REAL (posix_spawnp_2_2), pidp,
+ path, file_actions, attrp, argv, envp);
+}
+
+__asm__(".symver __collector_posix_spawnp_2_2,posix_spawnp@GLIBC_2.2");
+
+#else /* ^WSIZE(32) */
+int
+__collector_posix_spawnp_2_2_5 (pid_t *pidp, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp,
+ char *const argv[], char *const envp[])
+{
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_posix_spawnp_2_2_5@%p(path=%s, argv[0]=%s, env[0]=%s)\n",
+ CALL_REAL (posix_spawnp_2_2_5), path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL", envp ? (envp[0] ? envp[0] : "NULL") : "NULL");
+ if (NULL_PTR (posix_spawnp))
+ init_lineage_intf ();
+ return __collector_posix_spawnp_symver (CALL_REAL (posix_spawnp_2_2_5), pidp,
+ path, file_actions, attrp, argv, envp);
+}
+
+__asm__(".symver __collector_posix_spawnp_2_2_5,posix_spawnp@GLIBC_2.2.5");
+
+#endif /* ^WSIZE(32) */
+
+static int
+__collector_posix_spawnp_symver (int(real_posix_spawnp) (),
+#else /* ^ARCH(Intel) */
+int
+__collector_posix_spawnp (
+#endif /* ARCH() */
+ pid_t *pidp, const char *path,
+ const posix_spawn_file_actions_t *file_actions,
+ const posix_spawnattr_t *attrp,
+ char *const argv[], char *const envp[]){
+ int ret;
+ static char **coll_env = NULL; /* environment for collection */
+ if (NULL_PTR (posix_spawnp))
+ init_lineage_intf ();
+ if (NULL_PTR (posix_spawnp))
+ {
+ TprintfT (DBG_LT0, "__collector_posix_spawnp(path=%s) interposing: ERROR, posix_spawnp() not found by dlsym\n",
+ path ? path : "NULL");
+ return -1; /* probably should set errno */
+ }
+ int * guard = NULL;
+ int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
+ TprintfT (DBG_LT0, "__collector_posix_spawnp(path=%s, argv[0]=%s, env[0]=%s) interposing: line_mode=%d combo=%d\n",
+ path ? path : "NULL", argv ? (argv[0] ? argv[0] : "NULL") : "NULL",
+ envp ? (envp[0] ? envp[0] : "NULL") : "NULL", line_mode, combo_flag);
+
+ if (line_mode == LM_CLOSED) /* ensure collection environment is sanitised */
+ __collector_env_unset ((char**) envp);
+ if (line_mode != LM_TRACK_LINEAGE || combo_flag)
+ {
+#if ARCH(Intel)
+ return (real_posix_spawnp) (pidp, path, file_actions, attrp, argv, envp);
+#else
+ return CALL_REAL (posix_spawnp)(pidp, path, file_actions, attrp, argv, envp);
+#endif
+ }
+ int following_exec = 0;
+ coll_env = linetrace_ext_exec_prologue ("posix_spawnp", path, argv, envp, &following_exec);
+ TprintfT (DBG_LT0, "__collector_posix_spawnp(): coll_env=0x%p\n", coll_env);
+ __collector_env_printall ("__collector_posix_spawnp", coll_env);
+ PUSH_REENTRANCE (guard);
+#if ARCH(Intel)
+ ret = (real_posix_spawnp) (pidp, path, file_actions, attrp, argv, coll_env);
+#else
+ ret = CALL_REAL (posix_spawnp)(pidp, path, file_actions, attrp, argv, coll_env);
+#endif
+ POP_REENTRANCE (guard);
+ linetrace_ext_exec_epilogue ("posix_spawnp", envp, ret, &following_exec);
+ return ret;
+}
+
+/*------------------------------------------------------------- system */
+int system () __attribute__ ((weak, alias ("__collector_system")));
+
+int
+__collector_system (const char *cmd)
+{
+ if (NULL_PTR (system))
+ init_lineage_intf ();
+ TprintfT (DBG_LT0,
+ "__collector_system(cmd=%s) interposing: line_mode=%d combo=%d\n",
+ cmd ? cmd : "NULL", line_mode, get_combo_flag ());
+ int *guard = NULL;
+ if (line_mode == LM_TRACK_LINEAGE)
+ INIT_REENTRANCE (guard);
+ if (guard == NULL)
+ return CALL_REAL (system)(cmd);
+ int following_combo = 0;
+ linetrace_ext_combo_prologue ("system", cmd, &following_combo);
+ PUSH_REENTRANCE (guard);
+ int ret = CALL_REAL (system)(cmd);
+ POP_REENTRANCE (guard);
+ linetrace_ext_combo_epilogue ("system", ret, &following_combo);
+ return ret;
+}
+
+/*------------------------------------------------------------- popen */
+// map interposed symbol versions
+#if ARCH(Intel) && WSIZE(32)
+static FILE *
+__collector_popen_symver (FILE*(real_popen) (), const char *cmd, const char *mode);
+
+FILE *
+__collector_popen_2_1 (const char *cmd, const char *mode)
+{
+ if (NULL_PTR (popen))
+ init_lineage_intf ();
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_popen_2_1@%p\n", CALL_REAL (popen_2_1));
+ return __collector_popen_symver (CALL_REALF (popen_2_1), cmd, mode);
+}
+
+FILE *
+__collector_popen_2_0 (const char *cmd, const char *mode)
+{
+ if (NULL_PTR (popen))
+ init_lineage_intf ();
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_popen_2_0@%p\n", CALL_REAL (popen_2_0));
+ return __collector_popen_symver (CALL_REALF (popen_2_0), cmd, mode);
+}
+
+FILE *
+__collector__popen_2_1 (const char *cmd, const char *mode)
+{
+ if (NULL_PTR (popen))
+ init_lineage_intf ();
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector__popen_2_1@%p\n", CALL_REAL (popen_2_1));
+ return __collector_popen_symver (CALL_REALF (popen_2_1), cmd, mode);
+}
+
+FILE *
+__collector__popen_2_0 (const char *cmd, const char *mode)
+{
+ if (NULL_PTR (popen))
+ init_lineage_intf ();
+ return __collector_popen_symver (CALL_REALF (popen_2_0), cmd, mode);
+}
+
+__asm__(".symver __collector_popen_2_1,popen@@GLIBC_2.1");
+__asm__(".symver __collector_popen_2_0,popen@GLIBC_2.0");
+__asm__(".symver __collector__popen_2_1,_popen@@GLIBC_2.1");
+__asm__(".symver __collector__popen_2_0,_popen@GLIBC_2.0");
+#else // WSIZE(64)
+FILE * popen () __attribute__ ((weak, alias ("__collector_popen")));
+#endif
+
+#if ARCH(Intel) && WSIZE(32)
+static FILE *
+__collector_popen_symver (FILE*(real_popen) (), const char *cmd, const char *mode)
+#else
+
+FILE *
+__collector_popen (const char *cmd, const char *mode)
+#endif
+{
+ FILE *ret;
+ if (NULL_PTR (popen))
+ init_lineage_intf ();
+ TprintfT (DBG_LT0,
+ "__collector_popen(cmd=%s) interposing: line_mode=%d combo=%d\n",
+ cmd ? cmd : "NULL", line_mode, get_combo_flag ());
+ int *guard = NULL;
+ if (line_mode == LM_TRACK_LINEAGE)
+ INIT_REENTRANCE (guard);
+ if (guard == NULL)
+ {
+#if ARCH(Intel) && WSIZE(32)
+ return (real_popen) (cmd, mode);
+#else
+ return CALL_REALF (popen)(cmd, mode);
+#endif
+ }
+ int following_combo = 0;
+ linetrace_ext_combo_prologue ("popen", cmd, &following_combo);
+ PUSH_REENTRANCE (guard);
+#if ARCH(Intel) && WSIZE(32)
+ ret = (real_popen) (cmd, mode);
+#else
+ ret = CALL_REALF (popen)(cmd, mode);
+#endif
+ POP_REENTRANCE (guard);
+ linetrace_ext_combo_epilogue ("popen", (ret == NULL) ? (-1) : 0, &following_combo);
+ return ret;
+}
+
+/*------------------------------------------------------------- grantpt */
+int grantpt () __attribute__ ((weak, alias ("__collector_grantpt")));
+
+int
+__collector_grantpt (const int fildes)
+{
+ if (NULL_PTR (grantpt))
+ init_lineage_intf ();
+ TprintfT (DBG_LT0,
+ "__collector_grantpt(%d) interposing: line_mode=%d combo=%d\n",
+ fildes, line_mode, get_combo_flag ());
+ int *guard = NULL;
+ if (line_mode == LM_TRACK_LINEAGE)
+ INIT_REENTRANCE (guard);
+ if (guard == NULL)
+ return CALL_REAL (grantpt)(fildes);
+ int following_combo = 0;
+ linetrace_ext_combo_prologue ("grantpt", "/usr/lib/pt_chmod", &following_combo);
+ PUSH_REENTRANCE (guard);
+ int ret = CALL_REAL (grantpt)(fildes);
+ POP_REENTRANCE (guard);
+ linetrace_ext_combo_epilogue ("grantpt", ret, &following_combo);
+ return ret;
+}
+
+/*------------------------------------------------------------- ptsname */
+char *ptsname () __attribute__ ((weak, alias ("__collector_ptsname")));
+
+char *
+__collector_ptsname (const int fildes)
+{
+ if (NULL_PTR (ptsname))
+ init_lineage_intf ();
+ TprintfT (DBG_LT0,
+ "__collector_ptsname(%d) interposing: line_mode=%d combo=%d\n",
+ fildes, line_mode, get_combo_flag ());
+ int *guard = NULL;
+ if (line_mode == LM_TRACK_LINEAGE)
+ INIT_REENTRANCE (guard);
+ if (guard == NULL)
+ return CALL_REALC (ptsname)(fildes);
+ int following_combo = 0;
+ linetrace_ext_combo_prologue ("ptsname", "/usr/lib/pt_chmod", &following_combo);
+ PUSH_REENTRANCE (guard);
+ char *ret = CALL_REALC (ptsname)(fildes);
+ POP_REENTRANCE (guard);
+ linetrace_ext_combo_epilogue ("ptsname", (ret == NULL) ? (-1) : 1, &following_combo);
+ return ret;
+}
+
+/*------------------------------------------------------------- clone */
+/* clone can be fork-like or pthread_create-like, depending on whether
+ * the flag CLONE_VM is set. If CLONE_VM is not set, then we interpose
+ * clone in the way similar to interposing fork; if CLONE_VM is set,
+ * then we interpose clone in the way similar to interposing pthread_create.
+ * One special case is not handled: when CLONE_VM is set but CLONE_THREAD
+ * is not, if the parent process exits earlier than the child process,
+ * experiment will close, losing data from child process.
+ */
+typedef struct __collector_clone_arg
+{
+ int (*fn)(void *);
+ void * arg;
+ char * new_lineage;
+ int following_fork;
+} __collector_clone_arg_t;
+
+static int
+__collector_clone_fn (void *fn_arg)
+{
+ int (*fn)(void *) = ((__collector_clone_arg_t*) fn_arg)->fn;
+ void * arg = ((__collector_clone_arg_t*) fn_arg)->arg;
+ char * new_lineage = ((__collector_clone_arg_t*) fn_arg)->new_lineage;
+ int following_fork = ((__collector_clone_arg_t*) fn_arg)->following_fork;
+ __collector_freeCSize (__collector_heap, fn_arg, sizeof (__collector_clone_arg_t));
+ linetrace_ext_fork_epilogue ("clone", 0, new_lineage, &following_fork);
+ return fn (arg);
+}
+
+int clone (int (*fn)(void *), void *, int, void *, ...) __attribute__ ((weak, alias ("__collector_clone")));
+
+int
+__collector_clone (int (*fn)(void *), void *child_stack, int flags, void *arg,
+ ... /* pid_t *ptid, struct user_desc *tls, pid_t *" ctid" */)
+{
+ int ret;
+ va_list va;
+ if (flags & CLONE_VM)
+ {
+ va_start (va, arg);
+ ret = __collector_ext_clone_pthread (fn, child_stack, flags, arg, va);
+ va_end (va);
+ }
+ else
+ {
+ if (NULL_PTR (clone))
+ init_lineage_intf ();
+ int *guard = NULL;
+ int combo_flag = (line_mode == LM_TRACK_LINEAGE) ? ((CHCK_REENTRANCE (guard)) ? 1 : 0) : 0;
+ TprintfT (DBG_LT0, "__collector_clone() interposition: line_mode=%d combo=%d\n",
+ line_mode, combo_flag);
+ char new_lineage[LT_MAXNAMELEN];
+ int following_fork = 0;
+ __collector_clone_arg_t *funcinfo = __collector_allocCSize (__collector_heap, sizeof (__collector_clone_arg_t), 1);
+ (*funcinfo).fn = fn;
+ (*funcinfo).arg = arg;
+ (*funcinfo).new_lineage = new_lineage;
+ (*funcinfo).following_fork = 0;
+ pid_t * ptid = NULL;
+ struct user_desc * tls = NULL;
+ pid_t * ctid = NULL;
+ int num_args = 0;
+ va_start (va, arg);
+ if (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID))
+ {
+ ptid = va_arg (va, pid_t *);
+ tls = va_arg (va, struct user_desc*);
+ ctid = va_arg (va, pid_t *);
+ num_args = 3;
+ }
+ else if (flags & CLONE_SETTLS)
+ {
+ ptid = va_arg (va, pid_t *);
+ tls = va_arg (va, struct user_desc*);
+ num_args = 2;
+ }
+ else if (flags & CLONE_PARENT_SETTID)
+ {
+ ptid = va_arg (va, pid_t *);
+ num_args = 1;
+ }
+ if ((line_mode != LM_TRACK_LINEAGE) || combo_flag || funcinfo == NULL)
+ {
+ switch (num_args)
+ {
+ case 3:
+ ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls, ctid);
+ break;
+ case 2:
+ ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid, tls);
+ break;
+ case 1:
+ ret = CALL_REAL (clone)(fn, child_stack, flags, arg, ptid);
+ break;
+ default:
+ ret = CALL_REAL (clone)(fn, child_stack, flags, arg);
+ break;
+ }
+
+ va_end (va);
+ return ret;
+ }
+ linetrace_ext_fork_prologue ("clone", new_lineage, &following_fork);
+ (*funcinfo).following_fork = following_fork;
+ switch (num_args)
+ {
+ case 3:
+ ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid, tls, ctid);
+ break;
+ case 2:
+ ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid, tls);
+ break;
+ case 1:
+ ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo, ptid);
+ break;
+ default:
+ ret = CALL_REAL (clone)(__collector_clone_fn, child_stack, flags, funcinfo);
+ break;
+ }
+ va_end (va);
+ if (ret < 0)
+ __collector_freeCSize (__collector_heap, funcinfo, sizeof (__collector_clone_arg_t));
+ TprintfT (DBG_LT0, "__collector_clone() interposing: pid=%d\n", ret);
+ linetrace_ext_fork_epilogue ("clone", ret, new_lineage, &following_fork);
+ }
+ return ret;
+}
+
+/*-------------------------------------------------------------------- setuid */
+int setuid () __attribute__ ((weak, alias ("__collector_setuid")));
+int _setuid () __attribute__ ((weak, alias ("__collector_setuid")));
+
+int
+__collector_setuid (uid_t ruid)
+{
+ if (NULL_PTR (setuid))
+ init_lineage_intf ();
+ TprintfT (DBG_LT0, "__collector_setuid(0x%x) interposing\n", ruid);
+ check_reuid_change (ruid, -1);
+ int ret = CALL_REAL (setuid)(ruid);
+ TprintfT (DBG_LT0, "__collector_setuid(0x%x) returning %d\n", ruid, ret);
+ return ret;
+}
+
+/*------------------------------------------------------------------- seteuid */
+int seteuid () __attribute__ ((weak, alias ("__collector_seteuid")));
+int _seteuid () __attribute__ ((weak, alias ("__collector_seteuid")));
+
+int
+__collector_seteuid (uid_t euid)
+{
+ if (NULL_PTR (seteuid))
+ init_lineage_intf ();
+ TprintfT (DBG_LT0, "__collector_seteuid(0x%x) interposing\n", euid);
+ check_reuid_change (-1, euid);
+ int ret = CALL_REAL (seteuid)(euid);
+ TprintfT (DBG_LT0, "__collector_seteuid(0x%x) returning %d\n", euid, ret);
+ return ret;
+}
+
+/*------------------------------------------------------------------ setreuid */
+int setreuid () __attribute__ ((weak, alias ("__collector_setreuid")));
+int _setreuid () __attribute__ ((weak, alias ("__collector_setreuid")));
+
+int
+__collector_setreuid (uid_t ruid, uid_t euid)
+{
+ if (NULL_PTR (setreuid))
+ init_lineage_intf ();
+ TprintfT (DBG_LT0, "__collector_setreuid(0x%x,0x%x) interposing\n", ruid, euid);
+ check_reuid_change (ruid, euid);
+ int ret = CALL_REAL (setreuid)(ruid, euid);
+ TprintfT (DBG_LT0, "__collector_setreuid(0x%x,0x%x) returning %d\n", ruid, euid, ret);
+ return ret;
+}
+
+/*-------------------------------------------------------------------- setgid */
+int setgid () __attribute__ ((weak, alias ("__collector_setgid")));
+int _setgid () __attribute__ ((weak, alias ("__collector_setgid")));
+
+int
+__collector_setgid (gid_t rgid)
+{
+ if (NULL_PTR (setgid))
+ init_lineage_intf ();
+ TprintfT (DBG_LT0, "__collector_setgid(0x%x) interposing\n", rgid);
+ check_regid_change (rgid, -1);
+ int ret = CALL_REAL (setgid)(rgid);
+ TprintfT (DBG_LT0, "__collector_setgid(0x%x) returning %d\n", rgid, ret);
+ return ret;
+}
+
+/*------------------------------------------------------------------- setegid */
+int setegid () __attribute__ ((weak, alias ("__collector_setegid")));
+int _setegid () __attribute__ ((weak, alias ("__collector_setegid")));
+
+int
+__collector_setegid (gid_t egid)
+{
+ if (NULL_PTR (setegid))
+ init_lineage_intf ();
+ TprintfT (DBG_LT0, "__collector_setegid(0x%x) interposing\n", egid);
+ check_regid_change (-1, egid);
+ int ret = CALL_REAL (setegid)(egid);
+ TprintfT (DBG_LT0, "__collector_setegid(0x%x) returning %d\n", egid, ret);
+ return ret;
+}
+
+/*------------------------------------------------------------------ setregid */
+int setregid () __attribute__ ((weak, alias ("__collector_setregid")));
+int _setregid () __attribute__ ((weak, alias ("__collector_setregid")));
+
+int
+__collector_setregid (gid_t rgid, gid_t egid)
+{
+ if (NULL_PTR (setregid))
+ init_lineage_intf ();
+ TprintfT (DBG_LT0, "__collector_setregid(0x%x,0x%x) interposing\n", rgid, egid);
+ check_regid_change (rgid, egid);
+ int ret = CALL_REAL (setregid)(rgid, egid);
+ TprintfT (DBG_LT0, "__collector_setregid(0x%x,0x%x) returning %d\n", rgid, egid, ret);
+ return ret;
+}
+
+/*------------------------------------------------------- selective following */
+
+static int
+linetrace_follow_experiment (const char *follow_spec, const char *lineage_str, const char *progname)
+{
+ regex_t regex_desc;
+ if (!follow_spec)
+ {
+ TprintfT (DBG_LT0, "linetrace_follow_experiment(): MATCHES NULL follow_spec\n");
+ return 1;
+ }
+ int ercode = regcomp (&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
index 0000000..84d6bbc
--- /dev/null
+++ b/gprofng/libcollector/mapfile.aarch64-Linux
@@ -0,0 +1,40 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+GLIBC_2.17 {
+ global:
+ posix_spawn;
+ posix_spawnp;
+ pthread_mutex_lock;
+ pthread_mutex_unlock;
+ pthread_join;
+ sem_wait;
+ pthread_create;
+ dlopen;
+ popen;
+ timer_create;
+ pthread_cond_wait;
+ pthread_cond_timedwait;
+ fopen;
+ fclose;
+ fdopen;
+ fgetpos;
+ fsetpos;
+};
diff --git a/gprofng/libcollector/mapfile.amd64-Linux b/gprofng/libcollector/mapfile.amd64-Linux
new file mode 100644
index 0000000..213061f
--- /dev/null
+++ b/gprofng/libcollector/mapfile.amd64-Linux
@@ -0,0 +1,79 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+GLIBC_2.2.5 {
+ global:
+ posix_spawn;
+ posix_spawnp;
+ pthread_mutex_lock;
+ pthread_mutex_unlock;
+ pthread_join;
+ sem_wait;
+ pthread_create;
+ dlopen;
+ popen;
+ timer_create;
+ pthread_cond_wait;
+ pthread_cond_timedwait;
+ fopen;
+ fclose;
+ fdopen;
+ fgetpos;
+ fsetpos;
+};
+
+GLIBC_2.3.2 {
+ global:
+ pthread_cond_wait;
+ pthread_cond_timedwait;
+};
+
+GLIBC_2.3.3 {
+ global:
+ timer_create;
+};
+
+GLIBC_2.15 {
+ global:
+ posix_spawn;
+ posix_spawnp;
+};
+
+GLIBC_2.17 {
+ global:
+ posix_spawn;
+ posix_spawnp;
+ pthread_mutex_lock;
+ pthread_mutex_unlock;
+ pthread_join;
+ sem_wait;
+ pthread_create;
+ dlopen;
+ popen;
+ timer_create;
+ pthread_cond_wait;
+ pthread_cond_timedwait;
+ fopen;
+ fclose;
+ fdopen;
+ fgetpos;
+ fsetpos;
+};
+
diff --git a/gprofng/libcollector/mapfile.intel-Linux b/gprofng/libcollector/mapfile.intel-Linux
new file mode 100644
index 0000000..97482d2
--- /dev/null
+++ b/gprofng/libcollector/mapfile.intel-Linux
@@ -0,0 +1,81 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+GLIBC_2.0 {
+ global:
+ pthread_mutex_lock;
+ pthread_mutex_unlock;
+ pthread_join;
+ pthread_create;
+ dlopen;
+ popen;
+ sem_wait;
+ pthread_cond_wait;
+ pthread_cond_timedwait;
+ fopen;
+ fclose;
+ fdopen;
+ fgetpos;
+ fsetpos;
+};
+
+GLIBC_2.1 {
+ global:
+ sem_wait;
+ pthread_create;
+ dlopen;
+ open64;
+ pread;
+ pwrite;
+ pwrite64;
+ popen;
+ fopen;
+ fclose;
+ fdopen;
+ fgetpos64;
+ fsetpos64;
+};
+
+GLIBC_2.2 {
+ global:
+ open64;
+ posix_spawn;
+ posix_spawnp;
+ pread;
+ pwrite;
+ pwrite64;
+ timer_create;
+ fgetpos;
+ fsetpos;
+ fgetpos64;
+ fsetpos64;
+};
+
+GLIBC_2.3.2 {
+ global:
+ pthread_cond_wait;
+ pthread_cond_timedwait;
+};
+
+GLIBC_2.15 {
+ global:
+ posix_spawn;
+ posix_spawnp;
+};
diff --git a/gprofng/libcollector/mapfile.sparc-Linux b/gprofng/libcollector/mapfile.sparc-Linux
new file mode 100644
index 0000000..30d3953
--- /dev/null
+++ b/gprofng/libcollector/mapfile.sparc-Linux
@@ -0,0 +1,40 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+GLIBC_2.0 {
+ global:
+ pthread_mutex_lock;
+ pthread_mutex_unlock;
+ pthread_join;
+};
+
+GLIBC_2.1 {
+ global:
+ sem_wait;
+ pthread_create;
+ dlopen;
+ popen;
+};
+
+GLIBC_2.3.2 {
+ global:
+ pthread_cond_wait;
+ pthread_cond_timedwait;
+};
diff --git a/gprofng/libcollector/mapfile.sparcv9-Linux b/gprofng/libcollector/mapfile.sparcv9-Linux
new file mode 100644
index 0000000..db79766
--- /dev/null
+++ b/gprofng/libcollector/mapfile.sparcv9-Linux
@@ -0,0 +1,58 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+GLIBC_2.0 {
+ global:
+ dlopen;
+};
+
+GLIBC_2.1 {
+ global:
+ dlopen;
+};
+
+GLIBC_2.2 {
+ global:
+ pthread_create;
+ popen;
+ pthread_mutex_lock;
+ pthread_mutex_unlock;
+ pthread_join;
+ sem_wait;
+ pthread_cond_wait;
+ pthread_cond_timedwait;
+ timer_create;
+ fopen;
+ fclose;
+ fdopen;
+ fgetpos;
+ fsetpos;
+};
+
+GLIBC_2.3.2 {
+ global:
+ pthread_cond_wait;
+ pthread_cond_timedwait;
+};
+
+GLIBC_2.3.3 {
+ global:
+ timer_create;
+};
diff --git a/gprofng/libcollector/memmgr.c b/gprofng/libcollector/memmgr.c
new file mode 100644
index 0000000..5ada421
--- /dev/null
+++ b/gprofng/libcollector/memmgr.c
@@ -0,0 +1,396 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "config.h"
+#include <sys/mman.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "collector.h"
+#include "libcol_util.h"
+#include "gp-experiment.h"
+#include "memmgr.h"
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+#define DBG_LT4 4
+
+/*
+ * Memory allocation.
+ *
+ * Heap:
+ * chain[0] - linked list of chunks;
+ * chain[1] - linked list of free 16-byte objects;
+ * chain[2] - linked list of free 32-byte objects;
+ * ...
+ *
+ * Chunk:
+ *
+ * base lo hi
+ * V V V
+ * +------------------+---------+-------------------+--+--+-----+
+ * | Var size object | -> <-| Const size objects| | |Chunk|
+ * +------------------+---------+-------------------+--+--+-----+
+ *
+ * Limitations:
+ * - one var size object per chunk
+ * - can't allocate const size objects larger than 2^MAXCHAIN
+ */
+
+#define MAXCHAIN 32
+#define ALIGNMENT 4 /* 2^ALIGNMENT == minimal size and alignment */
+#define ALIGN(x) ((((x) - 1)/(1 << ALIGNMENT) + 1) * (1 << ALIGNMENT))
+
+struct Heap
+{
+ collector_mutex_t lock; /* master lock */
+ void *chain[MAXCHAIN]; /* chain[0] - chunks */
+ /* chain[i] - structs of size 2^i */
+};
+
+typedef struct Chunk
+{
+ size_t size;
+ char *base;
+ char *lo;
+ char *hi;
+ struct Chunk *next;
+} Chunk;
+
+static void
+not_implemented ()
+{
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">error memmgr not_implemented()</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_NOZMEM);
+ return;
+}
+
+/*
+ * void __collector_mmgr_init_mutex_locks( Heap *heap )
+ * Iinitialize mmgr mutex locks.
+ */
+void
+__collector_mmgr_init_mutex_locks (Heap *heap)
+{
+ if (heap == NULL)
+ return;
+ if (__collector_mutex_trylock (&heap->lock))
+ {
+ /*
+ * We are in a child process immediately after the fork().
+ * Parent process was in the middle of critical section when the fork() happened.
+ * This is a placeholder for the cleanup.
+ * See CR 6997020 for details.
+ */
+ __collector_mutex_init (&heap->lock);
+ }
+ __collector_mutex_init (&heap->lock);
+}
+
+/*
+ * alloc_chunk( unsigned sz ) allocates a chunk of at least sz bytes.
+ * If sz == 0, allocates a chunk of the default size.
+ */
+static Chunk *
+alloc_chunk (unsigned sz, int log)
+{
+ static long pgsz = 0;
+ char *ptr;
+ Chunk *chnk;
+ size_t chunksz;
+ if (pgsz == 0)
+ {
+ pgsz = CALL_UTIL (sysconf)(_SC_PAGESIZE);
+ Tprintf (DBG_LT2, "memmgr: pgsz = %ld (0x%lx)\n", pgsz, pgsz);
+ }
+ /* Allocate 2^n >= sz bytes */
+ unsigned nsz = ALIGN (sizeof (Chunk)) + sz;
+ for (chunksz = pgsz; chunksz < nsz; chunksz *= 2);
+ if (log == 1)
+ Tprintf (DBG_LT2, "alloc_chunk mapping %u, rounded up from %u\n", (unsigned int) chunksz, sz);
+ /* mmap64 is only in 32-bits; this call goes to mmap in 64-bits */
+ ptr = (char*) CALL_UTIL (mmap64)(0, chunksz, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, (int) -1, (off64_t) 0);
+ if (ptr == MAP_FAILED)
+ {
+ Tprintf (0, "alloc_chunk mapping failed COL_ERROR_NOZMEMMAP: %s\n", CALL_UTIL (strerror)(errno));
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_NOZMEMMAP, errno, "0");
+ return NULL;
+ }
+ /* Put the chunk descriptor at the end of the chunk */
+ chnk = (Chunk*) (ptr + chunksz - ALIGN (sizeof (Chunk)));
+ chnk->size = chunksz;
+ chnk->base = ptr;
+ chnk->lo = chnk->base;
+ chnk->hi = (char*) chnk;
+ chnk->next = (Chunk*) NULL;
+ if (log == 1)
+ Tprintf (DBG_LT2, "memmgr: returning new chunk @%p, chunksx=%ld sz=%ld\n",
+ ptr, (long) chunksz, (long) sz);
+ return chnk;
+}
+
+Heap *
+__collector_newHeap ()
+{
+ Heap *heap;
+ Chunk *chnk;
+ Tprintf (DBG_LT2, "__collector_newHeap calling alloc_chunk(0)\n");
+ chnk = alloc_chunk (0, 1);
+ if (chnk == NULL)
+ return NULL;
+
+ /* A bit of hackery: allocate heap from its own chunk */
+ chnk->hi -= ALIGN (sizeof (Heap));
+ heap = (Heap*) chnk->hi;
+ heap->chain[0] = (void*) chnk;
+ __collector_mutex_init (&heap->lock);
+ return heap;
+}
+
+void
+__collector_deleteHeap (Heap *heap)
+{
+ if (heap == NULL)
+ return;
+ /* Note: heap itself is in the last chunk */
+ for (Chunk *chnk = heap->chain[0]; chnk;)
+ {
+ Chunk *next = chnk->next;
+ CALL_UTIL (munmap)((void*) chnk->base, chnk->size);
+ chnk = next;
+ }
+}
+
+void *
+__collector_allocCSize (Heap *heap, unsigned sz, int log)
+{
+ void *res;
+ Chunk *chnk;
+ if (heap == NULL)
+ return NULL;
+
+ /* block all signals and acquire lock */
+ sigset_t old_mask, new_mask;
+ CALL_UTIL (sigfillset)(&new_mask);
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask);
+ __collector_mutex_lock (&heap->lock);
+
+ /* Allocate nsz = 2^idx >= sz bytes */
+ unsigned idx = ALIGNMENT;
+ unsigned nsz = 1 << idx;
+ while (nsz < sz)
+ nsz = 1 << ++idx;
+
+ /* Look in the corresponding chain first */
+ if (idx < MAXCHAIN)
+ {
+ if (heap->chain[idx] != NULL)
+ {
+ res = heap->chain[idx];
+ heap->chain[idx] = *(void**) res;
+ __collector_mutex_unlock (&heap->lock);
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
+ if (log == 1)
+ Tprintf (DBG_LT2, "memmgr: allocCSize %p sz %d (0x%x) req = 0x%x, from chain idx = %d\n", res, nsz, nsz, sz, idx);
+ return res;
+ }
+ }
+ else
+ {
+ not_implemented ();
+ __collector_mutex_unlock (&heap->lock);
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
+ return NULL;
+ }
+
+ /* Chain is empty, allocate from chunks */
+ for (chnk = (Chunk*) heap->chain[0]; chnk; chnk = chnk->next)
+ if (chnk->lo + nsz < chnk->hi)
+ break;
+ if (chnk == NULL)
+ {
+ /* Get a new chunk */
+ if (log == 1)
+ Tprintf (DBG_LT2, "__collector_allocCSize (%u) calling alloc_chunk(%u)\n", sz, nsz);
+ chnk = alloc_chunk (nsz, 1);
+ if (chnk == NULL)
+ {
+ __collector_mutex_unlock (&heap->lock);
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
+ return NULL;
+ }
+ chnk->next = (Chunk*) heap->chain[0];
+ heap->chain[0] = chnk;
+ }
+
+ /* Allocate from the chunk */
+ chnk->hi -= nsz;
+ res = (void*) chnk->hi;
+ __collector_mutex_unlock (&heap->lock);
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
+ if (log == 1)
+ Tprintf (DBG_LT2, "memmgr: allocCSize %p sz %d (0x%x) req = 0x%x, new chunk\n", res, nsz, nsz, sz);
+ return res;
+}
+
+void
+__collector_freeCSize (Heap *heap, void *ptr, unsigned sz)
+{
+ if (heap == NULL || ptr == NULL)
+ return;
+
+ /* block all signals and acquire lock */
+ sigset_t old_mask, new_mask;
+ CALL_UTIL (sigfillset)(&new_mask);
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask);
+ __collector_mutex_lock (&heap->lock);
+
+ /* Free 2^idx >= sz bytes */
+ unsigned idx = ALIGNMENT;
+ unsigned nsz = 1 << idx;
+ while (nsz < sz)
+ nsz = 1 << ++idx;
+ if (idx < MAXCHAIN)
+ {
+ *(void**) ptr = heap->chain[idx];
+ heap->chain[idx] = ptr;
+ }
+ else
+ not_implemented ();
+ __collector_mutex_unlock (&heap->lock);
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
+ Tprintf (DBG_LT4, "memmgr: freeC %p sz %ld\n", ptr, (long) sz);
+}
+
+static void *
+allocVSize_nolock (Heap *heap, unsigned sz)
+{
+ void *res;
+ Chunk *chnk;
+ if (sz == 0)
+ return NULL;
+
+ /* Find a good chunk */
+ for (chnk = (Chunk*) heap->chain[0]; chnk; chnk = chnk->next)
+ if (chnk->lo == chnk->base && chnk->lo + sz < chnk->hi)
+ break;
+ if (chnk == NULL)
+ {
+ /* Get a new chunk */
+ Tprintf (DBG_LT2, "allocVsize_nolock calling alloc_chunk(%u)\n", sz);
+ chnk = alloc_chunk (sz, 0);
+ if (chnk == NULL)
+ return NULL;
+ chnk->next = (Chunk*) heap->chain[0];
+ heap->chain[0] = chnk;
+ }
+ chnk->lo = chnk->base + sz;
+ res = (void*) (chnk->base);
+ Tprintf (DBG_LT4, "memmgr: allocV %p for %ld\n", res, (long) sz);
+ return res;
+}
+
+void *
+__collector_allocVSize (Heap *heap, unsigned sz)
+{
+ void *res;
+ if (heap == NULL)
+ return NULL;
+
+ /* block all signals and acquire lock */
+ sigset_t old_mask, new_mask;
+ CALL_UTIL (sigfillset)(&new_mask);
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask);
+ __collector_mutex_lock (&heap->lock);
+ res = allocVSize_nolock (heap, sz);
+ __collector_mutex_unlock (&heap->lock);
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
+ return res;
+}
+
+/*
+ * reallocVSize( Heap *heap, void *ptr, unsigned newsz )
+ * Changes the size of memory pointed by ptr to newsz.
+ * If ptr == NULL, allocates new memory of size newsz.
+ * If newsz == 0, frees ptr and returns NULL.
+ */
+void *
+__collector_reallocVSize (Heap *heap, void *ptr, unsigned newsz)
+{
+ Chunk *chnk;
+ void *res;
+ if (heap == NULL)
+ return NULL;
+ if (ptr == NULL)
+ return __collector_allocVSize (heap, newsz);
+
+ /* block all signals and acquire lock */
+ sigset_t old_mask, new_mask;
+ CALL_UTIL (sigfillset)(&new_mask);
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &new_mask, &old_mask);
+ __collector_mutex_lock (&heap->lock);
+
+ /* Find its chunk */
+ for (chnk = (Chunk*) heap->chain[0]; chnk; chnk = chnk->next)
+ if (ptr == chnk->base)
+ break;
+ if (chnk == NULL)
+ {
+ /* memory corrpution */
+ not_implemented ();
+ __collector_mutex_unlock (&heap->lock);
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
+ return NULL;
+ }
+ if (chnk->base + newsz < chnk->hi)
+ {
+ /* easy case */
+ chnk->lo = chnk->base + newsz;
+ res = newsz ? chnk->base : NULL;
+ __collector_mutex_unlock (&heap->lock);
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
+ Tprintf (DBG_LT4, "memmgr: reallocV %p for %ld\n", ptr, (long) newsz);
+ return res;
+ }
+ res = allocVSize_nolock (heap, newsz);
+ /* Copy to new location */
+ if (res)
+ {
+ int size = chnk->lo - chnk->base;
+ if (newsz < size)
+ size = newsz;
+ char *s1 = (char*) res;
+ char *s2 = chnk->base;
+ while (size--)
+ *s1++ = *s2++;
+ }
+ /* Free old memory*/
+ chnk->lo = chnk->base;
+ __collector_mutex_unlock (&heap->lock);
+ CALL_UTIL (sigprocmask)(SIG_SETMASK, &old_mask, NULL);
+ return res;
+}
diff --git a/gprofng/libcollector/memmgr.h b/gprofng/libcollector/memmgr.h
new file mode 100644
index 0000000..78231c2
--- /dev/null
+++ b/gprofng/libcollector/memmgr.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#ifndef _MEMMGR_H
+#define _MEMMGR_H
+
+struct Heap;
+typedef struct Heap Heap;
+
+Heap *__collector_newHeap ();
+void __collector_deleteHeap (Heap *heap);
+
+/*
+ * Initialize memmgr mutex locks.
+ */
+void __collector_mmgr_init_mutex_locks (Heap *heap);
+
+/*
+ * Allocate non-resizable memory.
+ */
+void *__collector_allocCSize (Heap *heap, unsigned sz, int log);
+
+/*
+ * Free non-resizable memory.
+ */
+void __collector_freeCSize (Heap *heap, void *ptr, unsigned sz);
+
+/*
+ * Allocate resizable memory
+ */
+void *__collector_allocVSize (Heap *heap, unsigned sz);
+
+/*
+ * Change size of resizable memory.
+ * ptr - if not NULL, it must have been previously allocated from
+ * the same heap, otherwise returns allocVSize(heap, newsz);
+ * newsz - new size; if 0, memory is freed and no new allocation
+ * occurs;
+ */
+void *__collector_reallocVSize (Heap *heap, void *ptr, unsigned newsz);
+
+#endif
diff --git a/gprofng/libcollector/mmaptrace.c b/gprofng/libcollector/mmaptrace.c
new file mode 100644
index 0000000..ac5c997
--- /dev/null
+++ b/gprofng/libcollector/mmaptrace.c
@@ -0,0 +1,1691 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/*
+ * memory map tracking
+ * incorporating former "loadobjects" into more general "map"
+ * (including code and data segments and dynamic functions)
+ */
+
+#include "config.h"
+#include <alloca.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <elf.h>
+#include <sys/mman.h>
+#include <sys/param.h>
+#include <stdint.h>
+
+#include "gp-defs.h"
+#include "collector.h"
+#include "gp-experiment.h"
+#include "memmgr.h"
+
+/*
+ * These are obsolete and unreliable.
+ * They are included here only for historical compatibility.
+ */
+#define MA_SHARED 0x08 /* changes are shared by mapped object */
+#define MA_ANON 0x40 /* anonymous memory (e.g. /dev/zero) */
+#define MA_ISM 0x80 /* intimate shared mem (shared MMU resources) */
+#define MA_BREAK 0x10 /* grown by brk(2) */
+#define MA_STACK 0x20 /* grown automatically on stack faults */
+
+typedef struct prmap_t
+{
+ unsigned long pr_vaddr; /* virtual address of mapping */
+ unsigned long pr_size; /* size of mapping in bytes */
+ char *pr_mapname; /* name in /proc/<pid>/object */
+ int pr_mflags; /* protection and attribute flags (see below) */
+ unsigned long pr_offset; /* offset into mapped object, if any */
+ unsigned long pr_dev;
+ unsigned long pr_ino;
+ int pr_pagesize; /* pagesize (bytes) for this mapping */
+} prmap_t;
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+#define DBG_LT4 4
+
+#define SYS_MMAP_NAME "mmap"
+#define SYS_MMAP64_NAME "mmap64"
+#define SYS_MUNMAP_NAME "munmap"
+#define SYS_DLOPEN_NAME "dlopen"
+#define SYS_DLCLOSE_NAME "dlclose"
+
+typedef struct MapInfo
+{
+ struct MapInfo *next;
+ unsigned long vaddr;
+ unsigned long size;
+ char *mapname; /* name in /proc/<pid>/object */
+ char *filename;
+ unsigned long offset;
+ int mflags;
+ int pagesize;
+} MapInfo;
+
+typedef struct NameInfo
+{
+ struct NameInfo *next;
+ char *mapname;
+ char filename[1]; /* dynamic length file name */
+} NameInfo;
+
+static NameInfo *namemaps = NULL;
+static MapInfo mmaps; /* current memory maps */
+static struct DataHandle *map_hndl = NULL;
+static char dyntext_fname[MAXPATHLEN];
+static void *mapcache = NULL;
+static char *maptext = NULL;
+static size_t maptext_sz = 4096; /* initial buffer size */
+static int mmap_mode = 0;
+static int mmap_initted = 0;
+static collector_mutex_t map_lock = COLLECTOR_MUTEX_INITIALIZER;
+static collector_mutex_t dyntext_lock = COLLECTOR_MUTEX_INITIALIZER;
+
+/* a reentrance guard for the interposition functions ensures that updates to
+ the map cache/file are sequential, with the first doing the final update */
+static int reentrance = 0;
+#define CHCK_REENTRANCE (reentrance || mmap_mode <= 0)
+#define CURR_REENTRANCE reentrance
+#define PUSH_REENTRANCE reentrance++
+#define POP_REENTRANCE reentrance--
+
+#define CALL_REAL(x) (__real_##x)
+#define NULL_PTR(x) (__real_##x == NULL)
+
+/* interposition function handles */
+static void *(*__real_mmap)(void* start, size_t length, int prot, int flags,
+ int fd, off_t offset) = NULL;
+static void *(*__real_mmap64)(void* start, size_t length, int prot, int flags,
+ int fd, off64_t offset) = NULL;
+static int (*__real_munmap)(void* start, size_t length) = NULL;
+static void *(*__real_dlopen)(const char* pathname, int mode) = NULL;
+#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
+static void *(*__real_dlopen_2_1)(const char* pathname, int mode) = NULL;
+static void *(*__real_dlopen_2_0)(const char* pathname, int mode) = NULL;
+#endif
+static int (*__real_dlclose)(void* handle) = NULL;
+static void (*collector_heap_record)(int, size_t, void*) = NULL;
+
+/* internal function prototypes */
+static int init_mmap_intf ();
+static int init_mmap_files ();
+static void append_segment_record (char *format, ...);
+static void update_map_segments (hrtime_t hrt, int resolve);
+static void resolve_mapname (MapInfo *map, char *name);
+static void record_segment_map (hrtime_t timestamp, uint64_t loadaddr,
+ unsigned long msize, int pagesize, int modeflags,
+ long long offset, unsigned check, char *name);
+static void record_segment_unmap (hrtime_t timestamp, uint64_t loadaddr);
+
+/* Linux needs handling of the vsyscall page to get its data into the map.xml file */
+static void process_vsyscall_page ();
+
+#define MAXVSYSFUNCS 10
+static int nvsysfuncs = 0;
+static char *sysfuncname[MAXVSYSFUNCS];
+static uint64_t sysfuncvaddr[MAXVSYSFUNCS];
+static unsigned long sysfuncsize[MAXVSYSFUNCS];
+
+#define MAXDYN 20
+static int ndyn = 0;
+static char *dynname [MAXDYN];
+static void *dynvaddr [MAXDYN];
+static unsigned dynsize [MAXDYN];
+static char *dynfuncname[MAXDYN];
+
+/*===================================================================*/
+
+/*
+ * void __collector_mmap_init_mutex_locks()
+ * Iinitialize mmap mutex locks.
+ */
+void
+__collector_mmap_init_mutex_locks ()
+{
+ __collector_mutex_init (&map_lock);
+ __collector_mutex_init (&dyntext_lock);
+}
+
+/* __collector_ext_update_map_segments called by the audit agent
+ * Is is also called by dbx/collector when a (possible) map update
+ * is intimated, such as after dlopen/dlclose.
+ * Required when libcollector.so is not preloaded and interpositions inactive.
+ */
+int
+__collector_ext_update_map_segments (void)
+{
+ if (!mmap_initted)
+ return 0;
+ TprintfT (0, "__collector_ext_update_map_segments(%d)\n", CURR_REENTRANCE);
+ if (CHCK_REENTRANCE)
+ return 0;
+ PUSH_REENTRANCE;
+ update_map_segments (GETRELTIME (), 1);
+ POP_REENTRANCE;
+ return 0;
+}
+/*
+ * int __collector_ext_mmap_install()
+ * Install and initialise mmap tracing.
+ */
+int
+__collector_ext_mmap_install (int record)
+{
+ TprintfT (0, "__collector_ext_mmap_install(mmap_mode=%d)\n", mmap_mode);
+ if (NULL_PTR (mmap))
+ {
+ if (init_mmap_intf ())
+ {
+ TprintfT (0, "ERROR: collector mmap tracing initialization failed.\n");
+ return COL_ERROR_EXPOPEN;
+ }
+ }
+ else
+ TprintfT (DBG_LT2, "collector mmap tracing: mmap pointer not null\n");
+
+ /* Initialize side door interface with the heap tracing module */
+ collector_heap_record = (void(*)(int, size_t, void*))dlsym (RTLD_DEFAULT, "__collector_heap_record");
+ if (record)
+ {
+ map_hndl = __collector_create_handle (SP_MAP_FILE);
+ if (map_hndl == NULL)
+ return COL_ERROR_MAPOPEN;
+ if (init_mmap_files ())
+ {
+ TprintfT (0, "ERROR: collector init_mmap_files() failed.\n");
+ return COL_ERROR_EXPOPEN;
+ }
+ }
+ mmaps.next = NULL;
+ mapcache = NULL;
+ PUSH_REENTRANCE;
+ update_map_segments (GETRELTIME (), 1); // initial map
+ POP_REENTRANCE;
+ mmap_mode = 1;
+ mmap_initted = 1;
+ process_vsyscall_page ();
+ return COL_ERROR_NONE;
+}
+
+/*
+ * int __collector_ext_mmap_deinstall()
+ * Optionally update final map and stop tracing mmap events.
+ */
+int
+__collector_ext_mmap_deinstall (int update)
+{
+ if (!mmap_initted)
+ return COL_ERROR_NONE;
+ mmap_mode = 0;
+ if (update)
+ {
+ /* Final map */
+ PUSH_REENTRANCE;
+ update_map_segments (GETRELTIME (), 1);
+ POP_REENTRANCE;
+ }
+ TprintfT (0, "__collector_ext_mmap_deinstall(%d)\n", update);
+ if (map_hndl != NULL)
+ {
+ __collector_delete_handle (map_hndl);
+ map_hndl = NULL;
+ }
+ __collector_mutex_lock (&map_lock); // get lock before resetting
+
+ /* Free all memory maps */
+ MapInfo *mp;
+ for (mp = mmaps.next; mp;)
+ {
+ MapInfo *next = mp->next;
+ __collector_freeCSize (__collector_heap, mp, sizeof (*mp));
+ mp = next;
+ }
+ mmaps.next = NULL;
+
+ /* Free all name maps */
+ NameInfo *np;
+ for (np = namemaps; np;)
+ {
+ NameInfo *next = np->next;
+ __collector_freeCSize (__collector_heap, np, sizeof (*np) + __collector_strlen (np->filename));
+ np = next;
+ }
+ namemaps = NULL;
+ mapcache = __collector_reallocVSize (__collector_heap, mapcache, 0);
+ mmaps.next = NULL;
+ mapcache = NULL;
+ __collector_mutex_unlock (&map_lock);
+ TprintfT (0, "__collector_ext_mmap_deinstall done\n");
+ return 0;
+}
+
+/*
+ * void __collector_mmap_fork_child_cleanup()
+ * Perform all necessary cleanup steps in child process after fork().
+ */
+void
+__collector_mmap_fork_child_cleanup ()
+{
+ /* Initialize all mmap "mutex" locks */
+ __collector_mmap_init_mutex_locks ();
+ if (!mmap_initted)
+ return;
+ mmap_mode = 0;
+ __collector_delete_handle (map_hndl);
+ __collector_mutex_lock (&map_lock); // get lock before resetting
+
+ /* Free all memory maps */
+ MapInfo *mp;
+ for (mp = mmaps.next; mp;)
+ {
+ MapInfo *next = mp->next;
+ __collector_freeCSize (__collector_heap, mp, sizeof (*mp));
+ mp = next;
+ }
+ mmaps.next = NULL;
+
+ /* Free all name maps */
+ NameInfo *np;
+ for (np = namemaps; np;)
+ {
+ NameInfo *next = np->next;
+ __collector_freeCSize (__collector_heap, np, sizeof (*np) + __collector_strlen (np->filename));
+ np = next;
+ }
+ namemaps = NULL;
+ mapcache = __collector_reallocVSize (__collector_heap, mapcache, 0);
+ mmap_initted = 0;
+ reentrance = 0;
+ __collector_mutex_unlock (&map_lock);
+}
+
+static int
+init_mmap_files ()
+{
+ TprintfT (DBG_LT2, "init_mmap_files\n");
+ /* also create the headerless dyntext file (if required) */
+ CALL_UTIL (snprintf)(dyntext_fname, sizeof (dyntext_fname), "%s/%s",
+ __collector_exp_dir_name, SP_DYNTEXT_FILE);
+ if (CALL_UTIL (access)(dyntext_fname, F_OK) != 0)
+ {
+ int fd = CALL_UTIL (open)(dyntext_fname, O_RDWR | O_CREAT | O_TRUNC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (fd == -1)
+ {
+ char errmsg[256];
+ TprintfT (0, "ERROR: init_mmap_files: open(%s) failed\n",
+ dyntext_fname);
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s: %s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_DYNOPEN, errno,
+ dyntext_fname, errmsg);
+ return COL_ERROR_DYNOPEN;
+ }
+ else
+ CALL_UTIL (close)(fd);
+ }
+ return COL_ERROR_NONE;
+}
+
+static void
+append_segment_record (char *format, ...)
+{
+ char buf[1024];
+ char *bufptr = buf;
+ va_list va;
+ va_start (va, format);
+ int sz = __collector_xml_vsnprintf (bufptr, sizeof (buf), format, va);
+ va_end (va);
+
+ if (__collector_expstate != EXP_OPEN && __collector_expstate != EXP_PAUSED)
+ {
+ TprintfT (0, "append_segment_record: expt neither open nor paused (%d); "
+ "not writing to map.xml\n\t%s", __collector_expstate, buf);
+ return;
+ }
+ if (sz >= sizeof (buf))
+ {
+ /* Allocate a new buffer */
+ sz += 1; /* add the terminating null byte */
+ bufptr = (char*) alloca (sz);
+ va_start (va, format);
+ sz = __collector_xml_vsnprintf (bufptr, sz, format, va);
+ va_end (va);
+ }
+ int rc = __collector_write_string (map_hndl, bufptr, sz);
+ if (rc != 0)
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\"></event>\n",
+ SP_JCMD_CERROR, COL_ERROR_MAPWRITE);
+}
+
+static void
+record_segment_map (hrtime_t timestamp, uint64_t loadaddr, unsigned long msize,
+ int pagesize, int modeflags, long long offset,
+ unsigned check, char *name)
+{
+
+ TprintfT (DBG_LT2, "record_segment_map(%s @ 0x%llx)\n", name, (long long) loadaddr);
+ append_segment_record ("<event kind=\"map\" object=\"segment\" tstamp=\"%u.%09u\" "
+ "vaddr=\"0x%016llX\" size=\"%lu\" pagesz=\"%d\" foffset=\"%c0x%08llX\" "
+ "modes=\"0x%03X\" chksum=\"0x%0X\" name=\"%s\"/>\n",
+ (unsigned) (timestamp / NANOSEC),
+ (unsigned) (timestamp % NANOSEC),
+ loadaddr, msize, pagesize,
+ offset < 0 ? '-' : '+', offset < 0 ? -offset : offset,
+ modeflags, check, name);
+}
+
+static void
+record_segment_unmap (hrtime_t timestamp, uint64_t loadaddr)
+{
+ TprintfT (DBG_LT2, "record_segment_unmap(@ 0x%llx)\n", (long long) loadaddr);
+ append_segment_record ("<event kind=\"unmap\" tstamp=\"%u.%09u\" vaddr=\"0x%016llX\"/>\n",
+ (unsigned) (timestamp / NANOSEC),
+ (unsigned) (timestamp % NANOSEC), loadaddr);
+}
+
+#if WSIZE(64)
+#define ELF_EHDR Elf64_Ehdr
+#define ELF_PHDR Elf64_Phdr
+#define ELF_SHDR Elf64_Shdr
+#define ELF_DYN Elf64_Dyn
+#define ELF_AUX Elf64_auxv_t
+#define ELF_SYM Elf64_Sym
+#define ELF_ST_BIND ELF64_ST_BIND
+#define ELF_ST_TYPE ELF64_ST_TYPE
+#elif WSIZE(32)
+#define ELF_EHDR Elf32_Ehdr
+#define ELF_PHDR Elf32_Phdr
+#define ELF_SHDR Elf32_Shdr
+#define ELF_DYN Elf32_Dyn
+#define ELF_AUX Elf32_auxv_t
+#define ELF_SYM Elf32_Sym
+#define ELF_ST_BIND ELF32_ST_BIND
+#define ELF_ST_TYPE ELF32_ST_TYPE
+#endif
+
+static unsigned
+checksum_mapname (MapInfo* map)
+{
+ unsigned checksum = 0;
+ /* only checksum code segments */
+ if ((map->mflags & (PROT_EXEC | PROT_READ)) == 0 ||
+ (map->mflags & PROT_WRITE) != 0)
+ return 0;
+ checksum = (unsigned) - 1;
+ TprintfT (DBG_LT2, "checksum_mapname checksum = 0x%0X\n", checksum);
+ return checksum;
+}
+
+
+#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
+static void*
+dlopen_searchpath_symver (void*(real_dlopen) (), void* caller_addr, const char* basename, int mode)
+#else
+static void*
+dlopen_searchpath (void* caller_addr, const char* basename, int mode)
+#endif
+{
+ TprintfT (DBG_LT2, "dlopen_searchpath(%p, %s, %d)\n", caller_addr, basename, mode);
+ Dl_info dl_info;
+ if (dladdr (caller_addr, &dl_info) == 0)
+ {
+ TprintfT (0, "ERROR: dladdr(%p): %s\n", caller_addr, dlerror ());
+ return 0;
+ }
+ TprintfT (DBG_LT2, "dladdr(%p): %p fname=%s\n",
+ caller_addr, dl_info.dli_fbase, dl_info.dli_fname);
+ int noload = RTLD_BINDING_MASK | RTLD_NOLOAD; //XXXX why RTLD_BINDING_MASK?
+#define WORKAROUND_RTLD_BUG 1
+#ifdef WORKAROUND_RTLD_BUG
+ // A dynamic linker dlopen bug can result in corruption/closure of open streams
+ // XXXX workaround should be removed once linker patches are all available
+#if WSIZE(64)
+#define MAINBASE 0x400000
+#elif WSIZE(32)
+#define MAINBASE 0x08048000
+#endif
+ const char* tmp_path =
+ (dl_info.dli_fbase == (void*) MAINBASE) ? NULL : dl_info.dli_fname;
+ void* caller_hndl = NULL;
+#if ((ARCH(Intel) && WSIZE(32)) || ARCH(SPARC))
+ caller_hndl = (real_dlopen) (tmp_path, noload);
+#else
+ caller_hndl = CALL_REAL (dlopen)(tmp_path, noload);
+#endif
+
+#else //XXXX workaround should be removed once linker patches are all available
+
+ void* caller_hndl = NULL;
+#if (ARCH(Intel) && WSIZE(32) || ARCH(SPARC)
+ caller_hndl = (real_dlopen) (dl_info.dli_fname, noload);
+#else
+ caller_hndl = CALL_REAL (dlopen)(dl_info.dli_fname, noload);
+#endif
+
+#endif //XXXX workaround should be removed once linker patches are all available
+
+ if (!caller_hndl)
+ {
+ TprintfT (0, "ERROR: dlopen(%s,NOLOAD): %s\n", dl_info.dli_fname, dlerror ());
+ return 0;
+ }
+ Dl_serinfo _info, *info = &_info;
+ Dl_serpath *path;
+
+ /* determine search path count and required buffer size */
+ dlinfo (caller_hndl, RTLD_DI_SERINFOSIZE, (void *) info);
+
+ /* allocate new buffer and initialize */
+ /*
+ CR# 7191331
+ There is a bug in Linux that causes the first call
+ to dlinfo() to return a small value for the dls_size.
+
+ The first call to dlinfo() determines the search path
+ count and the required buffer size. The second call to
+ dlinfo() tries to obtain the search path information.
+
+ However, the size of the buffer that is returned by
+ the first call to the dlinfo() is incorrect (too small).
+ The second call to dlinfo() uses the incorrect size to
+ allocate memory on the stack and internally uses the memcpy()
+ function to copy the search paths to the allocated memory space.
+ The length of the search path is much larger than the buffer
+ that is allocated on the stack. The memcpy() overwrites some
+ of the information that are saved on the stack, specifically,
+ it overwrites the "basename" parameter.
+
+ collect crashes right after the second call to dlinfo().
+
+ The search paths are used to locate the shared libraries.
+ dlinfo() creates the search paths based on the paths
+ that are assigned to LD_LIBRARY_PATH environment variable
+ and the standard library paths. The standard library paths
+ consists of the /lib and the /usr/lib paths. The
+ standard library paths are always included to the search
+ paths by dlinfo() even if the LD_LIBRARY_PATH environment
+ variable is not defined. Therefore, at the very least the
+ dls_cnt is assigned to 2 (/lib and /usr/lib) and dlinfo()
+ will never assign dls_cnt to zero. The dls_cnt is the count
+ of the potential paths for searching the shared libraries.
+
+ So we need to increase the buffer size before the second
+ call to dlinfo(). There are number of ways to increase
+ the buffer size. However, none of them can calculate the
+ buffer size precisely. Some users on the web have suggested
+ to multiply the MAXPATHLEN by dls_cnt for the buffer size.
+ The MAXPATHLEN is assigned to 1024 bytes. In my opinion
+ this is too much. So I have decided to multiply dls_size
+ by dls_cnt for the buffer size since the dls_size is much
+ smaller than 1024 bytes.
+
+ I have already confirmed with our user that the workaround
+ is working with his real application. Additionally,
+ the dlopen_searchpath() function is called only by the
+ libcorrector init() function when the experiment is started.
+ Therefore, allocating some extra bytes on the stack which
+ is local to this routine is harmless.
+ */
+
+ info = alloca (_info.dls_size * _info.dls_cnt);
+ info->dls_size = _info.dls_size;
+ info->dls_cnt = _info.dls_cnt;
+
+ /* obtain search path information */
+ dlinfo (caller_hndl, RTLD_DI_SERINFO, (void *) info);
+ path = &info->dls_serpath[0];
+
+ char pathname[MAXPATHLEN];
+ for (unsigned int cnt = 1; cnt <= info->dls_cnt; cnt++, path++)
+ {
+ __collector_strlcpy (pathname, path->dls_name, sizeof (pathname));
+ __collector_strlcat (pathname, "/", sizeof (pathname));
+ __collector_strlcat (pathname, basename, sizeof (pathname));
+ void* ret = NULL;
+#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
+ ret = (real_dlopen) (pathname, mode);
+#else
+ ret = CALL_REAL (dlopen)(pathname, mode);
+#endif
+ TprintfT (DBG_LT2, "try %d/%d: %s = %p\n", cnt, info->dls_cnt, pathname, ret);
+ if (ret)
+ return ret; // success!
+ }
+ return 0;
+}
+
+static void
+resolve_mapname (MapInfo *map, char *name)
+{
+ map->filename = "";
+ map->mapname = "";
+ if (name == NULL || *name == '\0')
+ {
+ if (map->mflags & MA_STACK)
+ map->filename = "<" SP_MAP_STACK ">";
+ else if (map->mflags & MA_BREAK)
+ map->filename = "<" SP_MAP_HEAP ">";
+ else if (map->mflags & MA_ISM)
+ map->filename = "<" SP_MAP_SHMEM ">";
+ return;
+ }
+ NameInfo *np;
+ for (np = namemaps; np; np = np->next)
+ if (__collector_strcmp (np->mapname, name) == 0)
+ break;
+
+ if (np == NULL)
+ {
+ const char *fname;
+ fname = name;
+ /* Create and link a new name map */
+ size_t fnamelen = __collector_strlen (fname) + 1;
+ np = (NameInfo*) __collector_allocCSize (__collector_heap, sizeof (NameInfo) + fnamelen, 1);
+ if (np == NULL) // We could not get memory
+ return;
+ np->mapname = np->filename;
+ __collector_strlcpy (np->filename, fname, fnamelen);
+ np->next = namemaps;
+ namemaps = np;
+ }
+ map->mapname = np->mapname;
+ map->filename = np->filename;
+ if (map->filename[0] == (char) 0)
+ map->filename = map->mapname;
+ TprintfT (DBG_LT2, "resolve_mapname: %s resolved to %s\n", map->mapname, map->filename);
+}
+
+static unsigned long
+str2ulong (char **ss)
+{
+ char *s = *ss;
+ unsigned long val = 0UL;
+ const int base = 16;
+ for (;;)
+ {
+ char c = *s++;
+ if (c >= '0' && c <= '9')
+ val = val * base + (c - '0');
+ else if (c >= 'a' && c <= 'f')
+ val = val * base + (c - 'a') + 10;
+ else if (c >= 'A' && c <= 'F')
+ val = val * base + (c - 'A') + 10;
+ else
+ break;
+ }
+ *ss = s - 1;
+ return val;
+}
+
+static void
+update_map_segments (hrtime_t hrt, int resolve)
+{
+ size_t filesz;
+ if (__collector_mutex_trylock (&map_lock))
+ {
+ TprintfT (0, "WARNING: update_map_segments(resolve=%d) BUSY\n", resolve);
+ return;
+ }
+ TprintfT (DBG_LT2, "\n");
+ TprintfT (DBG_LT2, "begin update_map_segments(hrt, %d)\n", resolve);
+
+ // Note: there is similar code to read /proc/$PID/map[s] in
+ // perfan/er_kernel/src/KSubExp.cc KSubExp::write_subexpt_map()
+ const char* proc_map = "/proc/self/maps";
+ size_t bufsz = maptext_sz;
+ int done = 0;
+ filesz = 0;
+ int map_fd = CALL_UTIL (open)(proc_map, O_RDONLY);
+ while (!done)
+ {
+ bufsz *= 2;
+ maptext = __collector_reallocVSize (__collector_heap, maptext, bufsz);
+ TprintfT (DBG_LT2, " update_map_segments: Loop for bufsize=%ld\n",
+ (long) bufsz);
+ for (;;)
+ {
+ int n = CALL_UTIL (read)(map_fd, maptext + filesz, bufsz - filesz);
+ TprintfT (DBG_LT2, " update_map_segments: __collector_read(bufp=%p nbyte=%ld)=%d\n",
+ maptext + filesz, (long) ( bufsz - filesz), n);
+ if (n < 0)
+ {
+ TprintfT (0, "ERROR: update_map_segments: read(maps): errno=%d\n", errno);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_MAPREAD, errno, proc_map);
+ CALL_UTIL (close)(map_fd);
+ __collector_mutex_unlock (&map_lock);
+ return;
+ }
+ else if (n == 0)
+ {
+ done = 1;
+ break;
+ }
+ filesz += n;
+ if (filesz >= bufsz) /* Buffer too small */
+ break;
+ }
+ }
+ CALL_UTIL (close)(map_fd);
+ maptext_sz = filesz;
+
+ int mapcache_entries = 0;
+ char *str, *str1;
+ for (str = maptext;; str = str1)
+ {
+ for (str1 = str; str1 - maptext < filesz; str1++)
+ {
+ if (*str1 == '\n')
+ {
+ *str1 = (char) 0;
+ break;
+ }
+ }
+ if (str1 - maptext >= filesz)
+ break;
+ str1++;
+ mapcache_entries++;
+ mapcache = __collector_reallocVSize (__collector_heap, mapcache,
+ sizeof (prmap_t) * mapcache_entries);
+ prmap_t *map = ((prmap_t *) mapcache) + (mapcache_entries - 1);
+ map->pr_vaddr = str2ulong (&str);
+ str++;
+ unsigned long eaddr = str2ulong (&str);
+ str++;
+ map->pr_size = eaddr - map->pr_vaddr;
+ map->pr_mflags = 0;
+ map->pr_mflags += (*str++ == 'r' ? PROT_READ : 0);
+ map->pr_mflags += (*str++ == 'w' ? PROT_WRITE : 0);
+ map->pr_mflags += (*str++ == 'x' ? PROT_EXEC : 0);
+ map->pr_mflags += (*str++ == 's' ? MA_SHARED : 0);
+ str++;
+ map->pr_offset = str2ulong (&str);
+ str++;
+ map->pr_dev = str2ulong (&str) * 0x100;
+ str++;
+ map->pr_dev += str2ulong (&str);
+ str++;
+ map->pr_ino = str2ulong (&str);
+ if (map->pr_dev == 0)
+ map->pr_mflags |= MA_ANON;
+ while (*str == ' ')
+ str++;
+ map->pr_mapname = str;
+ map->pr_pagesize = 4096;
+ }
+
+ /* Compare two maps and record all differences */
+ unsigned nidx = 0;
+ MapInfo *prev = &mmaps;
+ MapInfo *oldp = mmaps.next;
+ for (;;)
+ {
+ prmap_t *newp = nidx < mapcache_entries ?
+ (prmap_t*) mapcache + nidx : NULL;
+ if (oldp == NULL && newp == NULL)
+ break;
+
+ /* If two maps are equal proceed to the next pair */
+ if (oldp && newp &&
+ oldp->vaddr == newp->pr_vaddr &&
+ oldp->size == newp->pr_size &&
+ __collector_strcmp (oldp->mapname, newp->pr_mapname) == 0)
+ {
+ prev = oldp;
+ oldp = oldp->next;
+ nidx++;
+ continue;
+ }
+ /* Check if we need to unload the old map first */
+ if (newp == NULL || (oldp && oldp->vaddr <= newp->pr_vaddr))
+ {
+ if (oldp != NULL)
+ {
+ /* Don't record MA_ANON maps except MA_STACK and MA_BREAK */
+ if ((!(oldp->mflags & MA_ANON) || (oldp->mflags & (MA_STACK | MA_BREAK))))
+ record_segment_unmap (hrt, oldp->vaddr);
+ /* Remove and free map */
+ prev->next = oldp->next;
+ MapInfo *tmp = oldp;
+ oldp = oldp->next;
+ __collector_freeCSize (__collector_heap, tmp, sizeof (*tmp));
+ }
+ }
+ else
+ {
+ MapInfo *map = (MapInfo*) __collector_allocCSize (__collector_heap, sizeof (MapInfo), 1);
+ if (map == NULL)
+ {
+ __collector_mutex_unlock (&map_lock);
+ return;
+ }
+ map->vaddr = newp->pr_vaddr;
+ map->size = newp->pr_size;
+ map->offset = newp->pr_offset;
+ map->mflags = newp->pr_mflags;
+ map->pagesize = newp->pr_pagesize;
+ resolve_mapname (map, newp->pr_mapname);
+
+ /* Insert new map */
+ map->next = prev->next;
+ prev->next = map;
+ prev = map;
+
+ /* Don't record MA_ANON maps except MA_STACK and MA_BREAK */
+ if (!(newp->pr_mflags & MA_ANON) || (newp->pr_mflags & (MA_STACK | MA_BREAK)))
+ {
+ unsigned checksum = checksum_mapname (map);
+ record_segment_map (hrt, map->vaddr, map->size,
+ map->pagesize, map->mflags,
+ map->offset, checksum, map->filename);
+ }
+ nidx++;
+ }
+ }
+ TprintfT (DBG_LT2, "update_map_segments: done\n\n");
+ __collector_mutex_unlock (&map_lock);
+} /* update_map_segments */
+
+/*
+ * Map addr to a segment. Cope with split segments.
+ */
+int
+__collector_check_segment_internal (unsigned long addr, unsigned long *base,
+ unsigned long *end, int maxnretries, int MA_FLAGS)
+{
+ int number_of_tries = 0;
+retry:
+ ;
+
+ unsigned long curbase = 0;
+ unsigned long curfoff = 0;
+ unsigned long cursize = 0;
+
+ MapInfo *mp;
+ for (mp = mmaps.next; mp; mp = mp->next)
+ {
+
+ if (curbase + cursize == mp->vaddr &&
+ curfoff + cursize == mp->offset &&
+ ((mp->mflags & MA_FLAGS) == MA_FLAGS
+ || __collector_strncmp (mp->mapname, "[vdso]", 6) == 0
+ || __collector_strncmp (mp->mapname, "[vsyscall]", 10) == 0
+ ))
+ cursize = mp->vaddr + mp->size - curbase;
+ else if (addr < mp->vaddr)
+ break;
+ else if ((mp->mflags & MA_FLAGS) != MA_FLAGS
+ && __collector_strncmp (mp->mapname, "[vdso]", 6)
+ && __collector_strncmp (mp->mapname, "[vsyscall]", 10))
+ {
+ curbase = 0;
+ curfoff = 0;
+ cursize = 0;
+ }
+ else
+ {
+ curbase = mp->vaddr;
+ curfoff = mp->offset;
+ cursize = mp->size;
+ }
+ }
+
+ if (addr >= curbase && addr < curbase + cursize)
+ {
+ *base = curbase;
+ *end = curbase + cursize;
+ return 1;
+ }
+
+ /*
+ * 21275311 Unwind failure in native stack for java application running on jdk8 on x86
+ *
+ * On JDK8, we've observed cases where Java-compiled methods end up
+ * in virtual address segments that were "dead zones" (mflags&PROT_READ==0) at
+ * the time of the last update_map_segments() but are now "live". So if we
+ * fail to find a segment, let's call update_map_segments and then retry
+ * before giving up.
+ */
+ if (number_of_tries < maxnretries)
+ {
+ number_of_tries++;
+ __collector_ext_update_map_segments ();
+ goto retry;
+ }
+ *base = 0;
+ *end = 0;
+ return 0;
+}
+
+/**
+ * Check if address belongs to a readable and executable segment
+ * @param addr
+ * @param base
+ * @param end
+ * @param maxnretries
+ * @return 1 - yes, 0 - no
+ */
+int
+__collector_check_segment (unsigned long addr, unsigned long *base,
+ unsigned long *end, int maxnretries)
+{
+ int MA_FLAGS = PROT_READ | PROT_EXEC;
+ int res = __collector_check_segment_internal (addr, base, end, maxnretries, MA_FLAGS);
+ return res;
+}
+
+/**
+ * Check if address belongs to a readable segment
+ * @param addr
+ * @param base
+ * @param end
+ * @param maxnretries
+ * @return 1 - yes, 0 - no
+ */
+int
+__collector_check_readable_segment( unsigned long addr, unsigned long *base, unsigned long *end, int maxnretries )
+{
+ int MA_FLAGS = PROT_READ;
+ int res = __collector_check_segment_internal(addr, base, end, maxnretries, MA_FLAGS);
+ return res;
+}
+
+static ELF_AUX *auxv = NULL;
+
+static void
+process_vsyscall_page ()
+{
+ TprintfT (DBG_LT2, "process_vsyscall_page()\n");
+ if (ndyn != 0)
+ {
+ /* We've done this one in this process, and cached the results */
+ /* use the cached results */
+ for (int i = 0; i < ndyn; i++)
+ {
+ append_segment_record ("<event kind=\"map\" object=\"dynfunc\" name=\"%s\" "
+ "vaddr=\"0x%016lX\" size=\"%u\" funcname=\"%s\" />\n",
+ dynname[i], dynvaddr[i], dynsize[i], dynfuncname[i]);
+ TprintfT (DBG_LT2, "process_vsyscall_page: append_segment_record map dynfunc='%s' vaddr=0x%016lX size=%ld funcname='%s' -- from cache\n",
+ dynname[i], (unsigned long) dynvaddr[i],
+ (long) dynsize[i], dynfuncname[i]);
+ }
+ }
+ if (nvsysfuncs != 0)
+ {
+ /* We've done this one in this process, and cached the results */
+ /* use the cached results */
+ hrtime_t hrt = GETRELTIME ();
+ for (int i = 0; i < nvsysfuncs; i++)
+ {
+ append_segment_record ("<event kind=\"map\" object=\"function\" tstamp=\"%u.%09u\" "
+ "vaddr=\"0x%016lX\" size=\"%u\" name=\"%s\" />\n",
+ (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
+ (unsigned long) sysfuncvaddr[i], (unsigned) sysfuncsize[i], sysfuncname[i]);
+ TprintfT (DBG_LT2, "process_vsyscall_page: append_segment_record map function='%s' vaddr=0x%016lX size=%ld -- from cache\n",
+ sysfuncname[i], (unsigned long) sysfuncvaddr[i], (long) sysfuncsize[i]);
+ }
+ }
+ if (ndyn + nvsysfuncs != 0)
+ return;
+
+ /* After fork we can't rely on environ as it might have
+ * been moved by putenv(). Use the pointer saved by the parent.
+ */
+ if (auxv == NULL)
+ {
+ char **envp = (char**) environ;
+ if (envp == NULL)
+ return;
+ while (*envp++ != NULL);
+ auxv = (ELF_AUX*) envp;
+ }
+ TprintfT (DBG_LT2, "process_vsyscall_page, auxv = ox%p\n", auxv);
+
+ ELF_AUX *ap;
+#ifdef DEBUG
+ for (ap = auxv; ap->a_type != AT_NULL; ap++)
+ TprintfT (DBG_LT2, "process_vsyscall_page: ELF_AUX: "
+ " a_type = 0x%016llx %10lld "
+ " a_un.a_val = 0x%016llx %10lld\n",
+ (long long) ap->a_type, (long long) ap->a_type,
+ (long long) ap->a_un.a_val, (long long) ap->a_un.a_val);
+#endif
+
+ // find the first ELF_AUX of type AT_SYSINFO_EHDR
+ ELF_EHDR *ehdr = NULL;
+ for (ap = auxv; ap->a_type != AT_NULL; ap++)
+ {
+ if (ap->a_type == AT_SYSINFO_EHDR)
+ {
+ // newer Linuxes do not have a_ptr field, they just have a_val
+ ehdr = (ELF_EHDR*) ap->a_un.a_val;
+ if (ehdr != NULL)
+ break;
+ }
+ }
+
+ // If one is found
+ if (ehdr != NULL)
+ {
+ char *mapName = "SYSINFO_EHDR";
+ MapInfo *mp;
+ for (mp = mmaps.next; mp; mp = mp->next)
+ {
+ if ((unsigned long) ehdr == mp->vaddr)
+ {
+ mp->mflags |= PROT_EXEC;
+ if (mp->mapname && mp->mapname[0])
+ mapName = mp->mapname;
+ break;
+ }
+ }
+
+ // Find the dynsym section and record all symbols
+ char *base = (char*) ehdr;
+ ELF_SHDR *shdr = (ELF_SHDR*) (base + ehdr->e_shoff);
+ int i;
+
+#if 0
+ TprintfT (DBG_LT2, "process_vsyscall_page: ehdr: EI_CLASS=%lld EI_DATA=%lld EI_OSABI=%lld e_type=%lld e_machine=%lld e_version=%lld\n"
+ " e_entry =0x%016llx %10lld e_phoff =0x%016llx %10lld\n"
+ " e_shoff =0x%016llx %10lld e_flags =0x%016llx %10lld\n"
+ " e_ehsize =0x%016llx %10lld e_phentsize =0x%016llx %10lld\n"
+ " e_phnum =0x%016llx %10lld e_shentsize =0x%016llx %10lld\n"
+ " e_shnum =0x%016llx %10lld e_shstrndx =0x%016llx %10lld\n",
+ (long long) ehdr->e_ident[EI_CLASS], (long long) ehdr->e_ident[EI_DATA], (long long) ehdr->e_ident[EI_OSABI],
+ (long long) ehdr->e_type, (long long) ehdr->e_machine, (long long) ehdr->e_version,
+ (long long) ehdr->e_entry, (long long) ehdr->e_entry,
+ (long long) ehdr->e_phoff, (long long) ehdr->e_phoff,
+ (long long) ehdr->e_shoff, (long long) ehdr->e_shoff,
+ (long long) ehdr->e_flags, (long long) ehdr->e_flags,
+ (long long) ehdr->e_ehsize, (long long) ehdr->e_ehsize,
+ (long long) ehdr->e_phentsize, (long long) ehdr->e_phentsize,
+ (long long) ehdr->e_phnum, (long long) ehdr->e_phnum,
+ (long long) ehdr->e_shentsize, (long long) ehdr->e_shentsize,
+ (long long) ehdr->e_shnum, (long long) ehdr->e_shnum,
+ (long long) ehdr->e_shstrndx, (long long) ehdr->e_shstrndx);
+ for (i = 1; i < ehdr->e_shnum; i++)
+ {
+ TprintfT (DBG_LT2, "process_vsyscall_page: SECTION=%d sh_name=%lld '%s'\n"
+ " sh_type =0x%016llx %10lld\n"
+ " sh_flags =0x%016llx %10lld\n"
+ " sh_addr =0x%016llx %10lld\n"
+ " sh_offset =0x%016llx %10lld\n"
+ " sh_size =0x%016llx %10lld\n"
+ " sh_link =0x%016llx %10lld\n"
+ " sh_info =0x%016llx %10lld\n"
+ " sh_addralign =0x%016llx %10lld\n"
+ " sh_entsize =0x%016llx %10lld\n",
+ i, (long long) shdr[i].sh_name, base + shdr[ehdr->e_shstrndx].sh_offset + shdr[i].sh_name,
+ (long long) shdr[i].sh_type, (long long) shdr[i].sh_type,
+ (long long) shdr[i].sh_flags, (long long) shdr[i].sh_flags,
+ (long long) shdr[i].sh_addr, (long long) shdr[i].sh_addr,
+ (long long) shdr[i].sh_offset, (long long) shdr[i].sh_offset,
+ (long long) shdr[i].sh_size, (long long) shdr[i].sh_size,
+ (long long) shdr[i].sh_link, (long long) shdr[i].sh_link,
+ (long long) shdr[i].sh_info, (long long) shdr[i].sh_info,
+ (long long) shdr[i].sh_addralign, (long long) shdr[i].sh_addralign,
+ (long long) shdr[i].sh_entsize, (long long) shdr[i].sh_entsize);
+ }
+#endif
+
+ int dynSec = -1;
+ for (i = 1; i < ehdr->e_shnum; i++)
+ if (shdr[i].sh_type == SHT_DYNSYM)
+ {
+ dynSec = i;
+ break;
+ }
+ if (dynSec != -1)
+ {
+ char *symbase = base + shdr[shdr[dynSec].sh_link].sh_offset;
+ ELF_SYM *symbols = (ELF_SYM*) (base + shdr[dynSec].sh_offset);
+ int nextSec = 0;
+ int n = shdr[dynSec].sh_size / shdr[dynSec].sh_entsize;
+ for (i = 0; i < n; i++)
+ {
+ ELF_SYM *sym = symbols + i;
+ TprintfT (DBG_LT2, "process_vsyscall_page: symbol=%d st_name=%lld '%s'\n"
+ " st_size = 0x%016llx %10lld\n"
+ " st_value = 0x%016llx %10lld\n"
+ " st_shndx = 0x%016llx %10lld\n"
+ " st_info = 0x%016llx %10lld\n",
+ i, (long long) sym->st_name, symbase + sym->st_name,
+ (long long) sym->st_size, (long long) sym->st_size,
+ (long long) sym->st_value, (long long) sym->st_value,
+ (long long) sym->st_shndx, (long long) sym->st_shndx,
+ (long long) sym->st_info, (long long) sym->st_info);
+ if (sym->st_shndx <= 0 || sym->st_size <= 0 ||
+ ELF_ST_BIND (sym->st_info) != STB_GLOBAL || ELF_ST_TYPE (sym->st_info) != STT_FUNC)
+ continue;
+ if (nextSec == 0)
+ nextSec = sym->st_shndx;
+ else if (nextSec > sym->st_shndx)
+ nextSec = sym->st_shndx;
+ }
+ if (nextSec == 0)
+ ehdr = NULL;
+
+ while (nextSec != 0)
+ {
+ int curSec = nextSec;
+ char *bgn = base + shdr[curSec].sh_offset;
+ char *end = bgn + shdr[curSec].sh_size;
+ for (i = 0; i < n; i++)
+ {
+ ELF_SYM *sym = symbols + i;
+ if (sym->st_shndx <= 0 || sym->st_size <= 0 ||
+ ELF_ST_BIND (sym->st_info) != STB_GLOBAL || ELF_ST_TYPE (sym->st_info) != STT_FUNC)
+ continue;
+ if (sym->st_shndx > curSec)
+ {
+ if (nextSec == curSec)
+ nextSec = sym->st_shndx;
+ else if (nextSec > sym->st_shndx)
+ nextSec = sym->st_shndx;
+ nextSec = sym->st_shndx;
+ continue;
+ }
+ if (sym->st_shndx != curSec)
+ continue;
+ long long st_delta = (sym->st_value >= shdr[sym->st_shndx].sh_addr) ?
+ (sym->st_value - shdr[sym->st_shndx].sh_addr) : -1;
+ char *st_value = bgn + st_delta;
+ if (st_delta >= 0 && st_value + sym->st_size <= end)
+ {
+ append_segment_record ("<event kind=\"map\" object=\"dynfunc\" name=\"%s\" "
+ "vaddr=\"0x%016lX\" size=\"%u\" funcname=\"%s\" />\n",
+ mapName, (void*) st_value, sym->st_size, symbase + sym->st_name);
+
+ TprintfT (DBG_LT2, "process_vsyscall_page: append_segment_record map dynfunc='%s' vaddr=%016lX size=%ld funcname='%s'\n",
+ mapName, (unsigned long) st_value,
+ (long) sym->st_size, symbase + sym->st_name);
+
+ /* now cache this for a subsequent experiment */
+ if (ndyn >= MAXDYN)
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">MAXDYN=%d</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_MAPCACHE, MAXDYN);
+ else
+ {
+ dynname [ndyn] = CALL_UTIL (libc_strdup)(mapName);
+ dynvaddr [ndyn] = (void *) st_value;
+ dynsize [ndyn] = (unsigned) sym->st_size;
+ dynfuncname[ndyn] = CALL_UTIL (libc_strdup)(symbase + sym->st_name);
+ TprintfT (DBG_LT2, "process_vsyscall_page: cached entry %d map function='%s' vaddr=0x%016lX size=%ld '%s'\n",
+ ndyn, dynname[ndyn], (unsigned long) dynvaddr[ndyn],
+ (long) dynsize[ndyn], dynfuncname[ndyn]);
+ ndyn++;
+ }
+ }
+ }
+ __collector_int_func_load (DFUNC_KERNEL, mapName, NULL,
+ (void*) (base + shdr[curSec].sh_offset), shdr[curSec].sh_size, 0, NULL);
+
+ /* now cache this function for a subsequent experiment */
+ if (nvsysfuncs >= MAXVSYSFUNCS)
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">MAXVSYSFUNCS=%d</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_MAPCACHE, MAXVSYSFUNCS);
+ else
+ {
+ sysfuncname[nvsysfuncs] = CALL_UTIL (libc_strdup)(mapName);
+ sysfuncvaddr[nvsysfuncs] = (unsigned long) (base + shdr[curSec].sh_offset);
+ sysfuncsize[nvsysfuncs] = (unsigned long) (shdr[curSec].sh_size);
+ TprintfT (DBG_LT2, "process_vsyscall_page: cached entry %d map function='%s' vaddr=0x%016lX size=%ld\n",
+ nvsysfuncs, sysfuncname[nvsysfuncs],
+ (unsigned long) sysfuncvaddr[nvsysfuncs],
+ (long) sysfuncsize[nvsysfuncs]);
+ nvsysfuncs++;
+ }
+ TprintfT (DBG_LT2, "process_vsyscall_page: collector_int_func_load='%s' vaddr=0x%016lX size=%ld\n",
+ mapName, (unsigned long) (base + shdr[curSec].sh_offset),
+ (long) shdr[curSec].sh_size);
+ if (curSec == nextSec)
+ break;
+ }
+ }
+ }
+
+#if WSIZE(32)
+ unsigned long vsysaddr = (unsigned long) 0xffffe000;
+#elif WSIZE(64)
+ unsigned long vsysaddr = (unsigned long) 0xffffffffff600000;
+#endif
+ // Make sure the vsyscall map has PROT_EXEC
+ MapInfo *mp;
+ for (mp = mmaps.next; mp; mp = mp->next)
+ {
+ TprintfT (DBG_LT2, "MapInfo: vaddr=0x%016llx [size=%lld] mflags=0x%llx offset=%lld pagesize=%lld\n"
+ " mapname='%s' filename='%s'\n",
+ (unsigned long long) mp->vaddr, (long long) mp->size,
+ (long long) mp->mflags, (long long) mp->offset, (long long) mp->pagesize,
+ mp->mapname ? mp->mapname : "NULL",
+ mp->filename ? mp->filename : "NULL");
+ if (vsysaddr == mp->vaddr)
+ mp->mflags |= PROT_EXEC;
+ if ((unsigned long) ehdr == (unsigned long) mp->vaddr)
+ continue;
+ if (__collector_strncmp (mp->mapname, "[vdso]", 6) == 0
+ || __collector_strncmp (mp->mapname, "[vsyscall]", 10) == 0)
+ {
+ /*
+ * On rubbia ( 2.6.9-5.ELsmp #1 SMP 32-bit ) access to ehdr causes SEGV.
+ * There doesn't seem to be a way to reliably determine the actual presence
+ * of the page: even when /proc reports it's there it can't be accessed.
+ * We will have to put up with <Unknown> on some Linuxes until this is resolved.
+ __collector_int_func_load(DFUNC_KERNEL, mp->mapname, NULL, (void*) mp->vaddr, mp->size, 0, NULL);
+ */
+ hrtime_t hrt = GETRELTIME ();
+ append_segment_record (
+ "<event kind=\"map\" object=\"function\" tstamp=\"%u.%09u\" "
+ "vaddr=\"0x%016lX\" size=\"%u\" name=\"%s\" />\n",
+ (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
+ (unsigned long) mp->vaddr, (unsigned) mp->size, mp->mapname);
+ TprintfT (DBG_LT2, "process_vsyscall_page: append_segment_record map function = %s, vaddr = 0x%016lX, size = %u\n",
+ mp->mapname, (unsigned long) mp->vaddr, (unsigned) mp->size);
+
+ /* now cache this function for a subsequent experiment */
+ if (nvsysfuncs >= MAXVSYSFUNCS)
+ __collector_log_write ("<event kind=\"%s\" id=\"%d\">MAXVSYSFUNCS=%d</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_MAPCACHE, MAXVSYSFUNCS);
+ else
+ {
+ sysfuncname[nvsysfuncs] = CALL_UTIL (libc_strdup)(mp->mapname);
+ sysfuncvaddr[nvsysfuncs] = mp->vaddr;
+ sysfuncsize[nvsysfuncs] = (unsigned long) mp->size;
+ TprintfT (DBG_LT2, "process_vsyscall_page: cached entry %d map function='%s' vaddr=0x%016lX size=%ld\n",
+ nvsysfuncs, sysfuncname[nvsysfuncs],
+ (unsigned long) sysfuncvaddr[nvsysfuncs],
+ (long) sysfuncsize[nvsysfuncs]);
+ nvsysfuncs++;
+
+ }
+ }
+ }
+}
+
+/*
+ * collector API for dynamic functions
+ */
+void collector_func_load () __attribute__ ((weak, alias ("__collector_func_load")));
+void
+__collector_func_load (char *name, char *alias, char *sourcename,
+ void *vaddr, int size, int lntsize, DT_lineno *lntable)
+{
+ __collector_int_func_load (DFUNC_API, name, sourcename,
+ vaddr, size, lntsize, lntable);
+}
+
+void collector_func_unload () __attribute__ ((weak, alias ("__collector_func_unload")));
+void
+__collector_func_unload (void *vaddr)
+{
+ __collector_int_func_unload (DFUNC_API, vaddr);
+}
+
+/* routines for handling dynamic functions */
+static void
+rwrite (int fd, void *buf, size_t nbyte)
+{
+ size_t left = nbyte;
+ size_t res;
+ char *ptr = (char*) buf;
+ while (left > 0)
+ {
+ res = CALL_UTIL (write)(fd, ptr, left);
+ if (res == -1)
+ {
+ TprintfT (0, "ERROR: rwrite(%s) failed: errno=%d\n", dyntext_fname, errno);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_DYNWRITE, errno, dyntext_fname);
+ return;
+ }
+ left -= res;
+ ptr += res;
+ }
+}
+
+void
+__collector_int_func_load (dfunc_mode_t mode, char *name, char *sourcename,
+ void *vaddr, int size, int lntsize, DT_lineno *lntable)
+{
+ char name_buf[32];
+ int slen;
+ static char pad[16];
+ int padn;
+ if (!mmap_initted)
+ return;
+ hrtime_t hrt = GETRELTIME ();
+
+ if (name == NULL)
+ {
+ /* generate a name based on vaddr */
+ CALL_UTIL (snprintf)(name_buf, sizeof (name_buf), "0x%lx", (unsigned long) vaddr);
+ name = name_buf;
+ }
+
+ switch (mode)
+ {
+ case DFUNC_API:
+ case DFUNC_KERNEL:
+ append_segment_record ("<event kind=\"map\" object=\"function\" tstamp=\"%u.%09u\" "
+ "vaddr=\"0x%016lX\" size=\"%u\" name=\"%s\" />\n",
+ (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
+ (unsigned long) vaddr, (unsigned) size, name);
+ break;
+ case DFUNC_JAVA:
+ append_segment_record ("<event kind=\"map\" object=\"jcm\" tstamp=\"%u.%09u\" "
+ "vaddr=\"0x%016lX\" size=\"%u\" methodId=\"%s\" />\n",
+ (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC),
+ (unsigned long) vaddr, (unsigned) size, name);
+ break;
+ default:
+ return;
+ }
+
+ /* 21275311 Unwind failure in native stack for java application running on jdk8 on x86
+ * Check:
+ * - function starts in a known segment (base1 != 0)
+ * - function ends in the same segment (base1==base2 && end1==end2)
+ * If not, then call update_map_segments().
+ */
+ unsigned long base1, end1, base2, end2;
+ __collector_check_segment ((unsigned long) vaddr, &base1, &end1, 0);
+ if (base1)
+ __collector_check_segment (((unsigned long) vaddr)+((unsigned long) size), &base2, &end2, 0);
+ if (base1 == 0 || base1 != base2 || end1 != end2)
+ __collector_ext_update_map_segments ();
+
+ /* Write a copy of actual code to the "dyntext" file */
+ DT_header dt_hdr;
+ dt_hdr.type = DT_HEADER;
+ dt_hdr.size = sizeof (dt_hdr);
+ dt_hdr.time = hrt;
+ unsigned long t = (unsigned long) vaddr; /* to suppress a warning from gcc */
+ dt_hdr.vaddr = (uint64_t) t;
+
+ DT_code dt_code;
+ dt_code.type = DT_CODE;
+ void *code = vaddr;
+ if (vaddr != NULL && size > 0)
+ {
+ dt_code.size = sizeof (dt_code) + ((size + 0xf) & ~0xf);
+ if (mode == DFUNC_KERNEL)
+ {
+ /* Some Linuxes don't accept vaddrs from the vsyscall
+ * page in write(). Make a copy.
+ */
+ code = alloca (size);
+ __collector_memcpy (code, vaddr, size);
+ }
+ }
+ else
+ dt_code.size = 0;
+
+ DT_srcfile dt_src;
+ dt_src.type = DT_SRCFILE;
+ if (sourcename)
+ {
+ slen = CALL_UTIL (strlen)(sourcename) + 1;
+ dt_src.size = slen ? sizeof (dt_src) + ((slen + 0xf) & ~0xf) : 0;
+ }
+ else
+ {
+ slen = 0;
+ dt_src.size = 0;
+ }
+
+ DT_ltable dt_ltbl;
+ dt_ltbl.type = DT_LTABLE;
+ if (lntable != NULL && lntsize > 0)
+ dt_ltbl.size = sizeof (dt_ltbl) + lntsize * sizeof (DT_lineno);
+ else
+ dt_ltbl.size = 0;
+
+ int fd = CALL_UTIL (open)(dyntext_fname, O_RDWR | O_APPEND);
+ if (fd == -1)
+ {
+ TprintfT (0, "ERROR: __collector_int_func_load: open(%s) failed: errno=%d\n",
+ dyntext_fname, errno);
+ (void) __collector_log_write ("<event kind=\"%s\" id=\"%d\" ec=\"%d\">%s</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_DYNOPEN, errno, dyntext_fname);
+ return;
+ }
+
+ /* Lock the whole file */
+ __collector_mutex_lock (&dyntext_lock);
+ rwrite (fd, &dt_hdr, sizeof (dt_hdr));
+ if (dt_code.size)
+ {
+ padn = dt_code.size - sizeof (dt_code) - size;
+ rwrite (fd, &dt_code, sizeof (dt_code));
+ rwrite (fd, code, size);
+ rwrite (fd, &pad, padn);
+ }
+ if (dt_src.size)
+ {
+ padn = dt_src.size - sizeof (dt_src) - slen;
+ rwrite (fd, &dt_src, sizeof (dt_src));
+ rwrite (fd, sourcename, slen);
+ rwrite (fd, &pad, padn);
+ }
+ if (dt_ltbl.size)
+ {
+ rwrite (fd, &dt_ltbl, sizeof (dt_ltbl));
+ rwrite (fd, lntable, dt_ltbl.size - sizeof (dt_ltbl));
+ }
+
+ /* Unlock the file */
+ __collector_mutex_unlock( &dyntext_lock );
+ CALL_UTIL(close( fd ) );
+}
+
+void
+__collector_int_func_unload (dfunc_mode_t mode, void *vaddr)
+{
+ if (!mmap_initted)
+ return;
+ hrtime_t hrt = GETRELTIME ();
+ if (mode == DFUNC_API)
+ append_segment_record ("<event kind=\"unmap\" tstamp=\"%u.%09u\" vaddr=\"0x%016lX\"/>\n",
+ (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC), (unsigned long) vaddr);
+ else if (mode == DFUNC_JAVA)
+ /* note that the "vaddr" is really a method id, not an address */
+ append_segment_record ("<event kind=\"unmap\" tstamp=\"%u.%09u\" methodId=\"0x%016lX\"/>\n",
+ (unsigned) (hrt / NANOSEC), (unsigned) (hrt % NANOSEC), (unsigned long) vaddr);
+ else
+ return;
+}
+
+/*
+ * int init_mmap_intf()
+ * Set up interposition (if not already done).
+ */
+static int
+init_mmap_intf ()
+{
+ if (__collector_dlsym_guard)
+ return 1;
+ void *dlflag;
+ __real_mmap = (void*(*)(void* addr, size_t len, int prot, int flags,
+ int fildes, off_t off))dlsym (RTLD_NEXT, SYS_MMAP_NAME);
+ if (__real_mmap == NULL)
+ {
+
+ /* We are probably dlopened after libthread/libc,
+ * try to search in the previously loaded objects
+ */
+ __real_mmap = (void*(*)(void* addr, size_t len, int prot, int flags,
+ int fildes, off_t off))dlsym (RTLD_DEFAULT, SYS_MMAP_NAME);
+ if (__real_mmap == NULL)
+ {
+ TprintfT (0, "ERROR: collector real mmap not found\n");
+ return 1;
+ }
+ TprintfT (DBG_LT2, "collector real mmap found with RTLD_DEFAULT\n");
+ dlflag = RTLD_DEFAULT;
+ }
+ else
+ {
+ TprintfT (DBG_LT2, "collector real mmap found with RTLD_NEXT\n");
+ dlflag = RTLD_NEXT;
+ }
+
+ TprintfT (DBG_LT2, "init_mmap_intf() @%p __real_mmap\n", __real_mmap);
+ __real_mmap64 = (void*(*)(void *, size_t, int, int, int, off64_t))
+ dlsym (dlflag, SYS_MMAP64_NAME);
+ TprintfT (DBG_LT2, "init_mmap_intf() @%p __real_mmap64\n", __real_mmap64);
+ __real_munmap = (int(*)(void *, size_t)) dlsym (dlflag, SYS_MUNMAP_NAME);
+ TprintfT (DBG_LT2, "init_mmap_intf() @%p __real_munmap\n", __real_munmap);
+
+ // dlopen/dlmopen/dlclose are in libdl.so
+ __real_dlopen = (void*(*)(const char *, int))
+ dlvsym (dlflag, SYS_DLOPEN_NAME, SYS_DLOPEN_VERSION);
+ TprintfT (DBG_LT2, "init_mmap_intf() [%s] @%p __real_dlopen\n",
+ SYS_DLOPEN_VERSION, __real_dlopen);
+#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
+ __real_dlopen_2_1 = __real_dlopen;
+ __real_dlopen_2_0 = (void*(*)(const char *, int))
+ dlvsym (dlflag, SYS_DLOPEN_NAME, "GLIBC_2.0");
+#endif
+
+ __real_dlclose = (int(*)(void* handle))dlsym (dlflag, SYS_DLCLOSE_NAME);
+ TprintfT (DBG_LT2, "init_mmap_intf() @%p __real_dlclose\n", __real_dlclose);
+ TprintfT (DBG_LT2, "init_mmap_intf() done\n");
+
+ return 0;
+}
+
+/*------------------------------------------------------------- mmap */
+void *
+mmap (void *start, size_t length, int prot, int flags, int fd, off_t offset)
+{
+ int err = 0;
+ if (NULL_PTR (mmap))
+ err = init_mmap_intf ();
+ if (err)
+ return MAP_FAILED;
+
+ /* hrtime_t hrt = GETRELTIME(); */
+ void *ret = CALL_REAL (mmap)(start, length, prot, flags, fd, offset);
+
+ if (!CHCK_REENTRANCE && (ret != MAP_FAILED) && collector_heap_record != NULL)
+ {
+ PUSH_REENTRANCE;
+ /* write a separate record for mmap tracing */
+ collector_heap_record (MMAP_TRACE, length, ret);
+ POP_REENTRANCE;
+ }
+ TprintfT (DBG_LT2, "libcollector.mmap(%p, %ld, %d, %d, %d, 0x%lld) = %p\n",
+ start, (long) length, prot, flags, fd, (long long) offset, ret);
+ return ret;
+}
+
+/*------------------------------------------------------------- mmap64 */
+#if WSIZE(32) /* mmap64 only defined for non-64-bit */
+
+void *
+mmap64 (void *start, size_t length, int prot, int flags, int fd, off64_t offset)
+{
+ if (NULL_PTR (mmap64))
+ init_mmap_intf ();
+
+ /* hrtime_t hrt = GETRELTIME(); */
+ void *ret = CALL_REAL (mmap64)(start, length, prot, flags, fd, offset);
+ if (!CHCK_REENTRANCE && (ret != MAP_FAILED) && collector_heap_record != NULL)
+ {
+ PUSH_REENTRANCE;
+ /* write a separate record for mmap tracing */
+ collector_heap_record (MMAP_TRACE, length, ret);
+ POP_REENTRANCE;
+ }
+ TprintfT (DBG_LT2, "libcollector.mmap64(%p, %ld, %d, %d, %d, 0x%lld) = %p\n",
+ start, (long) length, prot, flags, fd, (long long) offset, ret);
+ return ret;
+}
+#endif /* WSIZE(32) */
+
+/*------------------------------------------------------------- munmap */
+int
+munmap (void *start, size_t length)
+{
+ if (NULL_PTR (munmap))
+ init_mmap_intf ();
+
+ /* hrtime_t hrt = GETRELTIME(); */
+ int rc = CALL_REAL (munmap)(start, length);
+ if (!CHCK_REENTRANCE && (rc == 0) && collector_heap_record != NULL)
+ {
+ PUSH_REENTRANCE;
+ /* write a separate record for mmap tracing */
+ collector_heap_record (MUNMAP_TRACE, length, start);
+ POP_REENTRANCE;
+ }
+ TprintfT (DBG_LT2, "libcollector.munmap(%p, %ld) = %d\n", start, (long) length, rc);
+ return rc;
+}
+
+
+/*------------------------------------------------------------- dlopen */
+// map interposed symbol versions
+#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
+
+static void *
+__collector_dlopen_symver (void*(real_dlopen) (), void *caller, const char *pathname, int mode);
+
+void *
+__collector_dlopen_2_1 (const char *pathname, int mode)
+{
+ if (NULL_PTR (dlopen))
+ init_mmap_intf ();
+ void *caller = __builtin_return_address (0); // must be called inside dlopen first layer interpostion
+ return __collector_dlopen_symver (CALL_REAL (dlopen_2_1), caller, pathname, mode);
+}
+
+void *
+__collector_dlopen_2_0 (const char *pathname, int mode)
+{
+ if (NULL_PTR (dlopen))
+ init_mmap_intf ();
+ void* caller = __builtin_return_address (0); // must be called inside dlopen first layer interpostion
+ return __collector_dlopen_symver (CALL_REAL (dlopen_2_0), caller, pathname, mode);
+}
+
+__asm__(".symver __collector_dlopen_2_1,dlopen@@GLIBC_2.1");
+__asm__(".symver __collector_dlopen_2_0,dlopen@GLIBC_2.0");
+
+#endif
+
+#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
+static void *
+__collector_dlopen_symver (void*(real_dlopen) (), void *caller, const char *pathname, int mode)
+#else
+void *
+dlopen (const char *pathname, int mode)
+#endif
+{
+ const char * real_pathname = pathname;
+ char new_pathname[MAXPATHLEN];
+ int origin_offset = 0;
+ TprintfT (DBG_LT2, "dlopen: pathname=%s, mode=%d\n", pathname ? pathname : "NULL", mode);
+ if (pathname && __collector_strStartWith (pathname, "$ORIGIN/") == 0)
+ origin_offset = 8;
+ else if (pathname && __collector_strStartWith (pathname, "${ORIGIN}/") == 0)
+ origin_offset = 10;
+ if (origin_offset)
+ {
+#if ! ((ARCH(Intel) && WSIZE(32)) || ARCH(SPARC))
+ // 'caller' is not passed as an argument
+ void * caller = __builtin_return_address (0); // must be called inside dlopen first layer interpostion
+#endif
+ Dl_info dl_info;
+ if (caller && dladdr (caller, &dl_info) != 0)
+ {
+ TprintfT (DBG_LT2, "dladdr(%p): %p fname=%s\n",
+ caller, dl_info.dli_fbase, dl_info.dli_fname);
+ new_pathname[0] = '\0';
+ const char *p = __collector_strrchr (dl_info.dli_fname, '/');
+ if (p)
+ __collector_strlcpy (new_pathname, dl_info.dli_fname,
+ (p - dl_info.dli_fname + 2) < MAXPATHLEN ? (p - dl_info.dli_fname + 2) : MAXPATHLEN);
+ __collector_strlcat (new_pathname, pathname + origin_offset, MAXPATHLEN - CALL_UTIL (strlen)(new_pathname));
+ real_pathname = new_pathname;
+ }
+ else
+ TprintfT (0, "ERROR: dladdr(%p): %s\n", caller, dlerror ());
+ }
+ if (NULL_PTR (dlopen))
+ init_mmap_intf ();
+ TprintfT (DBG_LT2, "libcollector.dlopen(%s,%d) interposing\n",
+ pathname ? pathname : "", mode);
+ void* ret = NULL;
+
+ // set guard for duration of handling dlopen, since want to ensure
+ // new mappings are resolved after the actual dlopen has occurred
+ PUSH_REENTRANCE;
+ hrtime_t hrt = GETRELTIME ();
+
+ if (real_pathname && !__collector_strchr (real_pathname, '/'))
+ { // got an unqualified name
+ // get caller and use its searchpath
+#if ! ((ARCH(Intel) && WSIZE(32)) || ARCH(SPARC))
+ void* caller = __builtin_return_address (0); // must be called inside dlopen
+#endif
+ if (caller)
+ {
+#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
+ ret = dlopen_searchpath_symver (real_dlopen, caller, real_pathname, mode);
+#else
+ ret = dlopen_searchpath (caller, real_pathname, mode);
+#endif
+ }
+ }
+
+ if (!ret)
+ {
+#if (ARCH(Intel) && WSIZE(32)) || ARCH(SPARC)
+ ret = (real_dlopen) (real_pathname, mode);
+#else
+ ret = CALL_REAL (dlopen)(real_pathname, mode);
+#endif
+ }
+ TprintfT (DBG_LT2, "libcollector -- dlopen(%s) returning %p\n", pathname, ret);
+
+ /* Don't call update if dlopen failed: preserve dlerror() */
+ if (ret && (mmap_mode > 0) && !(mode & RTLD_NOLOAD))
+ update_map_segments (hrt, 1);
+ TprintfT (DBG_LT2, "libcollector -- dlopen(%s) returning %p\n", pathname, ret);
+ POP_REENTRANCE;
+ return ret;
+}
+
+/*------------------------------------------------------------- dlclose */
+int
+dlclose (void *handle)
+{
+ if (NULL_PTR (dlclose))
+ init_mmap_intf ();
+ TprintfT (DBG_LT2, "__collector_dlclose(%p) entered\n", handle);
+ hrtime_t hrt = GETRELTIME ();
+ if (!CHCK_REENTRANCE)
+ {
+ PUSH_REENTRANCE;
+ update_map_segments (hrt, 1);
+ POP_REENTRANCE;
+ hrt = GETRELTIME ();
+ }
+ int ret = CALL_REAL (dlclose)(handle);
+
+ /* Don't call update if dlclose failed: preserve dlerror() */
+ if (!ret && !CHCK_REENTRANCE)
+ {
+ PUSH_REENTRANCE;
+ update_map_segments (hrt, 1);
+ POP_REENTRANCE;
+ }
+ TprintfT (DBG_LT2, "__collector_dlclose(%p) returning %d\n", handle, ret);
+ return ret;
+}
diff --git a/gprofng/libcollector/profile.c b/gprofng/libcollector/profile.c
new file mode 100644
index 0000000..996d3f0
--- /dev/null
+++ b/gprofng/libcollector/profile.c
@@ -0,0 +1,287 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/*
+ * Profile handling
+ *
+ * Note: SIGPROF signal-handling and interval timer (once exclusive to
+ * profile handling) are now common services provided by the dispatcher.
+ */
+
+#include "config.h"
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+#include "gp-defs.h"
+#include "collector_module.h"
+#include "gp-experiment.h"
+#include "data_pckts.h"
+#include "libcol_util.h"
+#include "hwprofile.h"
+#include "tsd.h"
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+
+static int init_interface (CollectorInterface*);
+static int open_experiment (const char *);
+static int start_data_collection (void);
+static int stop_data_collection (void);
+static int close_experiment (void);
+static int detach_experiment (void);
+
+static ModuleInterface module_interface ={
+ SP_PROFILE_FILE, /* description */
+ init_interface, /* initInterface */
+ open_experiment, /* openExperiment */
+ start_data_collection, /* startDataCollection */
+ stop_data_collection, /* stopDataCollection */
+ close_experiment, /* closeExperiment */
+ detach_experiment /* detachExperiment (fork child) */
+};
+
+static CollectorInterface *collector_interface = NULL;
+static int prof_mode = 0;
+static CollectorModule prof_hndl = COLLECTOR_MODULE_ERR;
+static unsigned prof_key = COLLECTOR_TSD_INVALID_KEY;
+
+typedef struct ClockPacket
+{ /* clock profiling packet */
+ CM_Packet comm;
+ pthread_t lwp_id;
+ pthread_t thr_id;
+ uint32_t cpu_id;
+ hrtime_t tstamp __attribute__ ((packed));
+ uint64_t frinfo __attribute__ ((packed));
+ int mstate; /* kernel microstate */
+ int nticks; /* number of ticks in that state */
+} ClockPacket;
+
+/* XXX should be able to use local types */
+#define CLOCK_TYPE OPROF_PCKT
+
+#define CHCK_REENTRANCE(x) ( !prof_mode || ((x) = collector_interface->getKey( prof_key )) == NULL || (*(x) != 0) )
+#define PUSH_REENTRANCE(x) ((*(x))++)
+#define POP_REENTRANCE(x) ((*(x))--)
+
+#ifdef DEBUG
+#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
+#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
+#else
+#define Tprintf(...)
+#define TprintfT(...)
+#endif
+
+static void init_module () __attribute__ ((constructor));
+
+static void
+init_module ()
+{
+ __collector_dlsym_guard = 1;
+ RegModuleFunc reg_module = (RegModuleFunc) dlsym (RTLD_DEFAULT, "__collector_register_module");
+ __collector_dlsym_guard = 0;
+ if (reg_module == NULL)
+ {
+ TprintfT (0, "clockprof: init_module FAILED -- reg_module = NULL\n");
+ return;
+ }
+ prof_hndl = reg_module (&module_interface);
+ if (prof_hndl == COLLECTOR_MODULE_ERR && collector_interface != NULL)
+ {
+ Tprintf (0, "clockprof: ERROR: handle not created.\n");
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n", SP_JCMD_CERROR, COL_ERROR_PROFINIT);
+ }
+ TprintfT (0, "clockprof: init_module, prof_hndl = %d\n", prof_hndl);
+ return;
+}
+
+static int
+init_interface (CollectorInterface *_collector_interface)
+{
+ collector_interface = _collector_interface;
+ return COL_ERROR_NONE;
+}
+
+static int
+open_experiment (const char *exp)
+{
+ if (collector_interface == NULL)
+ {
+ Tprintf (0, "clockprof: ERROR: collector_interface is null.\n");
+ return COL_ERROR_PROFINIT;
+ }
+ const char *params = collector_interface->getParams ();
+ while (params)
+ {
+ if (__collector_strStartWith (params, "p:") == 0)
+ {
+ params += 2;
+ break;
+ }
+ while (*params != 0 && *params != ';')
+ params++;
+ if (*params == 0)
+ params = NULL;
+ else
+ params++;
+ }
+ if (params == NULL) /* Clock profiling not specified */
+ return COL_ERROR_PROFINIT;
+ TprintfT (0, "clockprof: open_experiment %s -- %s\n", exp, params);
+ int prof_interval = CALL_UTIL (strtol)(params, NULL, 0);
+ prof_key = collector_interface->createKey (sizeof ( int), NULL, NULL);
+ if (prof_key == (unsigned) - 1)
+ {
+ Tprintf (0, "clockprof: ERROR: TSD key create failed.\n");
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n", SP_JCMD_CERROR, COL_ERROR_PROFINIT);
+ return COL_ERROR_PROFINIT;
+ }
+
+ /* set dispatcher interval timer period used for all timed activities */
+ int prof_interval_actual = __collector_ext_itimer_set (prof_interval);
+ TprintfT (0, "clockprof: open_experiment(): __collector_ext_itimer_set (actual period=%d, req_period=%d)\n",
+ prof_interval_actual, prof_interval);
+ if (prof_interval_actual <= 0)
+ {
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">itimer could not be set</event>\n", SP_JCMD_CERROR, COL_ERROR_PROFINIT);
+ return COL_ERROR_PROFINIT;
+ }
+ if ((prof_interval_actual >= (prof_interval + prof_interval / 10)) ||
+ (prof_interval_actual <= (prof_interval - prof_interval / 10)))
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n", SP_JCMD_CWARN, COL_WARN_PROFRND, prof_interval, prof_interval_actual);
+ else if (prof_interval_actual != prof_interval)
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">%d -> %d</event>\n", SP_JCMD_COMMENT, COL_WARN_PROFRND, prof_interval, prof_interval_actual);
+ prof_interval = prof_interval_actual;
+ collector_interface->writeLog ("<profile name=\"%s\" ptimer=\"%d\" numstates=\"%d\">\n",
+ SP_JCMD_PROFILE, prof_interval, LMS_MAGIC_ID_LINUX);
+ collector_interface->writeLog (" <profdata fname=\"%s\"/>\n",
+ module_interface.description);
+
+ /* Record Profile packet description */
+ ClockPacket *cp = NULL;
+ collector_interface->writeLog (" <profpckt kind=\"%d\" uname=\"" STXT ("Clock profiling data") "\">\n", CLOCK_TYPE);
+ collector_interface->writeLog (" <field name=\"LWPID\" uname=\"" STXT ("Lightweight process id") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &cp->lwp_id, sizeof (cp->lwp_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"THRID\" uname=\"" STXT ("Thread number") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &cp->thr_id, sizeof (cp->thr_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"CPUID\" uname=\"" STXT ("CPU id") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &cp->cpu_id, sizeof (cp->cpu_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"" STXT ("High resolution timestamp") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &cp->tstamp, sizeof (cp->tstamp) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
+ &cp->frinfo, sizeof (cp->frinfo) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"MSTATE\" uname=\"" STXT ("Thread state") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &cp->mstate, sizeof (cp->mstate) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"NTICK\" uname=\"" STXT ("Duration") "\" offset=\"%d\" type=\"%s\"/>\n",
+ &cp->nticks, sizeof (cp->nticks) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" </profpckt>\n");
+ collector_interface->writeLog ("</profile>\n");
+ return COL_ERROR_NONE;
+}
+
+static int
+start_data_collection (void)
+{
+ TprintfT (0, "clockprof: start_data_collection\n");
+ prof_mode = 1;
+ return 0;
+}
+
+static int
+stop_data_collection (void)
+{
+ prof_mode = 0;
+ TprintfT (0, "clockprof: stop_data_collection\n");
+ return 0;
+}
+
+static int
+close_experiment (void)
+{
+ prof_mode = 0;
+ prof_key = COLLECTOR_TSD_INVALID_KEY;
+ TprintfT (0, "clockprof: close_experiment\n");
+ return 0;
+}
+
+/* fork child. Clean up state but don't write to experiment */
+static int
+detach_experiment (void)
+{
+ prof_mode = 0;
+ prof_key = COLLECTOR_TSD_INVALID_KEY;
+ TprintfT (0, "clockprof: detach_experiment\n");
+ return 0;
+}
+
+/*
+ * void collector_lost_profile_context
+ * Placeholder/marker function used when profiling given NULL context.
+ */
+void
+__collector_lost_profile_context (void) { }
+
+/*
+ * void __collector_ext_profile_handler( siginfo_t *info, ucontext_t *context )
+ * Handle real profile events to collect profile data.
+ */
+void
+__collector_ext_profile_handler (siginfo_t *info, ucontext_t *context)
+{
+ int *guard;
+ if (!prof_mode) /* sigprof timer running only because hwprofile.c needs it */
+ return;
+ if (CHCK_REENTRANCE (guard))
+ {
+ TprintfT (0, "__collector_ext_profile_handler: ERROR: prof_mode=%d guard=%d!\n",
+ prof_mode, guard ? *guard : -2);
+ return;
+ }
+ PUSH_REENTRANCE (guard);
+ TprintfT (DBG_LT3, "__collector_ext_profile_handler\n");
+ ucontext_t uctxmem;
+ if (context == NULL)
+ {
+ /* assume this case is rare, and accept overhead of creating dummy_uc */
+ TprintfT (0, "collector_profile_handler: ERROR: got NULL context!\n");
+ context = &uctxmem;
+ getcontext (context); /* initialize dummy context */
+ SETFUNCTIONCONTEXT (context, &__collector_lost_profile_context);
+ }
+ ClockPacket pckt;
+ CALL_UTIL (memset)(&pckt, 0, sizeof ( pckt));
+ pckt.comm.tsize = sizeof ( pckt);
+ pckt.comm.type = CLOCK_TYPE;
+ pckt.lwp_id = __collector_lwp_self ();
+ pckt.thr_id = __collector_thr_self ();
+ pckt.cpu_id = CALL_UTIL (getcpuid)();
+ pckt.tstamp = collector_interface->getHiResTime ();
+ pckt.frinfo = collector_interface->getFrameInfo (COLLECTOR_MODULE_ERR, pckt.tstamp, FRINFO_FROM_UC, context);
+ pckt.mstate = LMS_LINUX_CPU;
+ pckt.nticks = 1;
+ collector_interface->writeDataPacket (prof_hndl, (CM_Packet*) & pckt);
+ POP_REENTRANCE (guard);
+}
diff --git a/gprofng/libcollector/synctrace.c b/gprofng/libcollector/synctrace.c
new file mode 100644
index 0000000..401c8f2
--- /dev/null
+++ b/gprofng/libcollector/synctrace.c
@@ -0,0 +1,1064 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/*
+ * Synchronization events
+ */
+#include "config.h"
+#include <alloca.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <semaphore.h> /* sem_wait() */
+#include <stdlib.h>
+#include <string.h>
+#include <sys/param.h>
+#include <pthread.h>
+
+#include "gp-defs.h"
+#include "collector_module.h"
+#include "gp-experiment.h"
+#include "data_pckts.h"
+#include "i18n.h"
+#include "tsd.h"
+#include "cc_libcollector.h"
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LTT 0 // for interposition on GLIBC functions
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+
+/* define the packet that will be written out */
+typedef struct Sync_packet
+{ /* Synchronization delay tracing packet */
+ Common_packet comm;
+ hrtime_t requested; /* time of synchronization request */
+ Vaddr_type objp; /* vaddr of synchronization object */
+} Sync_packet;
+
+static int open_experiment (const char *);
+static int start_data_collection (void);
+static int stop_data_collection (void);
+static int close_experiment (void);
+static int detach_experiment (void);
+static int init_thread_intf ();
+static int sync_calibrate ();
+
+static ModuleInterface module_interface ={
+ SP_SYNCTRACE_FILE, /* description */
+ NULL, /* initInterface */
+ open_experiment, /* openExperiment */
+ start_data_collection, /* startDataCollection */
+ stop_data_collection, /* stopDataCollection */
+ close_experiment, /* closeExperiment */
+ detach_experiment /* detachExperiment (fork child) */
+};
+
+static CollectorInterface *collector_interface = NULL;
+static int sync_mode = 0;
+static long sync_scope = 0;
+static int sync_native = 0;
+static int sync_java = 0;
+static CollectorModule sync_hndl = COLLECTOR_MODULE_ERR;
+static unsigned sync_key = COLLECTOR_TSD_INVALID_KEY;
+static long sync_threshold = -1; /* calibrate the value */
+static int init_thread_intf_started = 0;
+static int init_thread_intf_finished = 0;
+
+#define CHCK_NREENTRANCE(x) (!sync_native || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) != 0))
+#define RECHCK_NREENTRANCE(x) (!sync_native || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) == 0))
+#define CHCK_JREENTRANCE(x) (!sync_java || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) != 0))
+#define RECHCK_JREENTRANCE(x) (!sync_java || !sync_mode || ((x) = collector_interface->getKey( sync_key )) == NULL || (*(x) == 0))
+#define PUSH_REENTRANCE(x) ((*(x))++)
+#define POP_REENTRANCE(x) ((*(x))--)
+
+#define CALL_REAL(x) (*(int(*)())__real_##x)
+#define NULL_PTR(x) ( __real_##x == NULL )
+#define gethrtime collector_interface->getHiResTime
+
+#ifdef DEBUG
+#define Tprintf(...) if (collector_interface) collector_interface->writeDebugInfo( 0, __VA_ARGS__ )
+#define TprintfT(...) if (collector_interface) collector_interface->writeDebugInfo( 1, __VA_ARGS__ )
+#else
+#define Tprintf(...)
+#define TprintfT(...)
+#endif
+
+/*
+ * In most cases, the functions which require interposition are implemented as
+ * weak symbols corresponding to an associated internal function named with a
+ * leading underscore: e.g., mutex_lock() is simply an alias for _mutex_lock().
+ * For the wait functions, however, the published version (used by applications)
+ * is distinct from the internal version (used by system libraries), i.e.,
+ * cond_wait() is an alias for _cond_wait_cancel() rather than _cond_wait().
+ */
+static void *__real_strtol = NULL;
+static void *__real_fprintf = NULL;
+static void *__real___collector_jprofile_enable_synctrace = NULL;
+static void *__real_pthread_mutex_lock = NULL;
+static void *__real_pthread_mutex_unlock = NULL; /* not interposed, used in calibrate */
+static void *__real_pthread_cond_wait = NULL;
+static void *__real_pthread_cond_timedwait = NULL;
+static void *__real_pthread_join = NULL;
+static void *__real_sem_wait = NULL;
+static void *__real_pthread_cond_wait_2_3_2 = NULL;
+static void *__real_pthread_cond_timedwait_2_3_2 = NULL;
+
+#if WSIZE(32)
+static void *__real_sem_wait_2_1 = NULL;
+static void *__real_sem_wait_2_0 = NULL;
+static void *__real_pthread_cond_wait_2_0 = NULL;
+static void *__real_pthread_cond_timedwait_2_0 = NULL;
+#elif WSIZE(64)
+#if ARCH(Intel)
+static void *__real_pthread_cond_wait_2_2_5 = NULL;
+static void *__real_pthread_cond_timedwait_2_2_5 = NULL;
+#elif ARCH(SPARC)
+static void *__real_pthread_cond_wait_2_2 = NULL;
+static void *__real_pthread_cond_timedwait_2_2 = NULL;
+#endif /* ARCH() */
+#endif /* WSIZE() */
+
+static void
+collector_memset (void *s, int c, size_t n)
+{
+ unsigned char *s1 = s;
+ while (n--)
+ *s1++ = (unsigned char) c;
+}
+
+void
+__collector_module_init (CollectorInterface *_collector_interface)
+{
+ if (_collector_interface == NULL)
+ return;
+ collector_interface = _collector_interface;
+ TprintfT (0, "synctrace: __collector_module_init\n");
+ sync_hndl = collector_interface->registerModule (&module_interface);
+
+ /* Initialize next module */
+ ModuleInitFunc next_init = (ModuleInitFunc) dlsym (RTLD_NEXT, "__collector_module_init");
+ if (next_init != NULL)
+ next_init (_collector_interface);
+}
+
+static int
+open_experiment (const char *exp)
+{
+ long thresh = 0;
+ if (init_thread_intf_finished == 0)
+ init_thread_intf ();
+ if (collector_interface == NULL)
+ {
+ Tprintf (0, "synctrace: collector_interface is null.\n");
+ return COL_ERROR_SYNCINIT;
+ }
+ if (sync_hndl == COLLECTOR_MODULE_ERR)
+ {
+ Tprintf (0, "synctrace: handle create failed.\n");
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">data handle not created</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_SYNCINIT);
+ return COL_ERROR_SYNCINIT;
+ }
+ TprintfT (0, "synctrace: open_experiment %s\n", exp);
+
+ char *params = (char *) collector_interface->getParams ();
+ while (params)
+ {
+ if ((params[0] == 's') && (params[1] == ':'))
+ {
+ char *ptr = params + 2;
+ Tprintf (DBG_LT1, "synctrace: open_experiment s: parameter = %s\n", ptr);
+ while (*ptr != ',' && *ptr != ';')
+ ptr++;
+ sync_scope = 0;
+ if (*ptr == ',')
+ {
+ sync_scope = CALL_REAL (strtol) (ptr + 1, NULL, 0);
+ switch (sync_scope)
+ {
+ case 1:
+ sync_java = 0;
+ sync_native = 1;
+ break;
+ case 2:
+ sync_java = 1;
+ sync_native = 0;
+ break;
+ default:
+ case 3:
+ sync_native = 1;
+ sync_java = 1;
+ break;
+ }
+ Tprintf (0, "\tsynctrace: sync_scope found as %ld\n", sync_scope);
+ }
+ else
+ {
+ /* the old-style descriptor, without scope */
+ /* if there was no comma, use the old default */
+ sync_scope = 3;
+ sync_java = 1;
+ sync_native = 1;
+ Tprintf (0, "\tsynctrace: sync_scope not found set to %ld\n", sync_scope);
+ }
+ if (__real___collector_jprofile_enable_synctrace == NULL)
+ sync_java = 0;
+ thresh = CALL_REAL (strtol)(params + 2, NULL, 0);
+ break; /* from the loop to find the "s:thresh,scope" entry */
+ }
+ else
+ params++;
+ }
+ if (params == NULL) /* Sync data collection not specified */
+ return COL_ERROR_SYNCINIT;
+ if (thresh < 0) /* calibrate the threshold, keep it as a negative number */
+ thresh = -sync_calibrate ();
+
+ sync_key = collector_interface->createKey (sizeof ( int), NULL, NULL);
+ if (sync_key == (unsigned) - 1)
+ {
+ Tprintf (0, "synctrace: TSD key create failed.\n");
+ collector_interface->writeLog ("<event kind=\"%s\" id=\"%d\">TSD key not created</event>\n",
+ SP_JCMD_CERROR, COL_ERROR_SYNCINIT);
+ return COL_ERROR_SYNCINIT;
+ }
+ /* if Java synctrace was requested, tell the jprofile module */
+ if (sync_java)
+ {
+ TprintfT (0, "synctrace: enabling Java synctrace\n");
+ CALL_REAL (__collector_jprofile_enable_synctrace)();
+ }
+ collector_interface->writeLog ("<profile name=\"%s\" threshold=\"%ld\" scope=\"%ld\">\n",
+ SP_JCMD_SYNCTRACE, thresh, sync_scope);
+ collector_interface->writeLog (" <profdata fname=\"%s\"/>\n",
+ module_interface.description);
+ /* Record Sync_packet description */
+ Sync_packet *pp = NULL;
+ collector_interface->writeLog (" <profpckt kind=\"%d\" uname=\"Synchronization tracing data\">\n", SYNC_PCKT);
+ collector_interface->writeLog (" <field name=\"LWPID\" uname=\"Lightweight process id\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.lwp_id, sizeof (pp->comm.lwp_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"THRID\" uname=\"Thread number\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.thr_id, sizeof (pp->comm.thr_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"CPUID\" uname=\"CPU id\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.cpu_id, sizeof (pp->comm.cpu_id) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"TSTAMP\" uname=\"High resolution timestamp\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.tstamp, sizeof (pp->comm.tstamp) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"FRINFO\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->comm.frinfo, sizeof (pp->comm.frinfo) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"SRQST\" uname=\"Synchronization start time\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->requested, sizeof (pp->requested) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" <field name=\"SOBJ\" uname=\"Synchronization object address\" offset=\"%d\" type=\"%s\"/>\n",
+ &pp->objp, sizeof (pp->objp) == 4 ? "INT32" : "INT64");
+ collector_interface->writeLog (" </profpckt>\n");
+ collector_interface->writeLog ("</profile>\n");
+
+ /* Convert threshold from microsec to nanosec */
+ sync_threshold = (thresh > 0 ? thresh : -thresh) * 1000;
+ TprintfT (0, "synctrace: open_experiment complete %ld\n", sync_threshold);
+ return COL_ERROR_NONE;
+}
+
+static int
+start_data_collection (void)
+{
+ sync_mode = 1;
+ TprintfT (0, "synctrace: start_data_collection\n");
+ return 0;
+}
+
+static int
+stop_data_collection (void)
+{
+ sync_mode = 0;
+ TprintfT (0, "synctrace: stop_data_collection\n");
+ return 0;
+}
+
+static int
+close_experiment (void)
+{
+ sync_mode = 0;
+ sync_threshold = -1;
+ sync_key = COLLECTOR_TSD_INVALID_KEY;
+ TprintfT (0, "synctrace: close_experiment\n");
+ return 0;
+}
+
+/* fork child. Clean up state but don't write to experiment */
+static int
+detach_experiment (void)
+{
+ sync_mode = 0;
+ sync_threshold = -1;
+ sync_key = COLLECTOR_TSD_INVALID_KEY;
+ TprintfT (0, "synctrace: detach_experiment\n");
+ return 0;
+}
+
+#define NUM_ITER 100 /* number of iterations in calibration */
+#define NUM_WARMUP 3 /* number of warm up iterations */
+
+static int
+sync_calibrate ()
+{
+ pthread_mutex_t mt = PTHREAD_MUTEX_INITIALIZER;
+ hrtime_t bt, at, delta;
+ hrtime_t avg, max, min;
+ int i;
+ int ret;
+ avg = (hrtime_t) 0;
+ min = max = (hrtime_t) 0;
+ for (i = 0; i < NUM_ITER + NUM_WARMUP; i++)
+ {
+ /* Here we simulate a real call */
+ bt = gethrtime ();
+ ret = CALL_REAL (pthread_mutex_lock)(&mt);
+ at = gethrtime ();
+ CALL_REAL (pthread_mutex_unlock)(&mt);
+ if (i < NUM_WARMUP) /* skip these iterations */
+ continue;
+ /* add the time of this one */
+ delta = at - bt;
+ avg += delta;
+ if (min == 0)
+ min = delta;
+ if (delta < min)
+ min = delta;
+ if (delta > max)
+ max = delta;
+ }
+ /* compute average time */
+ avg = avg / NUM_ITER;
+
+ /* pretty simple, let's see how it works */
+ if (max < 6 * avg)
+ max = 6 * avg;
+ /* round up to the nearest microsecond */
+ ret = (int) ((max + 999) / 1000);
+ return ret;
+}
+
+static int
+init_thread_intf ()
+{
+ void *dlflag = RTLD_NEXT;
+ int err = 0;
+ /* if we detect recursion/reentrance, SEGV so we can get a stack */
+ init_thread_intf_started++;
+ if (!init_thread_intf_finished && init_thread_intf_started >= 3)
+ {
+ /* pull the plug if recursion occurs... */
+ abort ();
+ }
+ /* lookup fprint to print fatal error message */
+ void *ptr = dlsym (RTLD_DEFAULT, "fprintf");
+ if (ptr)
+ {
+ __real_fprintf = (void *) ptr;
+ }
+ else
+ {
+ abort ();
+ }
+
+ /* find the __collector_jprofile_enable_synctrace routine in jprofile module */
+ ptr = dlsym (RTLD_DEFAULT, "__collector_jprofile_enable_synctrace");
+ if (ptr)
+ __real___collector_jprofile_enable_synctrace = (void *) ptr;
+ else
+ {
+#if defined(GPROFNG_JAVA_PROFILING)
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT __collector_jprofile_enable_synctrace\n");
+ err = COL_ERROR_SYNCINIT;
+#endif
+ sync_java = 0;
+ }
+
+#if WSIZE(32)
+ /* ########################################## begin WSIZE(32) */
+ /* IMPORTANT!! The GLIBC_* versions below must match those in the er_sync.*.mapfile ! */
+ dlflag = RTLD_NEXT;
+ ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.0");
+ if (ptr == NULL)
+ {
+ /* We are probably dlopened after libthread/libc,
+ * try to search in the previously loaded objects
+ */
+ dlflag = RTLD_DEFAULT;
+ ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.0");
+ if (ptr != NULL)
+ {
+ __real_pthread_mutex_lock = ptr;
+ Tprintf (0, "synctrace: WARNING: init_thread_intf() using RTLD_DEFAULT for OS sync routines\n");
+ }
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_lock\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ }
+ else
+ __real_pthread_mutex_lock = ptr;
+
+ ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.0");
+ if (ptr)
+ __real_pthread_mutex_unlock = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_unlock\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.3.2");
+ if (ptr)
+ __real_pthread_cond_wait = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.3.2");
+ if (ptr)
+ __real_pthread_cond_timedwait = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_join", "GLIBC_2.0");
+ if (ptr)
+ __real_pthread_join = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_join\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.1");
+ if (ptr)
+ __real_sem_wait = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+
+#if ARCH(Intel)
+ /* ############## Intel specific additional pointers for 32-bits */
+ ptr = __real_sem_wait_2_1 = __real_sem_wait;
+ ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.0");
+ if (ptr)
+ __real_sem_wait_2_0 = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait_2_0\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.0");
+ if (ptr)
+ __real_pthread_cond_wait_2_0 = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait_2_0\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.0");
+ if (ptr)
+ __real_pthread_cond_timedwait_2_0 = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT __real_pthread_cond_timedwait_2_0\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+#endif /* ARCH(Intel) */
+
+#else /* WSIZE(64) */
+ /* # most versions are different between platforms */
+ /* # the few that are common are set after the ARCH ifdef */
+#if ARCH(Aarch64)
+ dlflag = RTLD_NEXT;
+#define GLIBC_N "GLIBC_2.17"
+ __real_pthread_mutex_lock = dlvsym(dlflag, "pthread_mutex_lock", GLIBC_N);
+ __real_pthread_mutex_unlock = dlvsym(dlflag, "pthread_mutex_unlock", GLIBC_N);
+ __real_pthread_cond_wait = dlvsym(dlflag, "pthread_cond_wait", GLIBC_N);
+ __real_pthread_cond_timedwait = dlvsym(dlflag, "pthread_cond_timedwait", GLIBC_N);
+ __real_pthread_join = dlvsym(dlflag, "pthread_join", GLIBC_N);
+ __real_sem_wait = dlvsym(dlflag, "sem_wait", GLIBC_N);
+
+#elif ARCH(Intel)
+ dlflag = RTLD_NEXT;
+ ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2.5");
+ if (ptr == NULL)
+ {
+ /* We are probably dlopened after libthread/libc,
+ * try to search in the previously loaded objects
+ */
+ dlflag = RTLD_DEFAULT;
+ ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2.5");
+ if (ptr != NULL)
+ {
+ __real_pthread_mutex_lock = ptr;
+ Tprintf (0, "synctrace: WARNING: init_thread_intf() using RTLD_DEFAULT for Solaris sync routines\n");
+ }
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_lock\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ }
+ else
+ __real_pthread_mutex_lock = ptr;
+ ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.2.5");
+ if (ptr)
+ __real_pthread_mutex_unlock = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_unlock\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.3.2");
+ if (ptr)
+ __real_pthread_cond_wait = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.3.2");
+ if (ptr)
+ __real_pthread_cond_timedwait = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_join", "GLIBC_2.2.5");
+ if (ptr)
+ __real_pthread_join = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_join\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.2.5");
+ if (ptr)
+ __real_sem_wait = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.2.5");
+ if (ptr)
+ __real_pthread_cond_wait_2_2_5 = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait_2_2_5\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.2.5");
+ if (ptr)
+ __real_pthread_cond_timedwait_2_2_5 = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait_2_2_5\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+
+#elif ARCH(SPARC)
+ dlflag = RTLD_NEXT;
+ ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2");
+ if (ptr == NULL)
+ {
+ /* We are probably dlopened after libthread/libc,
+ * try to search in the previously loaded objects
+ */
+ dlflag = RTLD_DEFAULT;
+ ptr = dlvsym (dlflag, "pthread_mutex_lock", "GLIBC_2.2");
+ if (ptr != NULL)
+ {
+ __real_pthread_mutex_lock = ptr;
+ Tprintf (0, "synctrace: WARNING: init_thread_intf() using RTLD_DEFAULT for Solaris sync routines\n");
+ }
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT mutex_lock\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ }
+ else
+ __real_pthread_mutex_lock = ptr;
+ ptr = dlvsym (dlflag, "pthread_mutex_unlock", "GLIBC_2.2");
+ if (ptr)
+ __real_pthread_mutex_unlock = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_mutex_unlock\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.3.2");
+ if (ptr)
+ __real_pthread_cond_wait = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.3.2");
+ if (ptr)
+ __real_pthread_cond_timedwait = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_join", "GLIBC_2.2");
+ if (ptr)
+ __real_pthread_join = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_join\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "sem_wait", "GLIBC_2.2");
+ if (ptr)
+ __real_sem_wait = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT sem_wait\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_cond_wait", "GLIBC_2.2");
+ if (ptr)
+ __real_pthread_cond_wait_2_2 = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_wait_2_2_5\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ ptr = dlvsym (dlflag, "pthread_cond_timedwait", "GLIBC_2.2");
+ if (ptr)
+ __real_pthread_cond_timedwait_2_2 = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT pthread_cond_timedwait_2_2\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+#endif /* ARCH() */
+#endif /* WSIZE(64) */
+ /* the pointers that are common to 32- and 64-bits, and to SPARC and Intel */
+
+ __real_pthread_cond_wait_2_3_2 = __real_pthread_cond_wait;
+ __real_pthread_cond_timedwait_2_3_2 = __real_pthread_cond_timedwait;
+ ptr = dlsym (dlflag, "strtol");
+ if (ptr)
+ __real_strtol = (void *) ptr;
+ else
+ {
+ CALL_REAL (fprintf)(stderr, "synctrace_init COL_ERROR_SYNCINIT strtol\n");
+ err = COL_ERROR_SYNCINIT;
+ }
+ init_thread_intf_finished++;
+ TprintfT (0, "synctrace init_thread_intf complete\n");
+ return err;
+}
+
+/* These next two routines are used from jprofile to record Java synctrace data */
+void
+__collector_jsync_begin ()
+{
+ int *guard;
+ if (CHCK_JREENTRANCE (guard))
+ {
+ Tprintf (DBG_LT1, "__collector_jsync_begin: skipped\n");
+ return;
+ }
+ Tprintf (DBG_LT1, "__collector_jsync_begin: start event\n");
+ PUSH_REENTRANCE (guard);
+}
+
+void
+__collector_jsync_end (hrtime_t reqt, void *object)
+{
+ int *guard;
+ if (RECHCK_JREENTRANCE (guard))
+ {
+ Tprintf (DBG_LT1, "__collector_jsync_end: skipped\n");
+ return;
+ }
+ hrtime_t grnt = gethrtime ();
+ if (grnt - reqt >= sync_threshold)
+ {
+ Sync_packet spacket;
+ collector_memset (&spacket, 0, sizeof ( Sync_packet));
+ spacket.comm.tsize = sizeof ( Sync_packet);
+ spacket.comm.tstamp = grnt;
+ spacket.requested = reqt;
+ spacket.objp = (Vaddr_type) object;
+ spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
+ collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
+ }
+ Tprintf (DBG_LT1, "__collector_jsync_begin: end event\n");
+ POP_REENTRANCE (guard);
+}
+
+/*-------------------------------------------------------- pthread_mutex_lock */
+int
+pthread_mutex_lock (pthread_mutex_t *mp)
+{
+ int *guard;
+ if (NULL_PTR (pthread_mutex_lock))
+ init_thread_intf ();
+ if (CHCK_NREENTRANCE (guard))
+ return CALL_REAL (pthread_mutex_lock)(mp);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ int ret = CALL_REAL (pthread_mutex_lock)(mp);
+ if (RECHCK_NREENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ if (grnt - reqt >= sync_threshold)
+ {
+ Sync_packet spacket;
+ collector_memset (&spacket, 0, sizeof ( Sync_packet));
+ spacket.comm.tsize = sizeof ( Sync_packet);
+ spacket.comm.tstamp = grnt;
+ spacket.requested = reqt;
+ spacket.objp = (Vaddr_type) mp;
+ spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK, &spacket);
+ collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
+ }
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+
+/*------------------------------------------------------------- pthread_cond_wait */
+// map interposed symbol versions
+static int
+__collector_pthread_cond_wait_symver (int(real_pthread_cond_wait) (), pthread_cond_t *cond, pthread_mutex_t *mutex);
+
+int
+__collector_pthread_cond_wait_2_3_2 (pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ if (NULL_PTR (pthread_cond_wait))
+ init_thread_intf ();
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_3_2@%p\n", CALL_REAL (pthread_cond_wait_2_3_2));
+ return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_3_2), cond, mutex);
+}
+
+#if ARCH(Intel) || ARCH(SPARC)
+__asm__(".symver __collector_pthread_cond_wait_2_3_2,pthread_cond_wait@@GLIBC_2.3.2");
+#endif
+
+#if WSIZE(32)
+
+int
+__collector_pthread_cond_wait_2_0 (pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ if (NULL_PTR (pthread_cond_wait))
+ init_thread_intf ();
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_0@%p\n", CALL_REAL (pthread_cond_wait_2_0));
+ return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_0), cond, mutex);
+}
+
+__asm__(".symver __collector_pthread_cond_wait_2_0,pthread_cond_wait@GLIBC_2.0");
+
+#else // WSIZE(64)
+#if ARCH(Intel)
+int
+__collector_pthread_cond_wait_2_2_5 (pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ if (NULL_PTR (pthread_cond_wait))
+ init_thread_intf ();
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_2_5@%p\n", CALL_REAL (pthread_cond_wait_2_2_5));
+ return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_2_5), cond, mutex);
+}
+
+__asm__(".symver __collector_pthread_cond_wait_2_2_5,pthread_cond_wait@GLIBC_2.2.5");
+#elif ARCH(SPARC)
+
+int
+__collector_pthread_cond_wait_2_2 (pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ if (NULL_PTR (pthread_cond_wait))
+ init_thread_intf ();
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_wait_2_2@%p\n", CALL_REAL (pthread_cond_wait_2_2));
+ return __collector_pthread_cond_wait_symver (CALL_REAL (pthread_cond_wait_2_2), cond, mutex);
+}
+
+__asm__(".symver __collector_pthread_cond_wait_2_2,pthread_cond_wait@GLIBC_2.2");
+#endif // ARCH()
+#endif // WSIZE()
+
+static int
+__collector_pthread_cond_wait_symver (int(real_pthread_cond_wait) (), pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+ int *guard;
+ if (NULL_PTR (pthread_cond_wait))
+ init_thread_intf ();
+ if (CHCK_NREENTRANCE (guard))
+ return (real_pthread_cond_wait) (cond, mutex);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ int ret = -1;
+ ret = (real_pthread_cond_wait) (cond, mutex);
+ if (RECHCK_NREENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ if (grnt - reqt >= sync_threshold)
+ {
+ Sync_packet spacket;
+ collector_memset (&spacket, 0, sizeof ( Sync_packet));
+ spacket.comm.tsize = sizeof ( Sync_packet);
+ spacket.comm.tstamp = grnt;
+ spacket.requested = reqt;
+ spacket.objp = (Vaddr_type) mutex;
+ spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
+ collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
+ }
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*---------------------------------------------------- pthread_cond_timedwait */
+// map interposed symbol versions
+static int
+__collector_pthread_cond_timedwait_symver (int(real_pthread_cond_timedwait) (),
+ pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime);
+
+int
+__collector_pthread_cond_timedwait_2_3_2 (pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ if (NULL_PTR (pthread_cond_timedwait))
+ init_thread_intf ();
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_3_2@%p\n", CALL_REAL (pthread_cond_timedwait_2_3_2));
+ return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_3_2), cond, mutex, abstime);
+}
+
+#if ARCH(Intel) || ARCH(SPARC)
+__asm__(".symver __collector_pthread_cond_timedwait_2_3_2,pthread_cond_timedwait@@GLIBC_2.3.2");
+#endif // ARCH()
+
+#if WSIZE(32)
+int
+__collector_pthread_cond_timedwait_2_0 (pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ if (NULL_PTR (pthread_cond_timedwait))
+ init_thread_intf ();
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_0@%p\n", CALL_REAL (pthread_cond_timedwait_2_0));
+ return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_0), cond, mutex, abstime);
+}
+
+__asm__(".symver __collector_pthread_cond_timedwait_2_0,pthread_cond_timedwait@GLIBC_2.0");
+
+#else // WSIZE(64)
+#if ARCH(Intel)
+int
+__collector_pthread_cond_timedwait_2_2_5 (pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ if (NULL_PTR (pthread_cond_timedwait))
+ init_thread_intf ();
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_2_5@%p\n", CALL_REAL (pthread_cond_timedwait_2_2_5));
+ return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_2_5), cond, mutex, abstime);
+}
+
+__asm__(".symver __collector_pthread_cond_timedwait_2_2_5,pthread_cond_timedwait@GLIBC_2.2.5");
+#elif ARCH(SPARC)
+
+int
+__collector_pthread_cond_timedwait_2_2 (pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ if (NULL_PTR (pthread_cond_timedwait))
+ init_thread_intf ();
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_pthread_cond_timedwait_2_2@%p\n", CALL_REAL (pthread_cond_timedwait_2_2));
+ return __collector_pthread_cond_timedwait_symver (CALL_REAL (pthread_cond_timedwait_2_2), cond, mutex, abstime);
+}
+
+__asm__(".symver __collector_pthread_cond_timedwait_2_2,pthread_cond_timedwait@GLIBC_2.2");
+#endif // ARCH()
+#endif // WSIZE()
+
+static int
+__collector_pthread_cond_timedwait_symver (int(real_pthread_cond_timedwait) (),
+ pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ int *guard;
+ if (NULL_PTR (pthread_cond_timedwait))
+ init_thread_intf ();
+ if (CHCK_NREENTRANCE (guard))
+ return (real_pthread_cond_timedwait) (cond, mutex, abstime);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ int ret = -1;
+ ret = (real_pthread_cond_timedwait) (cond, mutex, abstime);
+ if (RECHCK_NREENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ if (grnt - reqt >= sync_threshold)
+ {
+ Sync_packet spacket;
+ collector_memset (&spacket, 0, sizeof ( Sync_packet));
+ spacket.comm.tsize = sizeof ( Sync_packet);
+ spacket.comm.tstamp = grnt;
+ spacket.requested = reqt;
+ spacket.objp = (Vaddr_type) mutex;
+ spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
+ collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
+ }
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- pthread_join */
+int
+pthread_join (pthread_t target_thread, void **status)
+{
+ int *guard;
+ if (NULL_PTR (pthread_join))
+ init_thread_intf ();
+ if (CHCK_NREENTRANCE (guard))
+ return CALL_REAL (pthread_join)(target_thread, status);
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ int ret = CALL_REAL (pthread_join)(target_thread, status);
+ if (RECHCK_NREENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ if (grnt - reqt >= sync_threshold)
+ {
+ Sync_packet spacket;
+ collector_memset (&spacket, 0, sizeof ( Sync_packet));
+ spacket.comm.tsize = sizeof ( Sync_packet);
+ spacket.comm.tstamp = grnt;
+ spacket.requested = reqt;
+ spacket.objp = (Vaddr_type) target_thread;
+ spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK, &spacket);
+ collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
+ }
+ POP_REENTRANCE (guard);
+ return ret;
+}
+
+/*------------------------------------------------------------- sem_wait */
+// map interposed symbol versions
+#if ARCH(Intel) && WSIZE(32)
+static int
+__collector_sem_wait_symver (int(real_sem_wait) (), sem_t *sp);
+
+int
+__collector_sem_wait_2_1 (sem_t *sp)
+{
+ if (NULL_PTR (sem_wait))
+ init_thread_intf ();
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_sem_wait_2_1@%p\n", CALL_REAL (sem_wait_2_1));
+ return __collector_sem_wait_symver (CALL_REAL (sem_wait_2_1), sp);
+}
+
+int
+__collector_sem_wait_2_0 (sem_t *sp)
+{
+ if (NULL_PTR (sem_wait))
+ init_thread_intf ();
+ TprintfT (DBG_LTT, "linetrace: GLIBC: __collector_sem_wait_2_0@%p\n", CALL_REAL (sem_wait_2_0));
+ return __collector_sem_wait_symver (CALL_REAL (sem_wait_2_0), sp);
+}
+
+__asm__(".symver __collector_sem_wait_2_1,sem_wait@@GLIBC_2.1");
+__asm__(".symver __collector_sem_wait_2_0,sem_wait@GLIBC_2.0");
+#endif
+
+#if ARCH(Intel) && WSIZE(32)
+static int
+__collector_sem_wait_symver (int(real_sem_wait) (), sem_t *sp)
+{
+#else
+int
+sem_wait (sem_t *sp)
+{
+#endif
+ int *guard;
+ if (NULL_PTR (sem_wait))
+ init_thread_intf ();
+ if (CHCK_NREENTRANCE (guard))
+ {
+#if ARCH(Intel) && WSIZE(32)
+ return (real_sem_wait) (sp);
+#else
+ return CALL_REAL (sem_wait)(sp);
+#endif
+ }
+ PUSH_REENTRANCE (guard);
+ hrtime_t reqt = gethrtime ();
+ int ret = -1;
+#if ARCH(Intel) && WSIZE(32)
+ ret = (real_sem_wait) (sp);
+#else
+ ret = CALL_REAL (sem_wait)(sp);
+#endif
+ if (RECHCK_NREENTRANCE (guard))
+ {
+ POP_REENTRANCE (guard);
+ return ret;
+ }
+ hrtime_t grnt = gethrtime ();
+ if (grnt - reqt >= sync_threshold)
+ {
+ Sync_packet spacket;
+ collector_memset (&spacket, 0, sizeof ( Sync_packet));
+ spacket.comm.tsize = sizeof ( Sync_packet);
+ spacket.comm.tstamp = grnt;
+ spacket.requested = reqt;
+ spacket.objp = (Vaddr_type) sp;
+
+#if ARCH(Intel) && WSIZE(32)
+ spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK_ARG, &spacket);
+#else
+ spacket.comm.frinfo = collector_interface->getFrameInfo (sync_hndl, spacket.comm.tstamp, FRINFO_FROM_STACK, &spacket);
+#endif
+ collector_interface->writeDataRecord (sync_hndl, (Common_packet*) & spacket);
+ }
+ POP_REENTRANCE (guard);
+ return ret;
+}
diff --git a/gprofng/libcollector/tsd.c b/gprofng/libcollector/tsd.c
new file mode 100644
index 0000000..416c3e7
--- /dev/null
+++ b/gprofng/libcollector/tsd.c
@@ -0,0 +1,149 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "config.h"
+#include <pthread.h>
+
+#include "collector.h"
+#include "libcol_util.h"
+#include "tsd.h"
+#include "memmgr.h"
+
+/* TprintfT(<level>,...) definitions. Adjust per module as needed */
+#define DBG_LT0 0 // for high-level configuration, unexpected errors/warnings
+#define DBG_LT1 1 // for configuration details, warnings
+#define DBG_LT2 2
+#define DBG_LT3 3
+
+/*
+ * Build our thread-specific-data support on pthread interfaces.
+ */
+#define MAXNKEYS 64 /* hard-wired? really? well, it depends only on us and we have a sense for how many keys we will use */
+static pthread_key_t tsd_pkeys[MAXNKEYS];
+static size_t tsd_sizes[MAXNKEYS];
+static unsigned tsd_nkeys = 0;
+
+int
+__collector_tsd_init ()
+{
+ return 0;
+}
+
+void
+__collector_tsd_fini ()
+{
+ Tprintf (DBG_LT1, "tsd_fini()\n");
+ while (tsd_nkeys)
+ {
+ tsd_nkeys--;
+ pthread_key_delete (tsd_pkeys[tsd_nkeys]);
+ tsd_sizes[tsd_nkeys] = 0; // should be unneeded
+ }
+}
+
+int
+__collector_tsd_allocate ()
+{
+ return 0;
+}
+
+void
+__collector_tsd_release () { }
+
+static void
+tsd_destructor (void *p)
+{
+ if (p)
+ __collector_freeCSize (__collector_heap, p, *((size_t *) p));
+}
+
+unsigned
+__collector_tsd_create_key (size_t sz, void (*init)(void*), void (*fini)(void*))
+{
+ /*
+ * We no longer support init and fini arguments (and weren't using them anyhow).
+ * Our hard-wired MAXNKEYS presumably is considerably higher than the number of keys we use.
+ */
+ if (init || fini || (tsd_nkeys >= MAXNKEYS))
+ return COLLECTOR_TSD_INVALID_KEY;
+
+ /*
+ * A pthread key has a value that is (void *).
+ * We don't know where it is stored, and can access its value only through {get|set}specific.
+ * But libcollector expects a pointer to memory that it can modify.
+ * So we have to allocate that memory and store the pointer.
+ *
+ * For now, we just have to register a destructor that will free the memory
+ * when the thread finishes.
+ */
+ if (pthread_key_create (&tsd_pkeys[tsd_nkeys], &tsd_destructor))
+ return COLLECTOR_TSD_INVALID_KEY;
+ tsd_sizes[tsd_nkeys] = sz;
+ tsd_nkeys++;
+ return (tsd_nkeys - 1);
+}
+
+void *
+__collector_tsd_get_by_key (unsigned key_index)
+{
+ if (key_index == COLLECTOR_TSD_INVALID_KEY)
+ return NULL;
+ if (key_index < 0 || key_index >= tsd_nkeys)
+ return NULL;
+ pthread_key_t key = tsd_pkeys[key_index];
+ size_t sz = tsd_sizes[key_index];
+
+ /*
+ * When we use __collector_freeCSize(), we need to know the
+ * size that had been allocated. So, stick a header to the
+ * front of the allocation to hold the size. The header could
+ * just be sizeof(size_t), but pad it to preserve alignment for
+ * the usable area.
+ */
+ size_t header = 8;
+ void *value = pthread_getspecific (key);
+
+ // check whether we have allocated the memory
+ if (value == NULL)
+ {
+ // add room to record the size
+ value = __collector_allocCSize (__collector_heap, sz + header, 0);
+ if (value == NULL)
+ {
+ // do we need to guard against trying to alloc each time?
+ return NULL;
+ }
+ // write the size of the allocation
+ *((size_t *) value) = sz + header;
+ CALL_UTIL (memset)(((char *) value) + header, 0, sz);
+
+ // record the allocation for future retrieval
+ if (pthread_setspecific (key, value))
+ return NULL;
+ }
+ // return the pointer, skipping the header
+ return ((char *) value) +header;
+}
+
+void
+__collector_tsd_fork_child_cleanup ()
+{
+ __collector_tsd_fini ();
+}
diff --git a/gprofng/libcollector/tsd.h b/gprofng/libcollector/tsd.h
new file mode 100644
index 0000000..38b3d53
--- /dev/null
+++ b/gprofng/libcollector/tsd.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+/* Thread-specific data */
+
+#ifndef _TSD_H
+#define _TSD_H
+
+#include <sys/types.h>
+
+int __collector_tsd_init ();
+/* Function: Init tsd module. Call once before using other functions.
+ MT-Level: Unsafe
+ Return: 0 if successful
+ */
+
+void __collector_tsd_fini ();
+/* Function: Shutdown tsd module.
+ MT-Level: Unsafe
+ Return: None
+ */
+
+void __collector_tsd_fork_child_cleanup ();
+/* Function: Reset tsd module. Call immediately after fork() in child process.
+ MT-Level: Unsafe
+ Return: None
+ */
+
+int __collector_tsd_allocate ();
+/* Function: Allocate thread info.
+ Call from threads before using tsd_get_by_key().
+ Call from main thread should be made before calls from other threads.
+ MT-Level: First call is unsafe. Safe afterwards.
+ Return: 0 if successful
+ */
+
+void __collector_tsd_release ();
+/* Function: Free thread info.
+ Call from threads just before thread termination.
+ MT-Level: Safe
+ Return: None
+ */
+
+#define COLLECTOR_TSD_INVALID_KEY ((unsigned)-1)
+unsigned __collector_tsd_create_key (size_t memsize, void (*init)(void*), void (*fini)(void*));
+/* Function: Reserve TDS memory.
+ MT-Level: Unsafe
+ Inputs: <memsize>: number of bytes to reserve
+ <init>: key memory initialization. Must be callable even if
+ the associated thread has not yet been created.
+ <fini>: key memory finalization. Must be callable even if
+ the associated thread has been terminated.
+ Return: key or COLLECTOR_TSD_INVALID_KEY if not successful.
+ */
+
+void *__collector_tsd_get_by_key (unsigned key);
+/* Function: Get TSD memory.
+ Call from threads after calling tsd_allocate().
+ MT-Level: Safe
+ Inputs: <key>: return value from tsd_create_key()
+ Return: memory if successful, NULL otherwise
+ */
+#endif /* _TSD_H */
diff --git a/gprofng/libcollector/unwind.c b/gprofng/libcollector/unwind.c
new file mode 100644
index 0000000..ffb06f9
--- /dev/null
+++ b/gprofng/libcollector/unwind.c
@@ -0,0 +1,4630 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#include "config.h"
+#include <alloca.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include "gp-defs.h"
+#include "collector.h"
+#include "gp-experiment.h"
+#include "memmgr.h"
+#include "tsd.h"
+
+/* Get dynamic module interface*/
+#include "collector_module.h"
+
+/* Get definitions for SP_LEAF_CHECK_MARKER, SP_TRUNC_STACK_MARKER */
+#include "data_pckts.h"
+
+#if ARCH(SPARC)
+struct frame
+{
+ long fr_local[8]; /* saved locals */
+ long fr_arg[6]; /* saved arguments [0 - 5] */
+ struct frame *fr_savfp; /* saved frame pointer */
+ long fr_savpc; /* saved program counter */
+#if WSIZE(32)
+ char *fr_stret; /* struct return addr */
+#endif
+ long fr_argd[6]; /* arg dump area */
+ long fr_argx[1]; /* array of args past the sixth */
+};
+
+#elif ARCH(Intel)
+struct frame
+{
+ unsigned long fr_savfp;
+ unsigned long fr_savpc;
+};
+#endif
+
+/* Set the debug trace level */
+#define DBG_LT0 0
+#define DBG_LT1 1
+#define DBG_LT2 2
+#define DBG_LT3 3
+
+int (*__collector_VM_ReadByteInstruction)(unsigned char *) = NULL;
+#define VM_NO_ACCESS (-1)
+#define VM_NOT_VM_MEMORY (-2)
+#define VM_NOT_X_SEGMENT (-3)
+
+#define isInside(p, bgn, end) ((p) >= (bgn) && (p) < (end))
+
+/*
+ * Weed through all the arch dependent stuff to get the right definition
+ * for 'pc' in the ucontext structure. The system header files are mess
+ * dealing with all the arch (just look for PC, R_PC, REG_PC).
+ *
+ */
+
+#if ARCH(SPARC)
+
+#define IN_BARRIER(x) \
+ ( barrier_hdl && \
+ (unsigned long)x >= barrier_hdl && \
+ (unsigned long)x < barrier_hdlx )
+static unsigned long barrier_hdl = 0;
+static unsigned long barrier_hdlx = 0;
+
+#if WSIZE(64)
+#define STACK_BIAS 2047
+#define IN_TRAP_HANDLER(x) \
+ ( misalign_hdl && \
+ (unsigned long)x >= misalign_hdl && \
+ (unsigned long)x < misalign_hdlx )
+static unsigned long misalign_hdl = 0;
+static unsigned long misalign_hdlx = 0;
+#elif WSIZE(32)
+#define STACK_BIAS 0
+#endif
+
+#if WSIZE(64)
+#define GET_GREG(ctx,reg) (((ucontext_t*)ctx)->uc_mcontext.mc_gregs[(reg)])
+#define GET_SP(ctx) (((ucontext_t*)ctx)->uc_mcontext.mc_gregs[MC_O6])
+#define GET_PC(ctx) (((ucontext_t*)ctx)->uc_mcontext.mc_gregs[MC_PC])
+#else
+#define GET_GREG(ctx,reg) (((ucontext_t*)ctx)->uc_mcontext.gregs[(reg)])
+#define GET_SP(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_O6])
+#define GET_PC(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_PC])
+#endif
+
+#elif ARCH(Intel)
+#include "opcodes/disassemble.h"
+
+static int
+fprintf_func (void *arg ATTRIBUTE_UNUSED, const char *fmt ATTRIBUTE_UNUSED, ...)
+{
+ return 0;
+}
+
+/* Get LENGTH bytes from info's buffer, at target address memaddr.
+ Transfer them to myaddr. */
+static int
+read_memory_func (bfd_vma memaddr, bfd_byte *myaddr, unsigned int length,
+ disassemble_info *info)
+{
+ unsigned int opb = info->octets_per_byte;
+ size_t end_addr_offset = length / opb;
+ size_t max_addr_offset = info->buffer_length / opb;
+ size_t octets = (memaddr - info->buffer_vma) * opb;
+ if (memaddr < info->buffer_vma
+ || memaddr - info->buffer_vma > max_addr_offset
+ || memaddr - info->buffer_vma + end_addr_offset > max_addr_offset
+ || (info->stop_vma && (memaddr >= info->stop_vma
+ || memaddr + end_addr_offset > info->stop_vma)))
+ return -1;
+ memcpy (myaddr, info->buffer + octets, length);
+ return 0;
+}
+
+static void
+print_address_func (bfd_vma addr ATTRIBUTE_UNUSED,
+ disassemble_info *info ATTRIBUTE_UNUSED) { }
+
+static asymbol *
+symbol_at_address_func (bfd_vma addr ATTRIBUTE_UNUSED,
+ disassemble_info *info ATTRIBUTE_UNUSED)
+{
+ return NULL;
+}
+
+static bfd_boolean
+symbol_is_valid (asymbol *sym ATTRIBUTE_UNUSED,
+ disassemble_info *info ATTRIBUTE_UNUSED)
+{
+ return TRUE;
+}
+
+static void
+memory_error_func (int status ATTRIBUTE_UNUSED, bfd_vma addr ATTRIBUTE_UNUSED,
+ disassemble_info *info ATTRIBUTE_UNUSED) { }
+
+
+#if WSIZE(32)
+#define GET_PC(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_EIP])
+#define GET_SP(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_ESP])
+#define GET_FP(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_EBP])
+
+#elif WSIZE(64)
+#define GET_PC(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_RIP])
+#define GET_SP(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_RSP])
+#define GET_FP(ctx) (((ucontext_t*)ctx)->uc_mcontext.gregs[REG_RBP])
+#endif /* WSIZE() */
+
+#elif ARCH(Aarch64)
+#define GET_PC(ctx) (((ucontext_t*)ctx)->uc_mcontext.regs[15])
+#define GET_SP(ctx) (((ucontext_t*)ctx)->uc_mcontext.regs[13])
+#define GET_FP(ctx) (((ucontext_t*)ctx)->uc_mcontext.regs[14])
+#endif /* ARCH() */
+
+/*
+ * FILL_CONTEXT() for all platforms
+ * Could use getcontext() except:
+ * - it's not guaranteed to be async signal safe
+ * - it's a system call and not that lightweight
+ * - it's not portable as of POSIX.1-2008
+ * So we just use low-level mechanisms to fill in the few fields we need.
+ */
+#if ARCH(SPARC)
+#if WSIZE(32)
+#define FILL_CONTEXT(context) \
+ { \
+ greg_t fp; \
+ __asm__ __volatile__( "mov %%i6, %0" : "=r" (fp) ); \
+ __asm__ __volatile__( "ta 3" ); \
+ GET_SP(context) = fp; \
+ GET_PC(context) = (greg_t)0; \
+ }
+
+#elif WSIZE(64)
+#define FILL_CONTEXT(context) \
+ { \
+ greg_t fp; \
+ __asm__ __volatile__( "mov %%i6, %0" : "=r" (fp) ); \
+ __asm__ __volatile__( "flushw" ); \
+ GET_SP(context) = fp; \
+ GET_PC(context) = (greg_t)0; \
+ }
+#endif /* WSIZE() */
+
+#elif ARCH(Intel)
+#define FILL_CONTEXT(context) \
+ { \
+ context->uc_link = NULL; \
+ void *sp = __collector_getsp(); \
+ GET_SP(context) = (greg_t)sp; \
+ GET_FP(context) = (greg_t)__collector_getfp(); \
+ GET_PC(context) = (greg_t)__collector_getpc(); \
+ context->uc_stack.ss_sp = sp; \
+ context->uc_stack.ss_size = 0x100000; \
+ }
+
+#elif ARCH(Aarch64)
+#define FILL_CONTEXT(context) \
+ { getcontext(context); \
+ context->uc_mcontext.sp = (__u64) __builtin_frame_address(0); \
+ }
+
+#endif /* ARCH() */
+
+static int
+getByteInstruction (unsigned char *p)
+{
+ if (__collector_VM_ReadByteInstruction)
+ {
+ int v = __collector_VM_ReadByteInstruction (p);
+ if (v != VM_NOT_VM_MEMORY)
+ return v;
+ }
+ return *p;
+}
+
+struct DataHandle *dhndl = NULL;
+
+static unsigned unwind_key = COLLECTOR_TSD_INVALID_KEY;
+
+/* To support two OpenMP API's we use a pointer
+ * to the actual function.
+ */
+int (*__collector_omp_stack_trace)(char*, int, hrtime_t, void*) = NULL;
+int (*__collector_mpi_stack_trace)(char*, int, hrtime_t) = NULL;
+
+#define DEFAULT_MAX_NFRAMES 256
+static int max_native_nframes = DEFAULT_MAX_NFRAMES;
+static int max_java_nframes = DEFAULT_MAX_NFRAMES;
+
+#define NATIVE_FRAME_BYTES(nframes) ( ((nframes)+1) * sizeof(long) )
+#define JAVA_FRAME_BYTES(nframes) ( ((nframes)+1) * sizeof(long) * 2 + 16 )
+#define OVERHEAD_BYTES ( 2 * sizeof(long) + 2 * sizeof(Stack_info) )
+
+#define ROOT_UID 801425552975190205ULL
+#define ROOT_UID_INV 92251691606677ULL
+#define ROOT_IDX 13907816567264074199ULL
+#define ROOT_IDX_INV 2075111ULL
+#define UIDTableSize 1048576
+static volatile uint64_t *UIDTable = NULL;
+static volatile int seen_omp = 0;
+
+static int stack_unwind (char *buf, int size, void *bptr, void *eptr, ucontext_t *context, int mode);
+static FrameInfo compute_uid (Frame_packet *frp);
+static int omp_no_walk = 0;
+
+#if ARCH(Intel)
+#define ValTableSize 1048576
+#define OmpValTableSize 65536
+static unsigned long *AddrTable_RA_FROMFP = NULL; // Cache for RA_FROMFP pcs
+static unsigned long *AddrTable_RA_EOSTCK = NULL; // Cache for RA_EOSTCK pcs
+static struct WalkContext *OmpCurCtxs = NULL;
+static struct WalkContext *OmpCtxs = NULL;
+static uint32_t *OmpVals = NULL;
+static unsigned long *OmpRAs = NULL;
+static unsigned long adjust_ret_addr (unsigned long ra, unsigned long segoff, unsigned long tend);
+static int parse_x86_AVX_instruction (unsigned char *pc);
+
+struct WalkContext
+{
+ unsigned long pc;
+ unsigned long sp;
+ unsigned long fp;
+ unsigned long ln;
+ unsigned long sbase; /* stack boundary */
+ unsigned long tbgn; /* current memory segment start */
+ unsigned long tend; /* current memory segment end */
+};
+#endif
+
+#if defined(DEBUG) && ARCH(Intel)
+#include <execinfo.h>
+
+static void
+dump_stack (int nline)
+{
+ if ((__collector_tracelevel & SP_DUMP_STACK) == 0)
+ return;
+
+ enum Constexpr { MAX_SIZE = 1024 };
+ void *array[MAX_SIZE];
+ size_t sz = backtrace (array, MAX_SIZE);
+ char **strings = backtrace_symbols (array, sz);
+ DprintfT (SP_DUMP_STACK, "\ndump_stack: %d size=%d\n", nline, (int) sz);
+ for (int i = 0; i < sz; i++)
+ DprintfT (SP_DUMP_STACK, " %3d: %p %s\n", i, array[i],
+ strings[i] ? strings[i] : "???");
+}
+
+#define dump_targets(nline, ntrg, targets) \
+ if ((__collector_tracelevel & SP_DUMP_UNWIND) != 0) \
+ for(int i = 0; i < ntrg; i++) \
+ DprintfT (SP_DUMP_UNWIND, " %2d: 0x%lx\n", i, (long) targets[i])
+#else
+#define dump_stack(x)
+#define dump_targets(nline, ntrg, targets)
+#endif
+
+void
+__collector_ext_unwind_key_init (int isPthread, void * stack)
+{
+ void * ptr = __collector_tsd_get_by_key (unwind_key);
+ if (ptr == NULL)
+ {
+ TprintfT (DBG_LT2, "__collector_ext_unwind_key_init: cannot get tsd\n");
+ return;
+ }
+ if (isPthread)
+ {
+ size_t stack_size = 0;
+ void *stack_addr = 0;
+ pthread_t pthread = pthread_self ();
+ pthread_attr_t attr;
+ int err = pthread_getattr_np (pthread, &attr);
+ TprintfT (DBG_LT1, "__collector_ext_unwind_key_init: pthread: 0x%lx err: %d\n", pthread, err);
+ if (err == 0)
+ {
+ err = pthread_attr_getstack (&attr, &stack_addr, &stack_size);
+ if (err == 0)
+ stack_addr = (char*) stack_addr + stack_size;
+ TprintfT (DBG_LT1, "__collector_ext_unwind_key_init: stack_size=0x%lx eos=%p err=%d\n",
+ (long) stack_size, stack_addr, err);
+ err = pthread_attr_destroy (&attr);
+ TprintfT (DBG_LT1, "__collector_ext_unwind_key_init: destroy: %d\n", err);
+ }
+ *(void**) ptr = stack_addr;
+ }
+ else
+ *(void**) ptr = stack; // cloned thread
+}
+
+void
+__collector_ext_unwind_init (int record)
+{
+ int sz = UIDTableSize * sizeof (*UIDTable);
+ UIDTable = (uint64_t*) __collector_allocCSize (__collector_heap, sz, 1);
+ if (UIDTable == NULL)
+ {
+ __collector_terminate_expt ();
+ return;
+ }
+ CALL_UTIL (memset)((void*) UIDTable, 0, sz);
+
+ char *str = CALL_UTIL (getenv)("GPROFNG_JAVA_MAX_CALL_STACK_DEPTH");
+ if (str != NULL && *str != 0)
+ {
+ char *endptr;
+ int n = CALL_UTIL (strtol)(str, &endptr, 0);
+ if (endptr != str && n >= 0)
+ {
+ if (n < 5)
+ n = 5;
+ if (n > MAX_STACKDEPTH)
+ n = MAX_STACKDEPTH;
+ max_java_nframes = n;
+ }
+ }
+
+ str = CALL_UTIL (getenv)("GPROFNG_MAX_CALL_STACK_DEPTH");
+ if (str != NULL && *str != 0)
+ {
+ char *endptr = str;
+ int n = CALL_UTIL (strtol)(str, &endptr, 0);
+ if (endptr != str && n >= 0)
+ {
+ if (n < 5)
+ n = 5;
+ if (n > MAX_STACKDEPTH)
+ n = MAX_STACKDEPTH;
+ max_native_nframes = n;
+ }
+ }
+
+ TprintfT (DBG_LT0, "GPROFNG_MAX_CALL_STACK_DEPTH=%d GPROFNG_JAVA_MAX_CALL_STACK_DEPTH=%d\n",
+ max_native_nframes, max_java_nframes);
+ omp_no_walk = 1;
+
+ if (__collector_VM_ReadByteInstruction == NULL)
+ __collector_VM_ReadByteInstruction = (int(*)()) dlsym (RTLD_DEFAULT, "Async_VM_ReadByteInstruction");
+
+#if ARCH(SPARC)
+#if WSIZE(64)
+ misalign_hdl = (unsigned long) dlsym (RTLD_DEFAULT, "__misalign_trap_handler");
+ misalign_hdlx = (unsigned long) dlsym (RTLD_DEFAULT, "__misalign_trap_handler_end");
+ if (misalign_hdlx == 0)
+ misalign_hdlx = misalign_hdl + 292;
+ barrier_hdl = (unsigned long) dlsym (RTLD_DEFAULT, "__mt_EndOfTask_Barrier_");
+ barrier_hdlx = (unsigned long) dlsym (RTLD_DEFAULT, "__mt_EndOfTask_Barrier_Dummy_");
+ if (barrier_hdlx == 0)
+ barrier_hdl = 0;
+#else
+ barrier_hdl = (unsigned long) dlsym (RTLD_DEFAULT, "__mt_EndOfTask_Barrier_");
+ barrier_hdlx = (unsigned long) dlsym (RTLD_DEFAULT, "__mt_EndOfTask_Barrier_Dummy_");
+ if (barrier_hdlx == 0)
+ barrier_hdl = 0;
+#endif /* WSIZE() */
+
+#elif ARCH(Intel)
+ sz = ValTableSize * sizeof (*AddrTable_RA_FROMFP);
+ AddrTable_RA_FROMFP = (unsigned long*) __collector_allocCSize (__collector_heap, sz, 1);
+ sz = ValTableSize * sizeof (*AddrTable_RA_EOSTCK);
+ AddrTable_RA_EOSTCK = (unsigned long*) __collector_allocCSize (__collector_heap, sz, 1);
+ if (omp_no_walk && (__collector_omp_stack_trace != NULL || __collector_mpi_stack_trace != NULL))
+ {
+ sz = OmpValTableSize * sizeof (*OmpCurCtxs);
+ OmpCurCtxs = (struct WalkContext *) __collector_allocCSize (__collector_heap, sz, 1);
+ sz = OmpValTableSize * sizeof (*OmpCtxs);
+ OmpCtxs = (struct WalkContext *) __collector_allocCSize (__collector_heap, sz, 1);
+ sz = OmpValTableSize * sizeof (*OmpVals);
+ OmpVals = (uint32_t*) __collector_allocCSize (__collector_heap, sz, 1);
+ sz = OmpValTableSize * sizeof (*OmpRAs);
+ OmpRAs = (unsigned long*) __collector_allocCSize (__collector_heap, sz, 1);
+ if (OmpCurCtxs == NULL || OmpCtxs == NULL || OmpVals == NULL || OmpRAs == NULL)
+ {
+ TprintfT (0, "unwind_init() ERROR: failed; terminating experiment\n");
+ __collector_terminate_expt ();
+ return;
+ }
+ }
+#endif /* ARCH() */
+
+ if (record)
+ {
+ dhndl = __collector_create_handle (SP_FRINFO_FILE);
+ __collector_log_write ("<%s name=\"%s\" format=\"binary\"/>\n", SP_TAG_DATAPTR, SP_FRINFO_FILE);
+ }
+
+ unwind_key = __collector_tsd_create_key (sizeof (void*), NULL, NULL);
+ if (unwind_key == COLLECTOR_TSD_INVALID_KEY)
+ {
+ TprintfT (0, "unwind_init: ERROR: TSD key create failed.\n");
+ __collector_log_write ("<%s kind=\"%s\" id=\"%d\">TSD key not created</%s>\n",
+ SP_TAG_EVENT, SP_JCMD_CERROR, COL_ERROR_GENERAL, SP_TAG_EVENT);
+ return;
+ }
+ TprintfT (0, "unwind_init() completed normally\n");
+ return;
+}
+
+void
+__collector_ext_unwind_close ()
+{
+ __collector_delete_handle (dhndl);
+ dhndl = NULL;
+}
+
+void*
+__collector_ext_return_address (unsigned level)
+{
+ if (NULL == UIDTable) //unwind not initialized yet
+ return NULL;
+ unsigned size = (level + 4) * sizeof (long); // need to strip __collector_get_return_address and its caller
+ ucontext_t context;
+ FILL_CONTEXT ((&context));
+ char* buf = (char*) alloca (size);
+ if (buf == NULL)
+ {
+ TprintfT (DBG_LT0, "__collector_get_return_address: ERROR: alloca(%d) fails\n", size);
+ return NULL;
+ }
+ int sz = stack_unwind (buf, size, NULL, NULL, &context, 0);
+ if (sz < (level + 3) * sizeof (long))
+ {
+ TprintfT (DBG_LT0, "__collector_get_return_address: size=%d, but stack_unwind returns %d\n", size, sz);
+ return NULL;
+ }
+ long *lbuf = (long*) buf;
+ TprintfT (DBG_LT2, "__collector_get_return_address: return %lx\n", lbuf[level + 2]);
+ return (void *) (lbuf[level + 2]);
+}
+/*
+ * Collector interface method getFrameInfo
+ */
+FrameInfo
+__collector_get_frame_info (hrtime_t ts, int mode, void *arg)
+{
+ ucontext_t *context = NULL;
+ void *bptr = NULL;
+ CM_Array *array = NULL;
+
+ int unwind_mode = 0;
+ int do_walk = 1;
+
+ if (mode & FRINFO_NO_WALK)
+ do_walk = 0;
+ int bmode = mode & 0xffff;
+ int pseudo_context = 0;
+ if (bmode == FRINFO_FROM_STACK_ARG || bmode == FRINFO_FROM_STACK)
+ {
+ bptr = arg;
+ context = (ucontext_t*) alloca (sizeof (ucontext_t));
+ FILL_CONTEXT (context);
+ unwind_mode |= bmode;
+ }
+ else if (bmode == FRINFO_FROM_UC)
+ {
+ context = (ucontext_t*) arg;
+ if (context == NULL)
+ return (FrameInfo) 0;
+ if (GET_SP (context) == 0)
+ pseudo_context = 1;
+ }
+ else if (bmode == FRINFO_FROM_ARRAY)
+ {
+ array = (CM_Array*) arg;
+ if (array == NULL || array->length <= 0)
+ return (FrameInfo) 0;
+ }
+ else
+ return (FrameInfo) 0;
+
+ int max_frame_size = OVERHEAD_BYTES + NATIVE_FRAME_BYTES (max_native_nframes);
+ if (__collector_java_mode && __collector_java_asyncgetcalltrace_loaded && context && !pseudo_context)
+ max_frame_size += JAVA_FRAME_BYTES (max_java_nframes);
+
+ Frame_packet *frpckt = alloca (sizeof (Frame_packet) + max_frame_size);
+ frpckt->type = FRAME_PCKT;
+ frpckt->hsize = sizeof (Frame_packet);
+
+ char *d = (char*) (frpckt + 1);
+ int size = max_frame_size;
+
+#define MIN(a,b) ((a)<(b)?(a):(b))
+ /* get Java info */
+ if (__collector_java_mode && __collector_java_asyncgetcalltrace_loaded && context && !pseudo_context)
+ {
+ /* use only 2/3 of the buffer and leave the rest for the native stack */
+ int tmpsz = MIN (size, JAVA_FRAME_BYTES (max_java_nframes));
+ if (tmpsz > 0)
+ {
+ int sz = __collector_ext_jstack_unwind (d, tmpsz, context);
+ d += sz;
+ size -= sz;
+ }
+ }
+
+ /* get native stack */
+ if (context)
+ {
+ Stack_info *sinfo = (Stack_info*) d;
+ int sz = sizeof (Stack_info);
+ d += sz;
+ size -= sz;
+#if ARCH(Intel)
+ if (omp_no_walk == 0)
+ do_walk = 1;
+#endif
+ if (do_walk == 0)
+ unwind_mode |= FRINFO_NO_WALK;
+
+ int tmpsz = MIN (size, NATIVE_FRAME_BYTES (max_native_nframes));
+ if (tmpsz > 0)
+ {
+ sz = stack_unwind (d, tmpsz, bptr, NULL, context, unwind_mode);
+ d += sz;
+ size -= sz;
+ }
+ sinfo->kind = STACK_INFO;
+ sinfo->hsize = (d - (char*) sinfo);
+ }
+
+ /* create a stack image from user data */
+ if (array && array->length > 0)
+ {
+ Stack_info *sinfo = (Stack_info*) d;
+ int sz = sizeof (Stack_info);
+ d += sz;
+ size -= sz;
+ sz = array->length;
+ if (sz > size)
+ sz = size; // YXXX should we mark this with truncation frame?
+ __collector_memcpy (d, array->bytes, sz);
+ d += sz;
+ size -= sz;
+ sinfo->kind = STACK_INFO;
+ sinfo->hsize = (d - (char*) sinfo);
+ }
+
+ /* Compute the total size */
+ frpckt->tsize = d - (char*) frpckt;
+ FrameInfo uid = compute_uid (frpckt);
+ return uid;
+}
+
+FrameInfo
+compute_uid (Frame_packet *frp)
+{
+ uint64_t idxs[LAST_INFO];
+ uint64_t uid = ROOT_UID;
+ uint64_t idx = ROOT_IDX;
+
+ Common_info *cinfo = (Common_info*) ((char*) frp + frp->hsize);
+ char *end = (char*) frp + frp->tsize;
+ for (;;)
+ {
+ if ((char*) cinfo >= end || cinfo->hsize == 0 ||
+ (char*) cinfo + cinfo->hsize > end)
+ break;
+
+ /* Start with a different value to avoid matching with uid */
+ uint64_t uidt = 1;
+ uint64_t idxt = 1;
+ long *ptr = (long*) ((char*) cinfo + cinfo->hsize);
+ long *bnd = (long*) ((char*) cinfo + sizeof (Common_info));
+ TprintfT (DBG_LT2, "compute_uid: Cnt=%ld: ", (long) cinfo->hsize);
+ while (ptr > bnd)
+ {
+ long val = *(--ptr);
+ tprintf (DBG_LT2, "0x%8.8llx ", (unsigned long long) val);
+ uidt = (uidt + val) * ROOT_UID;
+ idxt = (idxt + val) * ROOT_IDX;
+ uid = (uid + val) * ROOT_UID;
+ idx = (idx + val) * ROOT_IDX;
+ }
+ if (cinfo->kind == STACK_INFO || cinfo->kind == JAVA_INFO)
+ {
+ cinfo->uid = uidt;
+ idxs[cinfo->kind] = idxt;
+ }
+ cinfo = (Common_info*) ((char*) cinfo + cinfo->hsize);
+ }
+ tprintf (DBG_LT2, "\n");
+
+ /* Check if we have already recorded that uid.
+ * The following fragment contains benign data races.
+ * It's important, though, that all reads from UIDTable
+ * happen before writes.
+ */
+ int found1 = 0;
+ int idx1 = (int) ((idx >> 44) % UIDTableSize);
+ if (UIDTable[idx1] == uid)
+ found1 = 1;
+ int found2 = 0;
+ int idx2 = (int) ((idx >> 24) % UIDTableSize);
+ if (UIDTable[idx2] == uid)
+ found2 = 1;
+ int found3 = 0;
+ int idx3 = (int) ((idx >> 4) % UIDTableSize);
+ if (UIDTable[idx3] == uid)
+ found3 = 1;
+ if (!found1)
+ UIDTable[idx1] = uid;
+ if (!found2)
+ UIDTable[idx2] = uid;
+ if (!found3)
+ UIDTable[idx3] = uid;
+
+ if (found1 || found2 || found3)
+ return (FrameInfo) uid;
+ frp->uid = uid;
+
+ /* Compress info's */
+ cinfo = (Common_info*) ((char*) frp + frp->hsize);
+ for (;;)
+ {
+ if ((char*) cinfo >= end || cinfo->hsize == 0 ||
+ (char*) cinfo + cinfo->hsize > end)
+ break;
+ if (cinfo->kind == STACK_INFO || cinfo->kind == JAVA_INFO)
+ {
+ long *ptr = (long*) ((char*) cinfo + sizeof (Common_info));
+ long *bnd = (long*) ((char*) cinfo + cinfo->hsize);
+ uint64_t uidt = cinfo->uid;
+ uint64_t idxt = idxs[cinfo->kind];
+ int found = 0;
+ int first = 1;
+ while (ptr < bnd - 1)
+ {
+ int idx1 = (int) ((idxt >> 44) % UIDTableSize);
+ if (UIDTable[idx1] == uidt)
+ {
+ found = 1;
+ break;
+ }
+ else if (first)
+ {
+ first = 0;
+ UIDTable[idx1] = uidt;
+ }
+ long val = *ptr++;
+ uidt = uidt * ROOT_UID_INV - val;
+ idxt = idxt * ROOT_IDX_INV - val;
+ }
+ if (found)
+ {
+ char *d = (char*) ptr;
+ char *s = (char*) bnd;
+ if (!first)
+ {
+ int i;
+ for (i = 0; i<sizeof (uidt); i++)
+ {
+ *d++ = (char) uidt;
+ uidt = uidt >> 8;
+ }
+ }
+ int delta = s - d;
+ while (s < end)
+ *d++ = *s++;
+ cinfo->kind |= COMPRESSED_INFO;
+ cinfo->hsize -= delta;
+ frp->tsize -= delta;
+ end -= delta;
+ }
+ }
+ cinfo = (Common_info*) ((char*) cinfo + cinfo->hsize);
+ }
+ __collector_write_packet (dhndl, (CM_Packet*) frp);
+ return (FrameInfo) uid;
+}
+
+FrameInfo
+__collector_getUID (CM_Array *arg, FrameInfo suid)
+{
+ if (arg->length % sizeof (long) != 0 ||
+ (long) arg->bytes % sizeof (long) != 0)
+ return (FrameInfo) - 1;
+ if (arg->length == 0)
+ return suid;
+
+ uint64_t uid = suid ? suid : 1;
+ uint64_t idx = suid ? suid : 1;
+ long *ptr = (long*) ((char*) arg->bytes + arg->length);
+ long *bnd = (long*) (arg->bytes);
+ while (ptr > bnd)
+ {
+ long val = *(--ptr);
+ uid = (uid + val) * ROOT_UID;
+ idx = (idx + val) * ROOT_IDX;
+ }
+
+ /* Check if we have already recorded that uid.
+ * The following fragment contains benign data races.
+ * It's important, though, that all reads from UIDTable
+ * happen before writes.
+ */
+ int found1 = 0;
+ int idx1 = (int) ((idx >> 44) % UIDTableSize);
+ if (UIDTable[idx1] == uid)
+ found1 = 1;
+ int found2 = 0;
+ int idx2 = (int) ((idx >> 24) % UIDTableSize);
+ if (UIDTable[idx2] == uid)
+ found2 = 1;
+ int found3 = 0;
+ int idx3 = (int) ((idx >> 4) % UIDTableSize);
+ if (UIDTable[idx3] == uid)
+ found3 = 1;
+
+ if (!found1)
+ UIDTable[idx1] = uid;
+ if (!found2)
+ UIDTable[idx2] = uid;
+ if (!found3)
+ UIDTable[idx3] = uid;
+ if (found1 || found2 || found3)
+ return (FrameInfo) uid;
+
+ int sz = sizeof (Uid_packet) + arg->length;
+ if (suid)
+ sz += sizeof (suid);
+ Uid_packet *uidp = alloca (sz);
+ uidp->tsize = sz;
+ uidp->type = UID_PCKT;
+ uidp->flags = 0;
+ uidp->uid = uid;
+
+ /* Compress */
+ ptr = (long*) (arg->bytes);
+ bnd = (long*) ((char*) arg->bytes + arg->length);
+ long *dst = (long*) (uidp + 1);
+ uint64_t uidt = uid;
+ uint64_t idxt = idx;
+ uint64_t luid = suid; /* link uid */
+
+ while (ptr < bnd)
+ {
+
+ long val = *ptr++;
+ *dst++ = val;
+
+ if ((bnd - ptr) > sizeof (uidt))
+ {
+ uidt = uidt * ROOT_UID_INV - val;
+ idxt = idxt * ROOT_IDX_INV - val;
+ int idx1 = (int) ((idxt >> 44) % UIDTableSize);
+ if (UIDTable[idx1] == uidt)
+ {
+ luid = uidt;
+ break;
+ }
+ }
+ }
+ if (luid)
+ {
+ char *d = (char*) dst;
+ for (int i = 0; i<sizeof (luid); i++)
+ {
+ *d++ = (char) luid;
+ luid = luid >> 8;
+ }
+ uidp->flags |= COMPRESSED_INFO;
+ uidp->tsize = d - (char*) uidp;
+ }
+ __collector_write_packet (dhndl, (CM_Packet*) uidp);
+
+ return (FrameInfo) uid;
+}
+
+int
+__collector_getStackTrace (void *buf, int size, void *bptr, void *eptr, void *arg)
+{
+ if (arg == (void*) __collector_omp_stack_trace)
+ seen_omp = 1;
+ int do_walk = 1;
+ if (arg == NULL || arg == (void*) __collector_omp_stack_trace)
+ {
+ do_walk = (arg == (void*) __collector_omp_stack_trace && omp_no_walk) ? 0 : 1;
+ ucontext_t *context = (ucontext_t*) alloca (sizeof (ucontext_t));
+ FILL_CONTEXT (context);
+ arg = context;
+ }
+ int unwind_mode = 0;
+ if (do_walk == 0)
+ unwind_mode |= FRINFO_NO_WALK;
+ return stack_unwind (buf, size, bptr, eptr, arg, unwind_mode);
+}
+
+#if ARCH(SPARC)
+/*
+ * These are important data structures taken from the header files reg.h and
+ * ucontext.h. They are used for the stack trace algorithm explained below.
+ *
+ * typedef struct ucontext {
+ * u_long uc_flags;
+ * struct ucontext *uc_link;
+ * usigset_t uc_sigmask;
+ * stack_t uc_stack;
+ * mcontext_t uc_mcontext;
+ * long uc_filler[23];
+ * } ucontext_t;
+ *
+ * #define SPARC_MAXREGWINDOW 31
+ *
+ * struct rwindow {
+ * greg_t rw_local[8];
+ * greg_t rw_in[8];
+ * };
+ *
+ * #define rw_fp rw_in[6]
+ * #define rw_rtn rw_in[7]
+ *
+ * struct gwindows {
+ * int wbcnt;
+ * int *spbuf[SPARC_MAXREGWINDOW];
+ * struct rwindow wbuf[SPARC_MAXREGWINDOW];
+ * };
+ *
+ * typedef struct gwindows gwindows_t;
+ *
+ * typedef struct {
+ * gregset_t gregs;
+ * gwindows_t *gwins;
+ * fpregset_t fpregs;
+ * long filler[21];
+ * } mcontext_t;
+ *
+ * The stack would look like this when SIGPROF occurrs.
+ *
+ * ------------------------- <- high memory
+ * | |
+ * | |
+ * -------------------------
+ * | |
+ * ------------------------- <- fp' <-|
+ * | | |
+ * : : |
+ * | | |
+ * ------------------------- |
+ * | fp |----------|
+ * | |
+ * ------------------------- <- sp'
+ * | | | |
+ * | gwins | <- saved stack pointers & | |
+ * | | register windows | |- mcontext
+ * ------------------------- | |
+ * | gregs | <- saved registers | |
+ * ------------------------- |
+ * | | |- ucontext
+ * ------------------------- <- ucp (ucontext pointer) |
+ * | | |
+ * | | |- siginfo
+ * ------------------------- <- sip (siginfo pointer) |
+ * | |
+ * ------------------------- <- sp
+ *
+ * Then the signal handler is called with:
+ * handler( signo, sip, uip );
+ * When gwins is null, all the stack frames are saved in the user stack.
+ * In that case we can find sp' from gregs and walk the stack for a backtrace.
+ * However, if gwins is not null we will have a more complicated case.
+ * Wbcnt(in gwins) tells you how many saved register windows are valid.
+ * This is important because the kernel does not allocate the entire array.
+ * And the top most frame is saved in the lowest index element. The next
+ * paragraph explains the possible causes.
+ *
+ * There are two routines in the kernel to flush out user register windows.
+ * flush_user_windows and flush_user_windows_to_stack
+ * The first routine will not cause a page fault. Therefore if the user
+ * stack is not in memory, the register windows will be saved to the pcb.
+ * This can happen when the kernel is trying to deliver a signal and
+ * the user stack got swap out. The kernel will then build a new context for
+ * the signal handler and the saved register windows will
+ * be copied to the ucontext as show above. On the other hand,
+ * flush_user_windows_to_stack can cause a page fault, and if it failed
+ * then there is something wrong (stack overflow, misalign).
+ * The first saved register window does not necessary correspond to the
+ * first stack frame. So the current stack pointer must be compare with
+ * the stack pointers in spbuf to find a match.
+ *
+ * We will also follow the uc_link field in ucontext to trace also nested
+ * signal stack frames.
+ *
+ */
+
+/* Dealing with trap handlers.
+ * When a user defined trap handler is invoked the return address
+ * (or actually the address of an instruction that raised the trap)
+ * is passed to the trap handler in %l6, whereas saved %o7 contains
+ * garbage. First, we need to find out if a particular pc belongs
+ * to the trap handler, and if so, take the %l6 value from the stack rather
+ * than %o7 from either the stack or the register.
+ * There are three possible situations represented
+ * by the following stacks:
+ *
+ * MARKER MARKER MARKER
+ * trap handler pc __func pc before 'save' __func pc after 'save'
+ * %l6 %o7 from reg %o7 (garbage)
+ * ... %l6 trap handler pc
+ * ... %l6
+ * ...
+ * where __func is a function called from the trap handler.
+ *
+ * Currently this is implemented to only deal with __misalign_trap_handler
+ * set for v9 FORTRAN applications. Implementation of IN_TRAP_HANDLER
+ * macro shows it. A general solution is postponed.
+ */
+
+/* Special handling of unwind through the parallel loop barrier code:
+ *
+ * The library defines two symbols, __mt_EndOfTask_Barrier_ and
+ * __mt_EndOfTask_Barrier_Dummy_ representing the first word of
+ * the barrier sychronization code, and the first word following
+ * it. Whenever the leaf PC is between these two symbols,
+ * the unwind code is special-cased as follows:
+ * The __mt_EndOfTask_Barrier_ function is guaranteed to be a leaf
+ * function, so its return address is in a register, not saved on
+ * the stack.
+ *
+ * MARKER
+ * __mt_EndOfTask_Barrier_ PC -- the leaf PC
+ * loop body function address for the task -- implied caller of __mt_EndOfTask_Barrier_
+ * this address is taken from the %O0 register
+ * {mt_master or mt_slave} -- real caller of __mt_EndOfTask_Barrier_
+ * ...
+ *
+ * With this trick, the analyzer will show the time in the barrier
+ * attributed to the loop at the end of which the barrier synchronization
+ * is taking place. That loop body routine, will be shown as called
+ * from the function from which it was extracted, which will be shown
+ * as called from the real caller, either the slave or master library routine.
+ */
+
+/*
+ * These no-fault-load (0x82) assembly functions are courtesy of Rob Gardner.
+ *
+ * Note that 0x82 is ASI_PNF. See
+ * http://lxr.free-electrons.com/source/arch/sparc/include/uapi/asm/asi.h#L134
+ * ASI address space identifier; PNF primary no fault
+ */
+
+/* load an int from an address */
+
+/* if the address is illegal, return a 0 */
+static int
+SPARC_no_fault_load_int (void *addr)
+{
+ int val;
+ __asm__ __volatile__(
+ "lda [%1] 0x82, %0\n\t"
+ : "=r" (val)
+ : "r" (addr)
+ );
+
+ return val;
+}
+
+/* check if an address is invalid
+ *
+ * A no-fault load of an illegal address still faults, but it does so silently to the calling process.
+ * It returns a 0, but so could a load of a legal address.
+ * So, we time the load. A "fast" load must be a successful load.
+ * A "slow" load is probably a fault.
+ * Since it could also be a cache/TLB miss or other abnormality,
+ * it's safest to retry a slow load.
+ * The cost of trying a valid address should be some nanosecs.
+ * The cost of trying an invalid address up to 10 times could be some microsecs.
+ */
+#if 0
+static
+int invalid_SPARC_addr(void *addr)
+{
+ long t1, t2;
+ int i;
+
+ for (i=0; i<10; i++) {
+ __asm__ __volatile__(
+ "rd %%tick, %0\n\t"
+ "lduba [%2] 0x82, %%g0\n\t"
+ "rd %%tick, %1\n\t"
+ : "=r" (t1), "=r" (t2)
+ : "r" (addr) );
+ if ( (t2 - t1) < 100 )
+ return 0;
+ }
+ return 1;
+}
+#endif
+
+/*
+ * The standard SPARC procedure-calling convention is that the
+ * calling PC (for determining the return address when the procedure
+ * is finished) is placed in register %o7. A called procedure
+ * typically executes a "save" instruction that shifts the register
+ * window, and %o7 becomes %i7.
+ *
+ * Optimized leaf procedures do not shift the register window.
+ * They assume the return address will remain %o7. So when
+ * we process a leaf PC, we walk instructions to see if there
+ * is a call, restore, or other instruction that would indicate
+ * we can IGNORE %o7 because this is NOT a leaf procedure.
+ *
+ * If a limited instruction walk uncovers no such hint, we save
+ * not only the PC but the %o7 value as well... just to be safe.
+ * Later, in DBE post-processing of the call stacks, we decide
+ * whether any recorded %o7 value should be used as a caller
+ * frame or should be discarded.
+ */
+
+#define IS_ILLTRAP(x) (((x) & 0xc1c00000) == 0)
+#define IS_SAVE(x) (((x) & 0xc1f80000) == 0x81e00000)
+#define IS_MOVO7R(x) (((x) & 0xc1f8201f) == 0x8160000f)
+#define IS_MOVRO7(x) (((x) & 0xfff82000) == 0x9f600000)
+#define IS_ORRG0O7(x) (((x) & 0xff78201f) == 0x9e100000)
+#define IS_ORG0RO7(x) (((x) & 0xff7fe000) == 0x9e100000)
+#define IS_ORG0O7R(x) (((x) & 0xc17fe01f) == 0x8010000f)
+#define IS_ORO7G0R(x) (((x) & 0xc17fe01f) == 0x8013c000)
+#define IS_RESTORE(x) (((x) & 0xc1f80000) == 0x81e80000)
+#define IS_RET(x) ((x) == 0x81c7e008)
+#define IS_RETL(x) ((x) == 0x81c3e008)
+#define IS_RETURN(x) (((x) & 0xc1f80000) == 0x81c80000)
+#define IS_BRANCH(x) ((((x) & 0xc0000000) == 0) && (((x) & 0x01c00000) != 0x01000000))
+#define IS_CALL(x) (((x) & 0xc0000000) == 0x40000000)
+#define IS_LDO7(x) (((x) & 0xfff80000) == 0xde000000)
+
+static long pagesize = 0;
+
+static int
+process_leaf (long *lbuf, int ind, int lsize, void *context)
+{
+ greg_t pc = GET_PC (context);
+ greg_t o7 = GET_GREG (context, REG_O7);
+
+ /* omazur: TBR START -- not used */
+ if (IN_BARRIER (pc))
+ {
+ if (ind < lsize)
+ lbuf[ind++] = pc;
+ if (ind < lsize)
+ lbuf[ind++] = GET_GREG (context, REG_O0);
+ return ind;
+ }
+ /* omazur: TBR END */
+#if WSIZE(64)
+ if (IN_TRAP_HANDLER (pc))
+ {
+ if (ind < lsize)
+ lbuf[ind++] = pc;
+ return ind;
+ }
+#endif
+ unsigned *instrp = (unsigned *) pc;
+ unsigned *end_addr = instrp + 20;
+ while (instrp < end_addr)
+ {
+ unsigned instr = *instrp++;
+ if (IS_ILLTRAP (instr))
+ break;
+ else if (IS_SAVE (instr))
+ {
+ if (ind < lsize)
+ lbuf[ind++] = pc;
+ if (o7 && ind < lsize)
+ lbuf[ind++] = o7;
+ return ind;
+ }
+ else if (IS_MOVO7R (instr) || IS_ORG0O7R (instr) || IS_ORO7G0R (instr))
+ break;
+ else if (IS_MOVRO7 (instr) || IS_ORG0RO7 (instr))
+ {
+ int rs2 = (instr & 0x1f) + REG_G1 - 1;
+ o7 = (rs2 <= REG_O7) ? GET_GREG (context, rs2) : 0;
+ break;
+ }
+ else if (IS_ORRG0O7 (instr))
+ {
+ int rs2 = ((instr & 0x7c000) >> 14) + REG_G1 - 1;
+ o7 = (rs2 <= REG_O7) ? GET_GREG (context, rs2) : 0;
+ break;
+ }
+ else if (IS_RESTORE (instr))
+ {
+ o7 = 0;
+ break;
+ }
+ else if (IS_RETURN (instr))
+ {
+ o7 = 0;
+ break;
+ }
+ else if (IS_RET (instr))
+ {
+ o7 = 0;
+ break;
+ }
+ else if (IS_RETL (instr))
+ {
+ /* process delay slot */
+ instr = *instrp++;
+ if (IS_RESTORE (instr))
+ o7 = 0;
+ break;
+ }
+ else if (IS_BRANCH (instr))
+ {
+ unsigned *backbegin = ((unsigned *) pc - 1);
+ unsigned *backend = backbegin - 12 + (instrp - (unsigned *) pc);
+ while (backbegin > backend)
+ {
+ // 21920143 stack unwind: SPARC process_leaf backtracks too far
+ /*
+ * We've already dereferenced backbegin+1.
+ * So if backbegin is on the same page, we're fine.
+ * If we've gone to a different page, possibly things are not fine.
+ * We don't really know how to test that.
+ * Let's just assume the worst: that dereferencing backbegin would segv.
+ * We won't know if we're in a leaf function or not.
+ */
+ if (pagesize == 0)
+ pagesize = CALL_UTIL (sysconf)(_SC_PAGESIZE);
+ if ((((long) (backbegin + 1)) & (pagesize - 1)) < sizeof (unsigned*))
+ break;
+ unsigned backinstr = *backbegin--;
+ if (IS_LDO7 (backinstr))
+ {
+ o7 = 0;
+ break;
+ }
+ else if (IS_ILLTRAP (backinstr))
+ break;
+ else if (IS_RETURN (backinstr))
+ break;
+ else if (IS_RET (backinstr))
+ break;
+ else if (IS_RETL (backinstr))
+ break;
+ else if (IS_CALL (backinstr))
+ break;
+ else if (IS_SAVE (backinstr))
+ {
+ o7 = 0;
+ break;
+ }
+ }
+ break;
+ }
+ else if (IS_CALL (instr))
+ o7 = 0;
+ }
+
+#if WSIZE(64)
+ if (o7 != 0 && ((long) o7) < 32 && ((long) o7) > -32)
+ {
+ /* 20924821 SEGV in unwind code on SPARC/Linux
+ * We've seen this condition in some SPARC-Linux runs.
+ * o7 is non-zero but not a valid address.
+ * Values like 4 or -7 have been seen.
+ * Let's check if o7 is unreasonably small.
+ * If so, set to 0 so that it won't be recorded.
+ * Otherwise, there is risk of it being dereferenced in process_sigreturn().
+ */
+ // __collector_log_write("<event kind=\"%s\" id=\"%d\">time %lld, internal debug unwind at leaf; o7 = %ld, pc = %x</event>\n",
+ // SP_JCMD_COMMENT, COL_COMMENT_NONE, __collector_gethrtime() - __collector_start_time, (long) o7, pc );
+ o7 = 0;
+ }
+#endif
+
+ if (o7)
+ {
+ if (ind < lsize)
+ lbuf[ind++] = SP_LEAF_CHECK_MARKER;
+ if (ind < lsize)
+ lbuf[ind++] = pc;
+ if (ind < lsize)
+ lbuf[ind++] = o7;
+ }
+ else if (ind < lsize)
+ lbuf[ind++] = pc;
+ return ind;
+}
+
+#if WSIZE(64)
+// detect signal handler
+static int
+process_sigreturn (long *lbuf, int ind, int lsize, unsigned char * tpc,
+ struct frame **pfp, void * bptr, int extra_frame)
+{
+ // cheap checks whether tpc is obviously not an instruction address
+ if ((4096 > (unsigned long) tpc) // the first page is off limits
+ || (3 & (unsigned long) tpc))
+ return ind; // the address is not aligned
+
+ // get the instruction at tpc, skipping over as many as 7 nop's (0x01000000)
+ int insn, i;
+ for (i = 0; i < 7; i++)
+ {
+ insn = SPARC_no_fault_load_int ((void *) tpc);
+ if (insn != 0x01000000)
+ break;
+ tpc += 4;
+ }
+
+ // we're not expecting 0 (and it could mean an illegal address)
+ if (insn == 0)
+ return ind;
+
+ // We are looking for __rt_sigreturn_stub with the instruction
+ // 0x82102065 : mov 0x65 /* __NR_rt_sigreturn */, %g1
+ if (insn == 0x82102065)
+ {
+ /*
+ * according to linux kernel source code,
+ * syscall(_NR_rt_sigreturn) uses the following data in stack:
+ * struct rt_signal_frame {
+ * struct sparc_stackf ss;
+ * siginfo_t info;
+ * struct pt_regs regs;
+ * ....};
+ * sizeof(struct sparc_stackf) is 192;
+ * sizeof(siginfo_t) is 128;
+ * we need to get the register values from regs, which is defined as:
+ * struct pt_regs {
+ * unsigned long u_regs[16];
+ * unsigned long tstate;
+ * unsigned long tpc;
+ * unsigned long tnpc;
+ * ....};
+ * pc and fp register has offset of 120 and 112;
+ * the pc of kill() is stored in tnpc, whose offest is 136.
+ */
+ greg_t pc = *((unsigned long*) ((char*) ((*pfp)) + 192 + 128 + 136));
+ greg_t pc1 = *((unsigned long*) ((char*) ((*pfp)) + 192 + 128 + 120));
+ (*pfp) = *((struct frame**) ((char*) ((*pfp)) + 192 + 128 + 112));
+ if (pc && pc1)
+ {
+ if (bptr != NULL && extra_frame && ((char*) (*pfp) + STACK_BIAS) < (char*) bptr && ind < 2)
+ {
+ lbuf[0] = pc1;
+ if (ind == 0)
+ ind++;
+ }
+ if (bptr == NULL || ((char*) (*pfp) + STACK_BIAS) >= (char*) bptr)
+ {
+ if (ind < lsize)
+ lbuf[ind++] = (unsigned long) tpc;
+ if (ind < lsize)
+ lbuf[ind++] = pc;
+ if (ind < lsize)
+ lbuf[ind++] = pc1;
+ }
+ }
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: resolved sigreturn pc=0x%lx, pc1=0x%lx, fp=0x%lx\n", pc, pc1, *(pfp));
+ }
+ return ind;
+}
+#endif
+
+/*
+ * int stack_unwind( char *buf, int size, ucontext_t *context )
+ * This routine looks into the mcontext and
+ * trace stack frames to record return addresses.
+ */
+int
+stack_unwind (char *buf, int size, void *bptr, void *eptr, ucontext_t *context, int mode)
+{
+ /*
+ * trace the stack frames from user stack.
+ * We are assuming that the frame pointer and return address
+ * are null when we are at the top level.
+ */
+ long *lbuf = (long*) buf;
+ int lsize = size / sizeof (long);
+ struct frame *fp = (struct frame *) GET_SP (context); /* frame pointer */
+ greg_t pc; /* program counter */
+ int extra_frame = 0;
+ if ((mode & 0xffff) == FRINFO_FROM_STACK)
+ extra_frame = 1;
+
+ int ind = 0;
+ if (bptr == NULL)
+ ind = process_leaf (lbuf, ind, lsize, context);
+
+ int extra_frame = 0;
+ if ((mode & 0xffff) == FRINFO_FROM_STACK)
+ extra_frame = 1;
+ int ind = 0;
+ if (bptr == NULL)
+ ind = process_leaf (lbuf, ind, lsize, context);
+
+ while (fp)
+ {
+ if (ind >= lsize)
+ break;
+ fp = (struct frame *) ((char *) fp + STACK_BIAS);
+ if (eptr && fp >= (struct frame *) eptr)
+ {
+ ind = ind >= 2 ? ind - 2 : 0;
+ break;
+ }
+#if WSIZE(64) // detect signal handler
+ unsigned char * tpc = ((unsigned char*) (fp->fr_savpc));
+ struct frame * tfp = (struct frame*) ((char*) (fp->fr_savfp) + STACK_BIAS);
+ int old_ind = ind;
+ ind = process_sigreturn (lbuf, old_ind, lsize, tpc, &tfp, bptr, extra_frame);
+ if (ind != old_ind)
+ {
+ pc = (greg_t) tpc;
+ fp = tfp;
+ }
+ else
+#endif
+ {
+#if WSIZE(64)
+ if (IN_TRAP_HANDLER (lbuf[ind - 1]))
+ pc = fp->fr_local[6];
+ else
+ pc = fp->fr_savpc;
+#else
+ pc = fp->fr_savpc;
+#endif
+ fp = fp->fr_savfp;
+ if (pc)
+ {
+ if (bptr != NULL && extra_frame && ((char*) fp + STACK_BIAS) < (char*) bptr && ind < 2)
+ {
+ lbuf[0] = pc;
+ if (ind == 0)
+ ind++;
+ }
+ if (bptr == NULL || ((char*) fp + STACK_BIAS) >= (char*) bptr)
+ lbuf[ind++] = pc;
+ }
+ }
+
+ /* 4616238: _door_return may have a frame that has non-zero
+ * saved stack pointer and zero pc
+ */
+ if (pc == (greg_t) NULL)
+ break;
+ }
+
+ if (ind >= lsize)
+ { /* truncated stack handling */
+ ind = lsize - 1;
+ lbuf[ind++] = SP_TRUNC_STACK_MARKER;
+ }
+ return ind * sizeof (long);
+}
+
+#elif ARCH(Intel)
+
+/* get __NR_<syscall_name> constants */
+#include <syscall.h>
+
+/*
+ * From uts/intel/ia32/os/sendsig.c:
+ *
+ * An amd64 signal frame looks like this on the stack:
+ *
+ * old %rsp:
+ * <128 bytes of untouched stack space>
+ * <a siginfo_t [optional]>
+ * <a ucontext_t>
+ * <siginfo_t *>
+ * <signal number>
+ * new %rsp: <return address (deliberately invalid)>
+ *
+ * The signal number and siginfo_t pointer are only pushed onto the stack in
+ * order to allow stack backtraces. The actual signal handling code expects the
+ * arguments in registers.
+ *
+ * An i386 SVR4/ABI signal frame looks like this on the stack:
+ *
+ * old %esp:
+ * <a siginfo32_t [optional]>
+ * <a ucontext32_t>
+ * <pointer to that ucontext32_t>
+ * <pointer to that siginfo32_t>
+ * <signo>
+ * new %esp: <return address (deliberately invalid)>
+ */
+
+#if WSIZE(32)
+#define OPC_REG(x) ((x)&0x7)
+#define MRM_REGD(x) (((x)>>3)&0x7)
+#define MRM_REGS(x) ((x)&0x7)
+#define RED_ZONE 0
+#elif WSIZE(64)
+#define OPC_REG(x) (B|((x)&0x7))
+#define MRM_REGD(x) (R|(((x)>>3)&0x7))
+#define MRM_REGS(x) (B|((x)&0x7))
+#define RED_ZONE 16
+#endif
+#define MRM_EXT(x) (((x)>>3)&0x7)
+#define MRM_MOD(x) ((x)&0xc0)
+
+#define RAX 0
+#define RDX 2
+#define RSP 4
+#define RBP 5
+
+struct AdvWalkContext
+{
+ unsigned char *pc;
+ unsigned long *sp;
+ unsigned long *sp_safe;
+ unsigned long *fp;
+ unsigned long *fp_sav;
+ unsigned long *fp_loc;
+ unsigned long rax;
+ unsigned long rdx;
+ unsigned long ra_sav;
+ unsigned long *ra_loc;
+ unsigned long regs[16];
+ int tidx; /* targets table index */
+ uint32_t cval; /* cache value */
+};
+
+static unsigned long
+getRegVal (struct AdvWalkContext *cur, int r, int *undefRez)
+{
+ if (cur->regs[r] == 0)
+ {
+ if (r == RBP)
+ {
+ tprintf (DBG_LT3, "getRegVal: returns cur->regs[RBP]=0x%lx cur->pc=0x%lx\n",
+ (unsigned long) cur->fp, (unsigned long) cur->pc);
+ return (unsigned long) cur->fp;
+ }
+ *undefRez = 1;
+ }
+ tprintf (DBG_LT3, "getRegVal: cur->regs[%d]=0x%lx cur->pc=0x%lx\n",
+ r, (unsigned long) cur->regs[r], (unsigned long) cur->pc);
+ return cur->regs[r];
+}
+
+static unsigned char *
+check_modrm (unsigned char *pc)
+{
+ unsigned char modrm = *pc++;
+ unsigned char mod = MRM_MOD (modrm);
+ if (mod == 0xc0)
+ return pc;
+ unsigned char regs = modrm & 0x07;
+ if (regs == RSP)
+ {
+ if (mod == 0x40)
+ return pc + 2; // SIB + disp8
+ if (mod == 0x80)
+ return pc + 5; // SIB + disp32
+ return pc + 1; // SIB
+ }
+ if (mod == 0x0)
+ {
+ if (regs == RBP)
+ pc += 4; // disp32
+ }
+ else if (mod == 0x40)
+ pc += 1; /* byte */
+ else if (mod == 0x80)
+ pc += 4; /* word */
+ return pc;
+}
+
+static int
+read_int (unsigned char *pc, int w)
+{
+ if (w == 1)
+ return *((char *) pc);
+ if (w == 2)
+ return *(short*) pc;
+ return *(int*) pc;
+}
+
+/* Return codes */
+enum
+{
+ RA_FAILURE = 0,
+ RA_SUCCESS,
+ RA_END_OF_STACK,
+ RA_SIGRETURN,
+ RA_RT_SIGRETURN
+};
+
+/* Cache value encodings */
+static const uint32_t RA_FROMFP = (uint32_t) - 1; /* get the RA from the frame pointer */
+static const uint32_t RA_EOSTCK = (uint32_t) - 2; /* end-of-stack */
+
+
+#define MAXCTX 16
+#define MAXTRGTS 64
+#define MAXJMPREG 2
+#define MAXJMPREGCTX 3
+
+#define DELETE_CURCTX() __collector_memcpy (cur, buf + (--nctx), sizeof (*cur))
+
+/**
+ * Look for pc in AddrTable_RA_FROMFP and in AddrTable_RA_EOSTCK
+ * @param wctx
+ * @return
+ */
+static int
+cache_get (struct WalkContext *wctx)
+{
+ unsigned long addr;
+ if (AddrTable_RA_FROMFP != NULL)
+ {
+ uint64_t idx = wctx->pc % ValTableSize;
+ addr = AddrTable_RA_FROMFP[ idx ];
+ if (addr == wctx->pc)
+ { // Found in AddrTable_RA_FROMFP
+ unsigned long *sp = NULL;
+ unsigned long fp = wctx->fp;
+ /* validate fp before use */
+ if (fp < wctx->sp || fp >= wctx->sbase - sizeof (*sp))
+ return RA_FAILURE;
+ sp = (unsigned long *) fp;
+ fp = *sp++;
+ unsigned long ra = *sp++;
+ unsigned long tbgn = wctx->tbgn;
+ unsigned long tend = wctx->tend;
+ if (ra < tbgn || ra >= tend)
+ if (!__collector_check_segment (ra, &tbgn, &tend, 0))
+ return RA_FAILURE;
+ unsigned long npc = adjust_ret_addr (ra, ra - tbgn, tend);
+ if (npc == 0)
+ return RA_FAILURE;
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d cached pc=0x%lX\n", __LINE__, npc);
+ wctx->pc = npc;
+ wctx->sp = (unsigned long) sp;
+ wctx->fp = fp;
+ wctx->tbgn = tbgn;
+ wctx->tend = tend;
+ return RA_SUCCESS;
+ }
+ }
+ if (NULL == AddrTable_RA_EOSTCK)
+ return RA_FAILURE;
+ uint64_t idx = wctx->pc % ValTableSize;
+ addr = AddrTable_RA_EOSTCK[ idx ];
+ if (addr != wctx->pc)
+ return RA_FAILURE;
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d cached RA_END_OF_STACK\n", __LINE__);
+ return RA_END_OF_STACK;
+}
+/**
+ * Save pc in RA_FROMFP or RA_EOSTCK cache depending on val
+ * @param wctx
+ */
+static void
+cache_put (struct WalkContext *wctx, const uint32_t val)
+{
+ if (RA_FROMFP == val)
+ {
+ // save pc in RA_FROMFP cache
+ if (NULL != AddrTable_RA_FROMFP)
+ {
+ uint64_t idx = wctx->pc % ValTableSize;
+ AddrTable_RA_FROMFP[ idx ] = wctx->pc;
+ if (NULL != AddrTable_RA_EOSTCK)
+ if (AddrTable_RA_EOSTCK[ idx ] == wctx->pc)
+ // invalidate pc in RA_EOSTCK cache
+ AddrTable_RA_EOSTCK[ idx ] = 0;
+ }
+ return;
+ }
+ if (RA_EOSTCK == val)
+ {
+ // save pc in RA_EOSTCK cache
+ if (NULL != AddrTable_RA_EOSTCK)
+ {
+ uint64_t idx = wctx->pc % ValTableSize;
+ AddrTable_RA_EOSTCK[ idx ] = wctx->pc;
+ if (NULL != AddrTable_RA_FROMFP)
+ {
+ if (AddrTable_RA_FROMFP[ idx ] == wctx->pc)
+ // invalidate pc in RA_FROMFP cache
+ AddrTable_RA_FROMFP[ idx ] = 0;
+ }
+ }
+ return;
+ }
+}
+
+static int
+process_return_real (struct WalkContext *wctx, struct AdvWalkContext *cur, int cache_on)
+{
+ if ((unsigned long) cur->sp >= wctx->sbase ||
+ (unsigned long) cur->sp < wctx->sp)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: not in stack: %p [0x%lX-0x%lX]\n",
+ cur->sp, wctx->sp, wctx->sbase);
+ return RA_FAILURE;
+ }
+
+ unsigned long ra;
+ if (cur->sp == cur->ra_loc)
+ {
+ ra = cur->ra_sav;
+ cur->sp++;
+ }
+ else if (cur->sp >= cur->sp_safe && (unsigned long) cur->sp < wctx->sbase)
+ ra = *cur->sp++;
+ else
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: not safe: %p >= %p\n", cur->sp, cur->sp_safe);
+ return RA_FAILURE;
+ }
+ if (ra == 0)
+ {
+ if (cache_on)
+ cache_put (wctx, RA_EOSTCK);
+ wctx->pc = ra;
+ wctx->sp = (unsigned long) cur->sp;
+ wctx->fp = (unsigned long) cur->fp;
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d RA_END_OF_STACK\n", __LINE__);
+ return RA_END_OF_STACK;
+ }
+
+ unsigned long tbgn = wctx->tbgn;
+ unsigned long tend = wctx->tend;
+ if (ra < tbgn || ra >= tend)
+ {
+ if (!__collector_check_segment (ra, &tbgn, &tend, 0))
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: not in segment: 0x%lX [0x%lX-0x%lX]\n",
+ ra, wctx->tbgn, wctx->tend);
+ return RA_FAILURE;
+ }
+ }
+
+ if (cur->cval == RA_FROMFP)
+ {
+ if (wctx->fp == (unsigned long) (cur->sp - 2))
+ {
+ if (cache_on)
+ cache_put (wctx, RA_FROMFP);
+ }
+ else
+ cur->cval = 0;
+ }
+
+ unsigned long npc = adjust_ret_addr (ra, ra - tbgn, tend);
+ if (npc == 0)
+ {
+ if (cur->cval == RA_FROMFP)
+ {
+ /* We have another evidence that we can trust this RA */
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: trusted fp, pc = 0x%lX\n", wctx->pc);
+ wctx->pc = ra;
+ }
+ else
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: 0 after adjustment\n");
+ return RA_FAILURE;
+ }
+ }
+ else
+ wctx->pc = npc;
+ wctx->sp = (unsigned long) cur->sp;
+ wctx->fp = (unsigned long) cur->fp;
+ wctx->tbgn = tbgn;
+ wctx->tend = tend;
+ return RA_SUCCESS;
+}
+
+static int
+process_return (struct WalkContext *wctx, struct AdvWalkContext *cur)
+{
+ return process_return_real (wctx, cur, 1);
+}
+
+static void
+omp_cache_put (unsigned long *cur_sp_safe, struct WalkContext * wctx_pc_save,
+ struct WalkContext *wctx, uint32_t val)
+{
+ if (omp_no_walk && (OmpCurCtxs == NULL || OmpCtxs == NULL || OmpVals == NULL || OmpRAs == NULL))
+ {
+ size_t sz = OmpValTableSize * sizeof (*OmpCurCtxs);
+ OmpCurCtxs = (struct WalkContext *) __collector_allocCSize (__collector_heap, sz, 1);
+ sz = OmpValTableSize * sizeof (*OmpCtxs);
+ OmpCtxs = (struct WalkContext *) __collector_allocCSize (__collector_heap, sz, 1);
+ sz = OmpValTableSize * sizeof (*OmpVals);
+ OmpVals = (uint32_t*) __collector_allocCSize (__collector_heap, sz, 1);
+ sz = OmpValTableSize * sizeof (*OmpRAs);
+ OmpRAs = (unsigned long*) __collector_allocCSize (__collector_heap, sz, 1);
+ }
+ if (OmpCurCtxs == NULL || OmpCtxs == NULL || OmpVals == NULL || OmpRAs == NULL)
+ return;
+
+#define USE_18434988_OMP_CACHE_WORKAROUND
+#ifndef USE_18434988_OMP_CACHE_WORKAROUND
+ uint64_t idx = wctx_pc_save->pc * ROOT_IDX;
+ OmpVals[ idx % OmpValTableSize ] = val;
+ idx = (idx + val) * ROOT_IDX;
+ __collector_memcpy (&(OmpCurCtxs[ idx % OmpValTableSize ]), wctx_pc_save, sizeof (struct WalkContext));
+ idx = (idx + val) * ROOT_IDX;
+ __collector_memcpy (&(OmpCtxs[ idx % OmpValTableSize ]), wctx, sizeof (struct WalkContext));
+#endif
+ unsigned long *sp = NULL;
+ unsigned long fp = wctx_pc_save->fp;
+ int from_fp = 0;
+ if (val == RA_END_OF_STACK)
+ {
+ sp = (unsigned long *) (wctx->sp);
+ sp--;
+ TprintfT (DBG_LT1, "omp_cache_put: get sp from EOS, sp=%p\n", sp);
+ }
+ else
+ {
+ if (fp < wctx_pc_save->sp || fp >= wctx_pc_save->sbase - sizeof (*sp))
+ {
+ sp = (unsigned long *) (wctx->sp);
+ sp--;
+ TprintfT (DBG_LT1, "omp_cache_put: get sp from sp, sp=%p\n", sp);
+ }
+ else
+ {
+ TprintfT (DBG_LT1, "omp_cache_put: get sp from fp=0x%lx\n", fp);
+ sp = (unsigned long *) fp;
+ from_fp = 1;
+ }
+ }
+
+ if (sp < cur_sp_safe || ((unsigned long) sp >= wctx->sbase))
+ return;
+
+ unsigned long ra = *sp++;
+ if (from_fp)
+ {
+ unsigned long tbgn = wctx_pc_save->tbgn;
+ unsigned long tend = wctx_pc_save->tend;
+ if (ra < tbgn || ra >= tend)
+ {
+ sp = (unsigned long *) (wctx->sp);
+ sp--;
+ ra = *sp++;
+ }
+ }
+#ifdef USE_18434988_OMP_CACHE_WORKAROUND
+ uint64_t idx1 = wctx_pc_save->pc * ROOT_IDX;
+ uint64_t idx2 = (idx1 + val) * ROOT_IDX;
+ uint64_t idx3 = (idx2 + val) * ROOT_IDX;
+ uint64_t idx4 = (idx3 + val) * ROOT_IDX;
+ OmpRAs [ idx4 % OmpValTableSize ] = 0; // lock
+ OmpVals[ idx1 % OmpValTableSize ] = val;
+ __collector_memcpy (&(OmpCurCtxs[ idx2 % OmpValTableSize ]), wctx_pc_save, sizeof (struct WalkContext));
+ __collector_memcpy (&(OmpCtxs [ idx3 % OmpValTableSize ]), wctx, sizeof (struct WalkContext));
+ OmpRAs [ idx4 % OmpValTableSize ] = ra;
+#else
+ idx = (idx + val) * ROOT_IDX;
+ OmpRAs[ idx % OmpValTableSize ] = ra;
+#endif
+ TprintfT (DBG_LT1, "omp_cache_put: pc=0x%lx\n", wctx_pc_save->pc);
+}
+
+/*
+ * See bug 17166877 - malloc_internal unwind failure.
+ * Sometimes there are several calls right after ret, like:
+ * leave
+ * ret
+ * call xxx
+ * call xxxx
+ * call xxxxx
+ * If they are also jump targets, we should better not
+ * create new jump context for those, since they may
+ * end up into some other function.
+ */
+static int
+is_after_ret (unsigned char * npc)
+{
+ if (*npc != 0xe8)
+ return 0;
+ unsigned char * onpc = npc;
+ int ncall = 1;
+ int maxsteps = 10;
+ int mincalls = 3;
+ int steps = 0;
+ while (*(npc - 5) == 0xe8 && steps < maxsteps)
+ {
+ npc -= 5;
+ ncall++;
+ steps++;
+ }
+ if (*(npc - 1) != 0xc3 || *(npc - 2) != 0xc9)
+ return 0;
+ steps = 0;
+ while (*(onpc + 5) == 0xe8 && steps < maxsteps)
+ {
+ onpc += 5;
+ ncall++;
+ steps++;
+ }
+ if (ncall < mincalls)
+ return 0;
+ return 1;
+}
+
+static int
+find_i386_ret_addr (struct WalkContext *wctx, int do_walk)
+{
+ if (wctx->sp == 0)
+ // Some artificial contexts may have %sp set to 0. See SETFUNCTIONCONTEXT()
+ return RA_FAILURE;
+
+ /* Check cached values */
+ int retc = cache_get (wctx);
+ if (retc != RA_FAILURE)
+ return retc;
+
+ /* An attempt to perform code analysis for call stack tracing */
+ unsigned char opcode;
+ unsigned char extop;
+ unsigned char extop2;
+ unsigned char modrm;
+ int imm8; /* immediate operand, byte */
+ int immv; /* immediate operand, word(2) or doubleword(4) */
+ int reg; /* register code */
+
+ /* Buffer for branch targets (analysis stoppers) */
+ unsigned char *targets[MAXTRGTS];
+ int ntrg = 0; /* number of entries in the table */
+ targets[ntrg++] = (unsigned char*) wctx->pc;
+ targets[ntrg++] = (unsigned char*) - 1;
+
+ struct AdvWalkContext buf[MAXCTX];
+ struct AdvWalkContext *cur = buf;
+ CALL_UTIL (memset)((void*) cur, 0, sizeof (*cur));
+
+ cur->pc = (unsigned char*) wctx->pc;
+ cur->sp = (unsigned long*) wctx->sp;
+ cur->sp_safe = cur->sp - RED_ZONE; /* allow for the 128-byte red zone on amd64 */
+ cur->fp = (unsigned long*) wctx->fp;
+ cur->tidx = 1;
+ DprintfT (SP_DUMP_UNWIND, "\nstack_unwind (x86 walk):%d %p start\n", __LINE__, cur->pc);
+
+ int nctx = 1; /* number of contexts being processed */
+ int cnt = 8192; /* number of instructions to analyse */
+
+ /*
+ * The basic idea of our x86 stack unwind is that we don't know
+ * if we can trust the frame-pointer register. So we walk
+ * instructions to find a return instruction, at which point
+ * we know the return address is on the top of the stack, etc.
+ *
+ * A severe challenge to walking x86 instructions is when we
+ * encounter "jmp *(reg)" instructions, where we are expected
+ * to jump to the (unknown-to-us) contents of a register.
+ *
+ * The "jmp_reg" code here attempts to keep track of the
+ * context for such a jump, deferring any handling of such
+ * a difficult case. We continue with other contexts, hoping
+ * that some other walk will take us to a return instruction.
+ *
+ * If no other walk helps, we return to "jmp_reg" contexts.
+ * While we don't know the jump target, it is possible that the
+ * bytes immediately following the jmp_reg instruction represent
+ * one possible target, as might be the case when a "switch"
+ * statement is compiled.
+ *
+ * Unfortunately, the bytes following a "jmp_reg" instruction might
+ * instead be a jump target from somewhere else -- execution might
+ * never "fall through" from the preceding "jmp_reg". Those bytes
+ * might not even be instructions at all. There are many uses of
+ * jmp_reg instructions beyond just compiling switch statements.
+ *
+ * So walking the bytes after a "jmp_reg" instruction can lead
+ * to bugs and undefined behavior, including SEGV and core dump.
+ *
+ * We currently do not really understand the "jmp_reg" code below.
+ */
+ int jmp_reg_switch_mode = 0;
+ int num_jmp_reg = 0; // number of jmp *reg met when switch mode is off or when in current switch case
+ int total_num_jmp_reg = 0; // number of total jmp *reg met
+ struct AdvWalkContext * jmp_reg_ctx[MAXJMPREG]; // context of jmp *reg met when switch mode is off or when in current switch case
+ struct AdvWalkContext * jmp_reg_switch_ctx[MAXJMPREG]; // context of jmp *reg used in switch cases
+ struct AdvWalkContext * jmp_reg_switch_backup_ctx = NULL; // context of the first jmp *reg used in switch cases
+
+ int cur_jmp_reg_switch = 0; // current switch table
+ int num_jmp_reg_switch = 0; // number of switch table
+ int jmp_reg_switch_case = 0; // case number in current switch table
+ unsigned char * jmp_reg_switch_pc = NULL; // the start pc of current switch case
+ unsigned char * jmp_reg_switch_pc_old = NULL; // backup for deleteing context of jump target
+ unsigned char * jmp_reg_switch_base = NULL; // start pc for checking offsets
+ int max_jmp_reg_switch_case = 2;
+#if WSIZE(32)
+ int max_switch_pc_offset = 512;
+#else // WSIZE(64)
+ int max_switch_pc_offset = 1024;
+#endif
+ int expected_num_jmp_reg = 1; // should be smaller than MAXJMPREG
+ int max_num_jmp_reg_seen = 4; // try to resolve return if there are so many such instructions
+
+
+ int save_ctx = 0; // flag to save walk context in the cache to speed up unwind
+ struct WalkContext wctx_pc_save;
+ if (do_walk == 0)
+ // do_walk is the flag indicating not walking through the instructions, resolving the RA from the stack fp first
+ __collector_memcpy (&wctx_pc_save, wctx, sizeof (struct WalkContext));
+
+startWalk:
+ if (do_walk == 0)
+ { // try to resolve RA from stack frame pointer
+ if (OmpCurCtxs == NULL || OmpCtxs == NULL || OmpVals == NULL || OmpRAs == NULL)
+ {
+ do_walk = 1;
+ goto startWalk;
+ }
+ // before goto checkFP, try the RA from cache (key: WalkContext -> value: caller's WalkContext))
+ uint64_t idx = wctx->pc * ROOT_IDX;
+ uint32_t val = OmpVals[idx % OmpValTableSize];
+ idx = (idx + val) * ROOT_IDX;
+#ifdef USE_18434988_OMP_CACHE_WORKAROUND
+ // Check ra: if it is 0 - then cache is invalid
+ uint64_t idx4;
+ idx4 = (idx + val) * ROOT_IDX;
+ idx4 = (idx4 + val) * ROOT_IDX;
+ if (0 == OmpRAs[ idx4 % OmpValTableSize ]) // Invalid cache
+ goto checkFP;
+#endif
+ struct WalkContext saved_ctx;
+ __collector_memcpy (&saved_ctx, &OmpCurCtxs[ idx % OmpValTableSize ], sizeof (struct WalkContext));
+ if (wctx->pc == saved_ctx.pc
+ && wctx->sp == saved_ctx.sp
+ && wctx->fp == saved_ctx.fp
+ && wctx->tbgn == saved_ctx.tbgn
+ && wctx->tend == saved_ctx.tend)
+ { // key match, RA may be valid
+ idx = (idx + val) * ROOT_IDX;
+ unsigned long *sp = NULL;
+ unsigned long fp = wctx->fp;
+ int from_fp = 0;
+ if (val == RA_END_OF_STACK)
+ {
+ DprintfT (SP_DUMP_UNWIND, "find_i386_ret_addr:%d -- RA_END_OF_STACK: pc=0x%lx\n", __LINE__, wctx->pc);
+ __collector_memcpy (wctx, &OmpCtxs[ idx % OmpValTableSize ], sizeof (struct WalkContext));
+ return val;
+ }
+ else
+ {
+ if (fp < wctx->sp || fp >= wctx->sbase - sizeof (*sp))
+ {
+ TprintfT (DBG_LT1, "omp_cache_get -- wrong fp: pc=0x%lx\n", wctx->pc);
+ sp = (unsigned long *) (OmpCtxs[ idx % OmpValTableSize ].sp);
+ sp--;
+ if (sp < cur->sp_safe || (unsigned long) sp >= wctx->sbase)
+ {
+ goto checkFP;
+ }
+ unsigned long ra = *sp;
+ uint64_t idx2 = (idx + val) * ROOT_IDX;
+ if (OmpRAs[ idx2 % OmpValTableSize ] == ra)
+ {
+ __collector_memcpy (wctx, &OmpCtxs[ idx % OmpValTableSize ], sizeof (struct WalkContext));
+ TprintfT (DBG_LT1, "omp_cache_get -- ra match with target sp: pc=0x%lx, ra=0x%lx, val=%d\n", wctx->pc, ra, val);
+ return val;
+ }
+ TprintfT (DBG_LT1, "omp_cache_get -- ra mismatch: ra=0x%lx, expected ra=0x%lx, val=%d\n", ra, OmpRAs[ idx2 % OmpValTableSize ], val);
+ goto checkFP;
+ }
+ sp = (unsigned long *) fp;
+ from_fp = 1;
+ }
+
+ uint64_t idx2 = (idx + val) * ROOT_IDX;
+ unsigned long ra = *sp++;
+ if (from_fp)
+ {
+ unsigned long tbgn = wctx->tbgn;
+ unsigned long tend = wctx->tend;
+ if (ra < tbgn || ra >= tend)
+ {
+ sp = (unsigned long *) (OmpCtxs[ idx % OmpValTableSize ].sp);
+ sp--;
+ //if (sp < cur->sp_safe - 16 || (unsigned long)sp >= wctx->sbase - sizeof(*sp)) {
+ // The check above was replaced with the check below,
+ // because we do not know why "- 16" and "- sizeof(*sp)" was used.
+ if (sp < cur->sp_safe || (unsigned long) sp >= wctx->sbase)
+ goto checkFP;
+ else
+ ra = *sp;
+ }
+ }
+ if (OmpRAs[ idx2 % OmpValTableSize ] == ra)
+ {
+ TprintfT (DBG_LT1, "omp_cache_get -- ra match: pc=0x%lx\n", wctx->pc);
+ __collector_memcpy (wctx, &OmpCtxs[ idx % OmpValTableSize ], sizeof (struct WalkContext));
+ return val;
+ }
+ }
+ goto checkFP;
+ }
+ else
+ {
+ CALL_UTIL (memset)(jmp_reg_ctx, 0, MAXJMPREG * sizeof (struct AdvWalkContext *));
+ CALL_UTIL (memset)(jmp_reg_switch_ctx, 0, MAXJMPREG * sizeof (struct AdvWalkContext *));
+ }
+ while (cnt--)
+ {
+ if (nctx == 0 && (num_jmp_reg == expected_num_jmp_reg || jmp_reg_switch_mode == 1))
+ { // no context available, try jmp switch mode
+ int i = 0;
+ if (num_jmp_reg == expected_num_jmp_reg)
+ jmp_reg_switch_mode = 0; // first jmp reg expected, restart switch mode
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: begin switch mode, num_jmp_reg = %d, jmp_reg_switch_backup_ctx=%p, jmp_reg_switch_case=%d, jmp_reg_switch_mode=%d.\n",
+ num_jmp_reg, jmp_reg_switch_backup_ctx, jmp_reg_switch_case, jmp_reg_switch_mode);
+ // the ideal asm of switch is
+ // jmp reg
+ // ...//case 1
+ // ret
+ // ...//case 2
+ // ret
+ // ...//etc
+ if (jmp_reg_switch_mode == 0)
+ {
+ num_jmp_reg_switch = num_jmp_reg; // backup num_jmp_reg
+ jmp_reg_switch_mode = 1; // begin switch mode
+ for (i = 0; i < num_jmp_reg_switch; i++)
+ {
+ if (jmp_reg_switch_ctx[i] == NULL)
+ jmp_reg_switch_ctx[i] = (struct AdvWalkContext*) alloca (sizeof (*jmp_reg_switch_ctx[i]));
+ if (jmp_reg_switch_ctx[i] != NULL)
+ { // backup jmp_reg_ctx
+ __collector_memcpy (jmp_reg_switch_ctx[i], jmp_reg_ctx[i], sizeof (*jmp_reg_switch_ctx[i]));
+ cur_jmp_reg_switch = 0; // reset the current switch table
+ jmp_reg_switch_case = 0; // reset the case number in current switch table
+ }
+ }
+ if (jmp_reg_switch_backup_ctx == NULL)
+ { // only backup when the first jmp *reg is met for restoring later, if switch mode fails to resolve RA
+ jmp_reg_switch_backup_ctx = (struct AdvWalkContext*) alloca (sizeof (*jmp_reg_switch_backup_ctx));
+ if (jmp_reg_switch_backup_ctx != NULL)
+ __collector_memcpy (jmp_reg_switch_backup_ctx, cur, sizeof (*cur));
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: back up context for switch mode.\n");
+ }
+ }
+ if (jmp_reg_switch_mode == 1)
+ { // in the process of trying switch cases
+ if (cur_jmp_reg_switch == num_jmp_reg_switch)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: have tried all switch with max_jmp_reg_switch_case for each\n");
+ if (jmp_reg_switch_backup_ctx != NULL)
+ __collector_memcpy (cur, jmp_reg_switch_backup_ctx, sizeof (*cur));
+ int rc = process_return_real (wctx, cur, 0);
+ if (rc == RA_SUCCESS)
+ {
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc);
+ return rc;
+ }
+ break; // have tried all switch with max_jmp_reg_switch_case for each, goto checkFP
+ }
+ unsigned char *npc = jmp_reg_switch_ctx[cur_jmp_reg_switch]->pc;
+ if (jmp_reg_switch_case == 0)
+ // first switch case
+ npc = check_modrm (npc); // pc next to "jmp reg" instruction
+ else if (jmp_reg_switch_pc != NULL)
+ npc = jmp_reg_switch_pc; // // pc next to "ret" instruction of previous case
+ else
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: unexpected jum switch mode situation, jmp_reg_switch_case=%d, jmp_reg_switch_pc=%p\n",
+ jmp_reg_switch_case, jmp_reg_switch_pc);
+ break; //goto checkFP
+ }
+ jmp_reg_switch_base = npc;
+ struct AdvWalkContext *new = buf + nctx;
+ nctx += 1;
+ __collector_memcpy (new, jmp_reg_switch_ctx[cur_jmp_reg_switch], sizeof (*new));
+ new->pc = npc;
+ cur = new; /* advance the new context first */
+ jmp_reg_switch_pc = NULL;
+ jmp_reg_switch_case++;
+ if (jmp_reg_switch_case == max_jmp_reg_switch_case)
+ { // done many cases, change to another switch table
+ cur_jmp_reg_switch++;
+ jmp_reg_switch_case = 0;
+ }
+ }
+ num_jmp_reg = 0;
+ }
+ if (jmp_reg_switch_mode == 1)
+ { // when processing switch cases, check pc each time
+ unsigned long tbgn = wctx->tbgn;
+ unsigned long tend = wctx->tend;
+ if ((unsigned long) (cur->pc) < tbgn || (unsigned long) (cur->pc) >= tend)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: pc out of range, pc=0x%lx\n", (unsigned long) (cur->pc));
+ break;
+ }
+ if (jmp_reg_switch_base != NULL && cur->pc > jmp_reg_switch_base + max_switch_pc_offset)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: limit the walk offset after jmp reg instruction\n");
+ if (jmp_reg_switch_backup_ctx != NULL)
+ __collector_memcpy (cur, jmp_reg_switch_backup_ctx, sizeof (*cur));
+ int rc = process_return_real (wctx, cur, 0);
+ if (rc == RA_SUCCESS)
+ {
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc);
+ return rc;
+ }
+ break; // limit the walk offset after jmp reg instruction, got checkFP
+ }
+ }
+
+ if (nctx == 0)
+ break;
+// dump_targets (__LINE__, ntrg, targets);
+ while (cur->pc > targets[cur->tidx])
+ cur->tidx += 1;
+ if (cur->pc == targets[cur->tidx])
+ {
+ /* Stop analysis. Delete context. */
+ if (jmp_reg_switch_mode == 0 || cur->pc != jmp_reg_switch_pc_old)
+ {
+ if (jmp_reg_switch_mode == 1 && nctx == 1 && jmp_reg_switch_pc == NULL)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d old target, cur->pc=%p, jmp_reg_switch_pc=%p, nctx=%d\n",
+ __LINE__, cur->pc, jmp_reg_switch_pc, nctx);
+ jmp_reg_switch_pc = cur->pc; // save cp before delete context, may be used as a start of switch case
+ jmp_reg_switch_pc_old = jmp_reg_switch_pc;
+ }
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, old target.\n", __LINE__);
+ DELETE_CURCTX ();
+ if (cur >= buf + nctx)
+ cur = buf;
+ continue;
+ }
+ if (jmp_reg_switch_mode == 1 && cur->pc == jmp_reg_switch_pc_old)
+ jmp_reg_switch_pc_old = NULL; // reset jmp_reg_switch_pc_old to delete the context later when cur->pc != jmp_reg_switch_pc_old
+ }
+
+ /* let's walk the next x86 instruction */
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d cur:%ld pc=0x%lx %02x %02x %02x %02x %02x %02x %02x sp=0x%lx\n",
+ __LINE__, (long) (cur - buf), (unsigned long) cur->pc,
+ (int) cur->pc[0], (int) cur->pc[1], (int) cur->pc[2],
+ (int) cur->pc[3], (int) cur->pc[4], (int) cur->pc[5],
+ (int) cur->pc[6], (unsigned long) cur->sp);
+ int v = 4; /* Operand size */
+ int a = 4; /* Address size */
+ /* int W = 0; REX.W bit */
+#if WSIZE(64)
+ int R = 0; /* REX.R bit */
+#endif
+ int X = 0; /* REX.X bit */
+ int B = 0; /* REX.B bit */
+ /* Check prefixes */
+ int done = 0;
+ while (!done)
+ {
+ opcode = *cur->pc++;
+ switch (opcode)
+ {
+ case 0x66: /* opd size override */
+ v = 2;
+ break;
+ case 0x67: /*addr size override */
+ a = 2;
+ break;
+#if WSIZE(64)
+ case 0x40: /* REX */
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ case 0x47:
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f:
+ B = (opcode & 0x1) ? 8 : 0;
+ X = (opcode & 0x2) ? 8 : 0;
+ R = (opcode & 0x4) ? 8 : 0;
+ if (opcode & 0x8) /* 64 bit operand size */
+ v = 8;
+ opcode = *cur->pc++;
+ done = 1;
+ break;
+#endif
+ default:
+ done = 1;
+ break;
+ }
+ }
+ int z = (v == 8) ? 4 : v;
+ switch (opcode)
+ {
+ case 0x0: /* add Eb,Gb */
+ case 0x01: /* add Ev,Gv */
+ case 0x02: /* add Gb,Eb */
+ case 0x03: /* add Gv,Ev */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x04: /* add %al,Ib */
+ cur->pc += 1;
+ break;
+ case 0x05: /* add %eax,Iz */
+ cur->pc += z;
+ break;
+ case 0x06: /* push es */
+ cur->sp -= 1;
+ break;
+ case 0x07: /* pop es */
+ cur->sp += 1;
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ cur->sp_safe = cur->sp - RED_ZONE;
+ break;
+ case 0x08: /* or Eb,Gb */
+ case 0x09: /* or Ev,Gv */
+ case 0x0a: /* or Gb,Eb */
+ case 0x0b: /* or Gv,Ev */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x0c: /* or %al,Ib */
+ cur->pc += 1;
+ break;
+ case 0x0d: /* or %eax,Iz */
+ cur->pc += z;
+ break;
+ case 0x0e: /* push cs */
+ cur->sp -= 1;
+ break;
+ case 0x0f: /* two-byte opcodes */
+ extop = *cur->pc++;
+ switch (extop)
+ { /* RTM or HLE */
+ case 0x01:
+ extop2 = *cur->pc;
+ switch (extop2)
+ {
+ case 0xd5: /* xend */
+ case 0xd6: /* xtest */
+ cur->pc++;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 0x03:
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x0b:
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, undefined instruction. opcode=0x%02x\n",
+ __LINE__, (int) opcode);
+ DELETE_CURCTX ();
+ break;
+ case 0x05: /* syscall */
+ case 0x34: /* sysenter */
+ if (cur->rax == __NR_exit)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode=0x%02x\n",
+ __LINE__, (int) opcode);
+ DELETE_CURCTX ();
+ break;
+ }
+ else if (cur->rax == __NR_rt_sigreturn)
+ {
+ if (jmp_reg_switch_mode == 1)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d give up return address under jmp switch mode, opcode=0x%02x\n",
+ __LINE__, (int) opcode);
+ goto checkFP;
+ }
+ wctx->sp = (unsigned long) cur->sp;
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_RT_SIGRETURN);
+ return RA_RT_SIGRETURN;
+ }
+#if WSIZE(32)
+ else if (cur->rax == __NR_sigreturn)
+ {
+ if (jmp_reg_switch_mode == 1)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: give up return address under jmp switch mode, opcode = 0x34\n");
+ goto checkFP;
+ }
+ wctx->sp = (unsigned long) cur->sp;
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_SIGRETURN);
+ return RA_SIGRETURN;
+ }
+#endif
+ /* Check for Linus' trick in the vsyscall page */
+ while (*cur->pc == 0x90) /* nop */
+ cur->pc++;
+ if (*cur->pc == 0xeb) /* jmp imm8 */
+ cur->pc += 2;
+ break;
+ case 0x0d: /* nop Ev */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x10: /* xmm Vq,Wq */
+ case 0x11:
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x18: /* prefetch */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x1E: /* endbr64/endbr32 (f3 0f 1e .. ) is parsing as repz nop edx */
+ cur->pc += 2;
+ break;
+ case 0x1f: /* nop Ev */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x28: /* xmm Vq,Wq */
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ case 0x2f:
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x30: /* wrmsr */
+ case 0x31: /* rdtsc */
+ case 0x32: /* rdmsr */
+ case 0x33: /* rdpmc */
+ break;
+ /* case 0x34: sysenter (see above) */
+ case 0x38: case 0x3a:
+ extop2 = *cur->pc++;
+ cur->pc = check_modrm (cur->pc);
+ // 21275311 Unwind failure in native stack for java application running on jdk8
+ // Three-byte opcodes "66 0f 3a ??" should consume an additional "immediate" byte.
+ if (extop == 0x3a)
+ cur->pc++;
+ break;
+ case 0x40: case 0x41: case 0x42: case 0x43: /* CMOVcc Gv,Ev */
+ case 0x44: case 0x45: case 0x46: case 0x47:
+ case 0x48: case 0x49: case 0x4a: case 0x4b:
+ case 0x4c: case 0x4d: case 0x4e: case 0x4f:
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x50: case 0x51: case 0x52: case 0x53:
+ case 0x54: case 0x55: case 0x56: case 0x57:
+ case 0x58: case 0x59: case 0x5a: case 0x5b:
+ case 0x5c: case 0x5d: case 0x5e: case 0x5f:
+ case 0x60: case 0x61: case 0x62: case 0x63:
+ case 0x64: case 0x65: case 0x66: case 0x67:
+ case 0x68: case 0x69: case 0x6a: case 0x6b:
+ case 0x6c: case 0x6d: case 0x6e: case 0x6f:
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x70: case 0x71: case 0x72: case 0x73:
+ cur->pc = check_modrm (cur->pc) + 1;
+ break;
+ case 0x74: case 0x75: case 0x76:
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x77:
+ break;
+ case 0x7c: case 0x7d: case 0x7e: case 0x7f:
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x80: case 0x81: case 0x82: case 0x83: /* Jcc Jz */
+ case 0x84: case 0x85: case 0x86: case 0x87:
+ case 0x88: case 0x89: case 0x8a: case 0x8b:
+ case 0x8c: case 0x8d: case 0x8e: case 0x8f:
+ immv = read_int (cur->pc, z);
+ cur->pc += z;
+ if (nctx < (jmp_reg_switch_mode ? MAXJMPREGCTX : MAXCTX))
+ {
+ int tidx = 0;
+ unsigned char *npc = cur->pc + immv;
+ if ((unsigned long) npc < wctx->tbgn || (unsigned long) npc >= wctx->tend)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode=0x%02x\n",
+ __LINE__, (int) opcode);
+ DELETE_CURCTX ();
+ break;
+ }
+ if (is_after_ret (npc))
+ break;
+ while (npc > targets[tidx])
+ tidx += 1;
+ if (npc != targets[tidx])
+ {
+ if (ntrg < MAXTRGTS)
+ {
+ for (int i = 0; i < nctx; i++)
+ if (buf[i].tidx >= tidx)
+ buf[i].tidx++;
+
+ /* insert a new target */
+ for (int i = ntrg; i > tidx; i--)
+ targets[i] = targets[i - 1];
+ ntrg += 1;
+ targets[tidx++] = npc;
+ }
+ else
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d ntrg=max(%d)\n",
+ __LINE__, ntrg);
+ struct AdvWalkContext *new = buf + nctx;
+ nctx += 1;
+ __collector_memcpy (new, cur, sizeof (*new));
+ new->pc = npc;
+ new->tidx = tidx;
+ cur = new; /* advance the new context first */
+ continue;
+ }
+ }
+ else
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d nctx=max(%d)\n",
+ __LINE__, ntrg);
+ break;
+ case 0x90: case 0x91: case 0x92: case 0x93: /* setcc Eb */
+ case 0x94: case 0x95: case 0x96: case 0x97:
+ case 0x98: case 0x99: case 0x9a: case 0x9b:
+ case 0x9c: case 0x9d: case 0x9e: case 0x9f:
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xa0: /* push fs */
+ cur->sp -= 1;
+ break;
+ case 0xa1: /* pop fs */
+ cur->sp += 1;
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ cur->sp_safe = cur->sp - RED_ZONE;
+ break;
+ case 0xa2: /* cpuid */
+ break;
+ case 0xa3: /* bt Ev,Gv */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xa4: /* shld Ev,Gv,Ib */
+ cur->pc = check_modrm (cur->pc);
+ cur->pc += 1;
+ break;
+ case 0xa5: /* shld Ev,Gv,%cl */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xa8: /* push gs */
+ cur->sp -= 1;
+ break;
+ case 0xa9: /* pop gs */
+ cur->sp += 1;
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ cur->sp_safe = cur->sp - RED_ZONE;
+ break;
+ case 0xaa: /* rsm */
+ break;
+ case 0xab: /* bts Ev,Gv */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xac: /* shrd Ev,Gv,Ib */
+ cur->pc = check_modrm (cur->pc);
+ cur->pc += 1;
+ break;
+ case 0xad: /* shrd Ev,Gv,%cl */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xae: /* group15 */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xaf: /* imul Gv,Ev */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xb1: /* cmpxchg Ev,Gv */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xb3:
+ case 0xb6: /* movzx Gv,Eb */
+ case 0xb7: /* movzx Gv,Ew */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xba: /* group8 Ev,Ib */
+ cur->pc = check_modrm (cur->pc);
+ cur->pc += 1;
+ break;
+ case 0xbb: /* btc Ev,Gv */
+ case 0xbc: /* bsf Gv,Ev */
+ case 0xbd: /* bsr Gv,Ev */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xbe: /* movsx Gv,Eb */
+ case 0xbf: /* movsx Gv,Ew */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xc0: /* xadd Eb,Gb */
+ case 0xc1: /* xadd Ev,Gv */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xc2: /* cmpps V,W,Ib */
+ cur->pc = check_modrm (cur->pc);
+ cur->pc += 1;
+ break;
+ case 0xc3: /* movnti M,G */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xc6: /* shufps V,W,Ib */
+ cur->pc = check_modrm (cur->pc);
+ cur->pc += 1;
+ break;
+ case 0xc7: /* RDRAND */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xc8: case 0xc9: case 0xca: case 0xcb: /* bswap */
+ case 0xcc: case 0xcd: case 0xce: case 0xcf:
+ break;
+ case 0xd0: case 0xd1: case 0xd2: case 0xd3:
+ case 0xd4: case 0xd5: case 0xd6: case 0xd7:
+ case 0xd8: case 0xd9: case 0xda: case 0xdb:
+ case 0xdc: case 0xdd: case 0xde: case 0xdf:
+ case 0xe0: case 0xe1: case 0xe2: case 0xe3:
+ case 0xe4: case 0xe5: case 0xe6: case 0xe7:
+ case 0xe8: case 0xe9: case 0xea: case 0xeb:
+ case 0xec: case 0xed: case 0xee: case 0xef:
+ case 0xf0: case 0xf1: case 0xf2: case 0xf3:
+ case 0xf4: case 0xf5: case 0xf6: case 0xf7:
+ case 0xf8: case 0xf9: case 0xfa: case 0xfb:
+ case 0xfc: case 0xfd: case 0xfe: case 0xff:
+ cur->pc = check_modrm (cur->pc);
+ break;
+ default:
+ if (jmp_reg_switch_mode == 1 && extop == 0x0b)
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d invalid opcode ub2: 0x0f %x jmp_reg_switch_mode=%d\n",
+ __LINE__, (int) extop, jmp_reg_switch_mode);
+ else
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d unknown opcode: 0x0f %x jmp_reg_switch_mode=%d\n",
+ __LINE__, (int) extop, jmp_reg_switch_mode);
+ DELETE_CURCTX ();
+ }
+ break;
+ }
+ break;
+ case 0x10: /* adc Eb,Gb */
+ case 0x11: /* adc Ev,Gv */
+ case 0x12: /* adc Gb,Eb */
+ case 0x13: /* adc Gv,Ev */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x14: /* adc %al,Ib */
+ cur->pc += 1;
+ break;
+ case 0x15: /* adc %eax,Iz */
+ cur->pc += z;
+ break;
+ case 0x16: /* push ss */
+ cur->sp -= 1;
+ break;
+ case 0x17: /* pop ss */
+ cur->sp += 1;
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ cur->sp_safe = cur->sp - RED_ZONE;
+ break;
+ case 0x18: /* sbb Eb,Gb */
+ case 0x19: /* sbb Ev,Gv */
+ case 0x1a: /* sbb Gb,Eb */
+ case 0x1b: /* sbb Gv,Ev */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x1c: /* sbb %al,Ib */
+ cur->pc += 1;
+ break;
+ case 0x1d: /* sbb %eax,Iz */
+ cur->pc += z;
+ break;
+ case 0x1e: /* push ds */
+ cur->sp -= 1;
+ break;
+ case 0x1f: /* pop ds */
+ cur->sp += 1;
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ cur->sp_safe = cur->sp - RED_ZONE;
+ break;
+ case 0x20: /* and Eb,Gb */
+ case 0x21: /* and Ev,Gv */
+ case 0x22: /* and Gb,Eb */
+ case 0x23: /* and Gv,Ev */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x24: /* and %al,Ib */
+ cur->pc += 1;
+ break;
+ case 0x25: /* and %eax,Iz */
+ cur->pc += z;
+ break;
+ case 0x26: /* seg=es prefix */
+ break;
+ case 0x27: /* daa */
+ break;
+ case 0x28: /* sub Eb,Gb */
+ case 0x29: /* sub Ev,Gv */
+ case 0x2a: /* sub Gb,Eb */
+ case 0x2b: /* sub Gv,Ev */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x2c: /* sub %al,Ib */
+ cur->pc += 1;
+ break;
+ case 0x2d: /* sub %eax,Iz */
+ cur->pc += z;
+ break;
+ case 0x2e: /* seg=cs prefix */
+ break;
+ case 0x2f: /* das */
+ break;
+ case 0x30: /* xor Eb,Gb */
+ case 0x31: /* xor Ev,Gv */
+ case 0x32: /* xor Gb,Eb */
+ case 0x33: /* xor Gv,Ev */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x34: /* xor %al,Ib */
+ cur->pc += 1;
+ break;
+ case 0x35: /* xor %eax,Iz */
+ cur->pc += z;
+ break;
+ case 0x36: /* seg=ss prefix */
+ break;
+ case 0x37: /* aaa */
+ break;
+ case 0x38: /* cmp Eb,Gb */
+ case 0x39: /* cmp Ev,Gv */
+ case 0x3a: /* cmp Gb,Eb */
+ case 0x3b: /* cmp Gv,Ev */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x3c: /* cmp %al,Ib */
+ cur->pc += 1;
+ break;
+ case 0x3d: /* cmp %eax,Iz */
+ cur->pc += z;
+ break;
+ case 0x3e: /* seg=ds prefix */
+ break;
+ case 0x3f: /* aas */
+ break;
+#if WSIZE(32)
+ case 0x40: /* inc %eax */
+ case 0x41: /* inc %ecx */
+ case 0x42: /* inc %edx */
+ case 0x43: /* inc %ebx */
+ break;
+ case 0x44: /* inc %esp */
+ /* Can't be a valid stack pointer - delete context */
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0x44.\n", __LINE__);
+ DELETE_CURCTX ();
+ break;
+ case 0x45: /* inc %ebp */
+ case 0x46: /* inc %esi */
+ case 0x47: /* inc %edi */
+ case 0x48: /* dec %eax */
+ case 0x49: /* dec %ecx */
+ case 0x4a: /* dec %edx */
+ case 0x4b: /* dec %ebx */
+ break;
+ case 0x4c: /* dec %esp */
+ /* Can't be a valid stack pointer - delete context */
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0x4c.\n", __LINE__);
+ DELETE_CURCTX ();
+ break;
+ case 0x4d: /* dec %ebp */
+ case 0x4e: /* dec %esi */
+ case 0x4f: /* dec %edi */
+ break;
+#endif
+ case 0x50: /* push %eax */
+ case 0x51: /* push %ecx */
+ case 0x52: /* push %edx */
+ case 0x53: /* push %ebx */
+ case 0x54: /* push %esp */
+ case 0x55: /* push %ebp */
+ case 0x56: /* push %esi */
+ case 0x57: /* push %edi */
+ cur->sp -= 1;
+ reg = OPC_REG (opcode);
+ if (reg == RBP)
+ {
+#if 0
+ /* Don't do this check yet. Affects tail calls. */
+ /* avoid other function's prologue */
+ if ((cur->pc[0] == 0x89 && cur->pc[1] == 0xe5) ||
+ (cur->pc[0] == 0x8b && cur->pc[1] == 0xec))
+ {
+ /* mov %esp,%ebp */
+ DELETE_CURCTX ();
+ break;
+ }
+#endif
+ if (cur->fp_loc == NULL)
+ {
+ cur->fp_loc = cur->sp;
+ cur->fp_sav = cur->fp;
+ }
+ }
+ break;
+ case 0x58: /* pop %eax */
+ case 0x59: /* pop %ecx */
+ case 0x5a: /* pop %edx */
+ case 0x5b: /* pop %ebx */
+ case 0x5c: /* pop %esp */
+ case 0x5d: /* pop %ebp */
+ case 0x5e: /* pop %esi */
+ case 0x5f: /* pop %edi */
+ reg = OPC_REG (opcode);
+ cur->regs[reg] = 0;
+ if (isInside ((unsigned long) cur->sp, (unsigned long) cur->sp_safe, wctx->sbase))
+ cur->regs[reg] = *cur->sp;
+ DprintfT (SP_DUMP_UNWIND, "stack_unwind:%d cur->regs[%d]=0x%lx\n",
+ __LINE__, reg, (unsigned long) cur->regs[reg]);
+ if (reg == RDX)
+ {
+ if (cur->sp >= cur->sp_safe &&
+ (unsigned long) cur->sp < wctx->sbase)
+ cur->rdx = *cur->sp;
+ }
+ else if (reg == RBP)
+ {
+ if (cur->fp_loc == cur->sp)
+ {
+ cur->fp = cur->fp_sav;
+ cur->fp_loc = NULL;
+ }
+ else if (cur->sp >= cur->sp_safe &&
+ (unsigned long) cur->sp < wctx->sbase)
+ cur->fp = (unsigned long*) (*cur->sp);
+ }
+ else if (reg == RSP)
+ {
+ /* f.e. JVM I2CAdapter */
+ if (cur->sp >= cur->sp_safe && (unsigned long) cur->sp < wctx->sbase)
+ {
+ unsigned long *nsp = (unsigned long*) (*cur->sp);
+ if (nsp >= cur->sp && nsp <= cur->fp)
+ {
+ cur->sp = nsp;
+ }
+ else
+ {
+ DprintfT (SP_DUMP_UNWIND, "stack_unwind%d give up return address, opcode=0x%02x\n",
+ __LINE__, opcode);
+ goto checkFP;
+ }
+ }
+ else
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d give up return address, opcode=0x%02x\n",
+ __LINE__, opcode);
+ goto checkFP;
+ }
+ break;
+ }
+ cur->sp += 1;
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ {
+ cur->sp_safe = cur->sp - RED_ZONE;
+ }
+ break;
+ case 0x60: /* pusha(d) */
+ cur->sp -= 8;
+ break;
+ case 0x61: /* popa(d) */
+ cur->sp += 8;
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ cur->sp_safe = cur->sp - RED_ZONE;
+ break;
+ case 0x62: /* group AVX, 4-bytes EVEX prefix */
+ {
+ unsigned char *pc = cur->pc - 1; // points to the beginning of the instruction
+ int len = parse_x86_AVX_instruction (pc);
+ if (len < 4)
+ {
+ DELETE_CURCTX ();
+ }
+ else
+ {
+ pc += len;
+ cur->pc = pc;
+ }
+ }
+ break;
+ case 0x63: /* arpl Ew,Gw (32) movsxd Gv,Ev (64)*/
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x64: /* seg=fs prefix */
+ case 0x65: /* seg=gs prefix */
+ break;
+ case 0x66: /* opd size override */
+ case 0x67: /* addr size override */
+ break;
+ case 0x68: /* push Iz */
+ cur->sp = (unsigned long*) ((long) cur->sp - z);
+ cur->pc += z;
+ break;
+ case 0x69: /* imul Gv,Ev,Iz */
+ cur->pc = check_modrm (cur->pc);
+ cur->pc += z;
+ break;
+ case 0x6a: /* push Ib */
+ cur->sp = (unsigned long*) ((long) cur->sp - v);
+ cur->pc += 1;
+ break;
+ case 0x6b: /* imul Gv,Ev,Ib */
+ cur->pc = check_modrm (cur->pc);
+ cur->pc += 1;
+ break;
+ case 0x6c: case 0x6d: case 0x6e: case 0x6f:
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x70: /* jo Jb */
+ case 0x71: /* jno Jb */
+ case 0x72: /* jb Jb */
+ case 0x73: /* jnb Jb */
+ case 0x74: /* jz Jb */
+ case 0x75: /* jnz Jb */
+ case 0x76: /* jna Jb */
+ case 0x77: /* ja Jb */
+ case 0x78: /* js Jb */
+ case 0x79: /* jns Jb */
+ case 0x7a: /* jp Jb */
+ case 0x7b: /* jnp Jb */
+ case 0x7c: /* jl Jb */
+ case 0x7d: /* jge Jb */
+ case 0x7e: /* jle Jb */
+ case 0x7f: /* jg Jb */
+ imm8 = *(char*) cur->pc++;
+ if (nctx < (jmp_reg_switch_mode ? MAXJMPREGCTX : MAXCTX))
+ {
+ int tidx = 0;
+ unsigned char *npc = cur->pc + imm8;
+ if (is_after_ret (npc))
+ break;
+ while (npc > targets[tidx])
+ tidx += 1;
+ if (npc != targets[tidx])
+ {
+ if (ntrg < MAXTRGTS)
+ {
+ for (int i = 0; i < nctx; i++)
+ if (buf[i].tidx >= tidx)
+ buf[i].tidx++;
+
+ /* insert a new target */
+ for (int i = ntrg; i > tidx; i--)
+ targets[i] = targets[i - 1];
+ ntrg += 1;
+ targets[tidx++] = npc;
+ }
+ else
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d ntrg(%d)=max\n", __LINE__, ntrg);
+ struct AdvWalkContext *new = buf + nctx;
+ nctx += 1;
+ __collector_memcpy (new, cur, sizeof (*new));
+ new->pc = npc;
+ new->tidx = tidx;
+ cur = new; /* advance the new context first */
+ continue;
+ }
+ }
+ else
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d nctx(%d)=max\n", __LINE__, nctx);
+ break;
+ case 0x80: /* group1 Eb,Ib */
+ cur->pc = check_modrm (cur->pc);
+ cur->pc += 1;
+ break;
+ case 0x81: /* group1 Ev,Iz */
+ modrm = *cur->pc;
+ if (MRM_MOD (modrm) == 0xc0 && MRM_REGS (modrm) == RSP)
+ {
+ int immz = read_int (cur->pc + 1, z);
+ extop = MRM_EXT (modrm);
+ if (extop == 0) /* add imm32,%esp */
+ cur->sp = (unsigned long*) ((long) cur->sp + immz);
+ else if (extop == 4) /* and imm32,%esp */
+ cur->sp = (unsigned long*) ((long) cur->sp & immz);
+ else if (extop == 5) /* sub imm32,%esp */
+ cur->sp = (unsigned long*) ((long) cur->sp - immz);
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ cur->sp_safe = cur->sp - RED_ZONE;
+ }
+ cur->pc = check_modrm (cur->pc);
+ cur->pc += z;
+ break;
+ case 0x82: /* group1 Eb,Ib */
+ cur->pc = check_modrm (cur->pc);
+ cur->pc += 1;
+ break;
+ case 0x83: /* group1 Ev,Ib */
+ modrm = *cur->pc;
+ if (MRM_MOD (modrm) == 0xc0 && MRM_REGS (modrm) == RSP)
+ {
+ imm8 = (char) cur->pc[1]; /* sign extension */
+ extop = MRM_EXT (modrm);
+ if (extop == 0) /* add imm8,%esp */
+ cur->sp = (unsigned long*) ((long) cur->sp + imm8);
+ else if (extop == 4) /* and imm8,%esp */
+ cur->sp = (unsigned long*) ((long) cur->sp & imm8);
+ else if (extop == 5) /* sub imm8,%esp */
+ cur->sp = (unsigned long*) ((long) cur->sp - imm8);
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ cur->sp_safe = cur->sp - RED_ZONE;
+ }
+ cur->pc = check_modrm (cur->pc);
+ cur->pc += 1;
+ break;
+ case 0x84: /* test Eb,Gb */
+ case 0x85: /* test Ev,Gv */
+ case 0x86: /* xchg Eb,Gb */
+ case 0x87: /* xchg Ev,Gv */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x88: /* mov Eb,Gb */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x89: /* mov Ev,Gv */
+ modrm = *cur->pc;
+ if (MRM_MOD (modrm) == 0xc0)
+ {
+ if (MRM_REGS (modrm) == RBP && MRM_REGD (modrm) == RSP)
+ /* movl %esp,%ebp */
+ cur->fp = cur->sp;
+ else if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP)
+ { /* mov %ebp,%esp */
+ cur->sp = cur->fp;
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ cur->sp_safe = cur->sp - RED_ZONE;
+ if (wctx->fp == (unsigned long) cur->sp)
+ cur->cval = RA_FROMFP;
+ }
+ }
+ else if (MRM_MOD (modrm) == 0x80)
+ {
+ if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP)
+ {
+ if (cur->pc[1] == 0x24)
+ { /* mov %ebp,disp32(%esp) - JVM */
+ immv = read_int (cur->pc + 2, 4);
+ cur->fp_loc = (unsigned long*) ((char*) cur->sp + immv);
+ cur->fp_sav = cur->fp;
+ }
+ }
+ }
+ else if (MRM_MOD (modrm) == 0x40)
+ {
+ if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RDX)
+ {
+ if (cur->pc[1] == 0x24 && cur->pc[2] == 0x0)
+ { /* movl %edx,0(%esp) */
+ cur->ra_loc = cur->sp;
+ cur->ra_sav = cur->rdx;
+ }
+ }
+ else if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP)
+ {
+ if (cur->pc[1] == 0x24)
+ { /* mov %ebp,disp8(%esp) - JVM */
+ imm8 = ((char*) (cur->pc))[2];
+ cur->fp_loc = (unsigned long*) ((char*) cur->sp + imm8);
+ cur->fp_sav = cur->fp;
+ }
+ }
+ }
+ else if (MRM_MOD (modrm) == 0x0)
+ {
+ if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP)
+ {
+ if (cur->pc[1] == 0x24)
+ { /* mov %ebp,(%esp) */
+ cur->fp_loc = cur->sp;
+ cur->fp_sav = cur->fp;
+ }
+ }
+ else if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RDX)
+ {
+ if (cur->pc[1] == 0x24)
+ { /* movl %edx,(%esp) */
+ cur->ra_loc = cur->sp;
+ cur->ra_sav = cur->rdx;
+ }
+ }
+ }
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x8a: /* mov Gb,Eb */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x8b: /* mov Gv,Ev */
+ modrm = *cur->pc;
+ if (MRM_MOD (modrm) == 0xc0)
+ {
+ if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP)
+ /* mov %esp,%ebp */
+ cur->fp = cur->sp;
+ else if (MRM_REGS (modrm) == RBP && MRM_REGD (modrm) == RSP)
+ { /* mov %ebp,%esp */
+ cur->sp = cur->fp;
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ cur->sp_safe = cur->sp - RED_ZONE;
+ if (wctx->fp == (unsigned long) cur->sp)
+ cur->cval = RA_FROMFP;
+ }
+ }
+ else if (MRM_MOD (modrm) == 0x80)
+ {
+ if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP)
+ {
+ if (cur->pc[1] == 0x24)
+ { /* mov disp32(%esp),%ebp */
+ immv = read_int (cur->pc + 2, 4);
+ unsigned long *ptr = (unsigned long*) ((char*) cur->sp + immv);
+ if (cur->fp_loc == ptr)
+ {
+ cur->fp = cur->fp_sav;
+ cur->fp_loc = NULL;
+ }
+ else if (ptr >= cur->sp_safe && (unsigned long) ptr < wctx->sbase)
+ cur->fp = (unsigned long*) (*ptr);
+ }
+ }
+ }
+ else if (MRM_MOD (modrm) == 0x40)
+ {
+ if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP)
+ {
+ if (cur->pc[1] == 0x24)
+ { /* mov disp8(%esp),%ebp - JVM */
+ imm8 = ((char*) (cur->pc))[2];
+ unsigned long *ptr = (unsigned long*) ((char*) cur->sp + imm8);
+ if (cur->fp_loc == ptr)
+ {
+ cur->fp = cur->fp_sav;
+ cur->fp_loc = NULL;
+ }
+ else if (ptr >= cur->sp_safe && (unsigned long) ptr < wctx->sbase)
+ cur->fp = (unsigned long*) (*ptr);
+ }
+ }
+ }
+ else if (MRM_MOD (modrm) == 0x0)
+ {
+ if (MRM_REGS (modrm) == RSP && MRM_REGD (modrm) == RBP)
+ {
+ if (cur->pc[1] == 0x24)
+ { /* mov (%esp),%ebp */
+ if (cur->fp_loc == cur->sp)
+ {
+ cur->fp = cur->fp_sav;
+ cur->fp_loc = NULL;
+ }
+ else if (cur->sp >= cur->sp_safe &&
+ (unsigned long) cur->sp < wctx->sbase)
+ cur->fp = (unsigned long*) *cur->sp;
+ }
+ }
+ }
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x8c: /* mov Mw,Sw */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x8d: /* lea Gv,M */
+ modrm = *cur->pc;
+ if (MRM_REGD (modrm) == RSP)
+ {
+ unsigned char *pc = cur->pc;
+ // Mez: need to use always regs[RSP/RBP] instead cur->sp(or fp):
+ cur->regs[RSP] = (unsigned long) cur->sp;
+ cur->regs[RBP] = (unsigned long) cur->fp;
+ cur->pc++;
+ int mod = (modrm >> 6) & 3;
+ int r_m = modrm & 7;
+ long val = 0;
+ int undefRez = 0;
+ if (mod == 0x3)
+ val = getRegVal (cur, MRM_REGS (modrm), &undefRez);
+ else if (r_m == 4)
+ { // SP or R12. Decode SIB-byte.
+ int sib = *cur->pc++;
+ int scale = 1 << (sib >> 6);
+ int index = X | ((sib >> 3) & 7);
+ int base = B | (sib & 7);
+ if (mod == 0)
+ {
+ if ((base & 7) == 5)
+ { // BP or R13
+ if (index != 4) // SP
+ val += getRegVal (cur, index, &undefRez) * scale;
+ val += read_int (cur->pc, 4);
+ cur->pc += 4;
+ }
+ else
+ {
+ val += getRegVal (cur, base, &undefRez);
+ if (index != 4) // SP
+ val += getRegVal (cur, index, &undefRez) * scale;
+ }
+ }
+ else
+ {
+ val += getRegVal (cur, base, &undefRez);
+ if (index != 4) // SP
+ val += getRegVal (cur, index, &undefRez) * scale;
+ if (mod == 1)
+ {
+ val += read_int (cur->pc, 1);
+ cur->pc++;
+ }
+ else
+ { // mod == 2
+ val += read_int (cur->pc, 4);
+ cur->pc += 4;
+ }
+ }
+ }
+ else if (mod == 0)
+ {
+ if (r_m == 5)
+ { // BP or R13
+ val += read_int (cur->pc, 4);
+ cur->pc += 4;
+ }
+ else
+ val += getRegVal (cur, MRM_REGS (modrm), &undefRez);
+ }
+ else
+ { // mod == 1 || mod == 2
+ val += getRegVal (cur, MRM_REGS (modrm), &undefRez);
+ if (mod == 1)
+ {
+ val += read_int (cur->pc, 1);
+ cur->pc++;
+ }
+ else
+ { // mod == 2
+ val += read_int (cur->pc, 4);
+ cur->pc += 4;
+ }
+ }
+ if (undefRez)
+ {
+ DprintfT (SP_DUMP_UNWIND, "stack_unwind%d cannot calculate RSP. cur->pc=0x%lx val=0x%lx\n",
+ __LINE__, (unsigned long) cur->pc, (unsigned long) val);
+ goto checkFP;
+ }
+ cur->regs[MRM_REGD (modrm)] = val;
+ DprintfT (SP_DUMP_UNWIND, "stack_unwind%d cur->pc=0x%lx val=0x%lx wctx->sp=0x%lx wctx->sbase=0x%lx\n",
+ __LINE__, (unsigned long) cur->pc, (unsigned long) val,
+ (unsigned long) wctx->sp, (unsigned long) wctx->sbase);
+ if (cur->pc != check_modrm (pc))
+ DprintfT (SP_DUMP_UNWIND, "stack_unwind%d ERROR: cur->pc=0x%lx != check_modrm(0x%lx)=0x%lx\n",
+ __LINE__, (unsigned long) cur->pc, (unsigned long) pc,
+ (unsigned long) check_modrm (pc));
+ if (MRM_REGD (modrm) == RSP)
+ {
+ if (!isInside ((unsigned long) val, wctx->sp, wctx->sbase))
+ {
+ DprintfT (SP_DUMP_UNWIND, "stack_unwind%d cannot calculate RSP. cur->pc=0x%lx opcode=0x%02x val=0x%lx wctx->sp=0x%lx wctx->sbase=0x%lx\n",
+ __LINE__, (unsigned long) cur->pc, opcode, (unsigned long) val,
+ (unsigned long) wctx->sp, (unsigned long) wctx->sbase);
+ goto checkFP;
+ }
+ cur->sp = (unsigned long *) val;
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ cur->sp_safe = cur->sp - RED_ZONE;
+ }
+ }
+ else
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x8e: /* mov Sw,Ew */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x8f: /* pop Ev */
+ cur->pc = check_modrm (cur->pc);
+ cur->sp += 1;
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ cur->sp_safe = cur->sp - RED_ZONE;
+ break;
+ case 0x90: /* nop */
+ break;
+ case 0x91: /* xchg %eax,%ecx */
+ case 0x92: /* xchg %eax,%edx */
+ case 0x93: /* xchg %eax,%ebx */
+ case 0x94: /* xchg %eax,%esp XXXX */
+ case 0x95: /* xchg %eax,%ebp XXXX */
+ case 0x96: /* xchg %eax,%esi */
+ case 0x97: /* xchg %eax,%edi */
+ break;
+ case 0x98: /* cbw/cwde */
+ case 0x99: /* cwd/cwq */
+ break;
+ case 0x9a: /* callf Ap */
+ if (jmp_reg_switch_mode == 1)
+ {
+ struct AdvWalkContext* tmpctx = (struct AdvWalkContext *) alloca (sizeof (*cur));
+ __collector_memcpy (tmpctx, cur, sizeof (*cur));
+ int rc = process_return (wctx, tmpctx);
+ if (rc != RA_FAILURE)
+ {
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc);
+ return rc;
+ }
+ }
+ cur->pc += 2 + a;
+ break;
+ case 0x9b: /* fwait */
+ case 0x9c: /* pushf Fv */
+ case 0x9d: /* popf Fv */
+ case 0x9e: /* sahf */
+ case 0x9f: /* lahf */
+ break;
+ case 0xa0: /* mov al,Ob */
+ case 0xa1: /* mov eax,Ov */
+ case 0xa2: /* mov Ob,al */
+ case 0xa3: /* mov Ov,eax */
+ cur->pc += a;
+ break;
+ case 0xa4: /* movsb Yb,Xb */
+ case 0xa5: /* movsd Yv,Xv */
+ case 0xa6: /* cmpsb Yb,Xb */
+ case 0xa7: /* cmpsd Xv,Yv */
+ break;
+ case 0xa8: /* test al,Ib */
+ cur->pc += 1;
+ break;
+ case 0xa9: /* test eax,Iz */
+ cur->pc += z;
+ break;
+ case 0xaa: /* stosb Yb,%al */
+ case 0xab: /* stosd Yv,%eax */
+ case 0xac: /* lodsb %al,Xb */
+ case 0xad: /* lodsd %eax,Xv */
+ case 0xae: /* scasb %al,Yb */
+ case 0xaf: /* scasd %eax,Yv */
+ break;
+ case 0xb0: /* mov %al,Ib */
+ case 0xb1: /* mov %cl,Ib */
+ case 0xb2: /* mov %dl,Ib */
+ case 0xb3: /* mov %bl,Ib */
+ case 0xb4: /* mov %ah,Ib */
+ case 0xb5: /* mov %ch,Ib */
+ case 0xb6: /* mov %dh,Ib */
+ case 0xb7: /* mov %bh,Ib */
+ cur->pc += 1;
+ break;
+ case 0xb8: /* mov Iv,%eax */
+ case 0xb9: /* mov Iv,%ecx */
+ case 0xba: /* mov Iv,%edx */
+ case 0xbb: /* mov Iv,%ebx */
+ case 0xbc: /* mov Iv,%esp */
+ case 0xbd: /* mov Iv,%rbp */
+ case 0xbe: /* mov Iv,%esi */
+ case 0xbf: /* mov Iv,%edi */
+ reg = OPC_REG (opcode);
+ if (reg == RAX)
+ cur->rax = read_int (cur->pc, v);
+ cur->pc += v;
+ break;
+ case 0xc0: /* group2 Eb,Ib */
+ case 0xc1: /* group2 Ev,Ib */
+ cur->pc = check_modrm (cur->pc) + 1;
+ break;
+ case 0xc2: /* ret Iw */
+ /* In the dynamic linker we may see that
+ * the actual return address is at sp+immv,
+ * while sp points to the resolved address.
+ */
+ {
+ immv = read_int (cur->pc, 2);
+ int rc = process_return (wctx, cur);
+ if (rc != RA_FAILURE)
+ {
+ if (jmp_reg_switch_mode == 1)
+ {
+ DprintfT (SP_DUMP_UNWIND, "stack_unwind%d give up return address under jmp switch mode, opcode = 0xc2\n", __LINE__);
+ goto checkFP;
+ }
+ wctx->sp += immv;
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc);
+ return rc;
+ }
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xc2.\n", __LINE__);
+ DELETE_CURCTX ();
+ }
+ break;
+ case 0xc3: /* ret */
+ {
+ int rc = process_return (wctx, cur);
+ if (rc != RA_FAILURE)
+ {
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc);
+ return rc;
+ }
+ if (jmp_reg_switch_mode == 1)
+ jmp_reg_switch_pc = cur->pc;
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xc3.\n", __LINE__);
+ DELETE_CURCTX ();
+ }
+ break;
+ case 0xc4: /* group AVX, 3-bytes VEX prefix */
+ {
+ unsigned char *pc = cur->pc - 1; // points to the beginning of the instruction
+ int len = parse_x86_AVX_instruction (pc);
+ if (len < 3)
+ DELETE_CURCTX ();
+ else
+ {
+ pc += len;
+ cur->pc = pc;
+ }
+ }
+ break;
+ case 0xc5: /* group AVX, 2-bytes VEX prefix */
+ {
+ unsigned char *pc = cur->pc - 1; // points to the beginning of the instruction
+ int len = parse_x86_AVX_instruction (pc);
+ if (len < 2)
+ DELETE_CURCTX ();
+ else
+ {
+ pc += len;
+ cur->pc = pc;
+ }
+ }
+ break;
+ case 0xc6:
+ modrm = *cur->pc;
+ if (modrm == 0xf8) /* xabort */
+ cur->pc += 2;
+ else /* mov Eb,Ib */
+ cur->pc = check_modrm (cur->pc) + 1;
+ break;
+ case 0xc7:
+ modrm = *cur->pc;
+ if (modrm == 0xf8) /* xbegin */
+ cur->pc += v + 1;
+ else
+ { /* mov Ev,Iz */
+ extop = MRM_EXT (modrm);
+ if (extop != 0)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d give up return address, opcode = 0xc7\n", __LINE__);
+ goto checkFP;
+ }
+ if (MRM_MOD (modrm) == 0xc0 && MRM_REGS (modrm) == RAX)
+ cur->rax = read_int (cur->pc + 1, z);
+ cur->pc = check_modrm (cur->pc) + z;
+ }
+ break;
+ case 0xc8: /* enter Iw,Ib */
+ cur->pc += 3;
+ break;
+ case 0xc9: /* leave */
+ /* mov %ebp,%esp */
+ cur->sp = cur->fp;
+ /* pop %ebp */
+ if (cur->fp_loc == cur->sp)
+ {
+ cur->fp = cur->fp_sav;
+ cur->fp_loc = NULL;
+ }
+ else if (cur->sp >= cur->sp_safe &&
+ (unsigned long) cur->sp < wctx->sbase)
+ {
+ cur->fp = (unsigned long*) (*cur->sp);
+ if (wctx->fp == (unsigned long) cur->sp)
+ cur->cval = RA_FROMFP;
+ }
+ cur->sp += 1;
+ if (cur->sp - RED_ZONE > cur->sp_safe)
+ cur->sp_safe = cur->sp - RED_ZONE;
+ break;
+ case 0xca: /* retf Iw */
+ cur->pc += 2; /* XXXX process return */
+ break;
+ case 0xcb: /* retf */
+ break; /* XXXX process return */
+ case 0xcc: /* int 3 */
+ break;
+ case 0xcd: /* int Ib */
+ if (*cur->pc == 0x80)
+ {
+ if (cur->rax == __NR_exit)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xcd.\n", __LINE__);
+ DELETE_CURCTX ();
+ break;
+ }
+ else if (cur->rax == __NR_rt_sigreturn)
+ {
+ if (jmp_reg_switch_mode == 1)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d give up return address under jmp switch mode, opcode=0xcd\n",
+ __LINE__);
+ goto checkFP;
+ }
+ wctx->sp = (unsigned long) cur->sp;
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_RT_SIGRETURN);
+ return RA_RT_SIGRETURN;
+ }
+#if WSIZE(32)
+ else if (cur->rax == __NR_sigreturn)
+ {
+ if (jmp_reg_switch_mode == 1)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d give up return address under jmp switch mode, opcode = 0xc2\n",
+ __LINE__);
+ goto checkFP;
+ }
+ wctx->sp = (unsigned long) cur->sp;
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_SIGRETURN);
+ return RA_SIGRETURN;
+ }
+#endif
+ }
+ cur->pc += 1;
+ break;
+ case 0xce: /* into */
+ case 0xcf: /* iret */
+ break;
+ case 0xd0: /* shift group2 Eb,1 */
+ case 0xd1: /* shift group2 Ev,1 */
+ case 0xd2: /* shift group2 Eb,%cl */
+ case 0xd3: /* shift group2 Ev,%cl */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xd4: /* aam Ib */
+ cur->pc += 1;
+ break;
+ case 0xd5: /* aad Ib */
+ cur->pc += 1;
+ break;
+ case 0xd6: /* falc? */
+ break;
+ case 0xd7:
+ cur->pc = check_modrm (cur->pc);
+ cur->pc++;
+ break;
+ case 0xd8: /* esc instructions */
+ case 0xd9:
+ case 0xda:
+ case 0xdb:
+ case 0xdc:
+ case 0xdd:
+ case 0xde:
+ case 0xdf:
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xe0: /* loopne Jb */
+ case 0xe1: /* loope Jb */
+ case 0xe2: /* loop Jb */
+ case 0xe3: /* jcxz Jb */
+ imm8 = *(char*) cur->pc++;
+ if (nctx < (jmp_reg_switch_mode ? MAXJMPREGCTX : MAXCTX))
+ {
+ int tidx = 0;
+ unsigned char *npc = cur->pc + imm8;
+ if (is_after_ret (npc))
+ break;
+ while (npc > targets[tidx])
+ tidx += 1;
+ if (npc != targets[tidx])
+ {
+ if (ntrg < MAXTRGTS)
+ {
+ for (int i = 0; i < nctx; i++)
+ if (buf[i].tidx >= tidx)
+ buf[i].tidx++;
+ /* insert a new target */
+ for (int i = ntrg; i > tidx; i--)
+ targets[i] = targets[i - 1];
+ ntrg += 1;
+ targets[tidx++] = npc;
+ }
+ else
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: ntrg = max\n");
+ struct AdvWalkContext *new = buf + nctx;
+ nctx += 1;
+ __collector_memcpy (new, cur, sizeof (*new));
+ new->pc = npc;
+ new->tidx = tidx;
+ cur = new; /* advance the new context first */
+ continue;
+ }
+ }
+ else
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: nctx = max\n");
+ break;
+ case 0xe4: case 0xe5:
+ cur->pc = check_modrm (cur->pc);
+ cur->pc++;
+ break;
+ case 0xe6: case 0xe7:
+ cur->pc++;
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xec: case 0xed: case 0xee: case 0xef:
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0xe8: /* call Jz (f64) */
+ {
+ if (jmp_reg_switch_mode == 1)
+ {
+ struct AdvWalkContext* tmpctx = (struct AdvWalkContext *) alloca (sizeof (*cur));
+ __collector_memcpy (tmpctx, cur, sizeof (*cur));
+ int rc = process_return (wctx, tmpctx);
+ if (rc != RA_FAILURE)
+ {
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc);
+ return rc;
+ }
+ }
+ int immz = read_int (cur->pc, z);
+ if (immz == 0)
+ /* special case in PIC code */
+ cur->sp -= 1;
+ cur->pc += z;
+ }
+ break;
+ case 0xe9: /* jump Jz */
+ {
+ int immz = read_int (cur->pc, z);
+ unsigned char *npc = cur->pc + z + immz;
+ if ((unsigned long) npc < wctx->tbgn || (unsigned long) npc >= wctx->tend)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xe9.\n", __LINE__);
+ DELETE_CURCTX ();
+ break;
+ }
+ int tidx = 0;
+ while (npc > targets[tidx])
+ tidx += 1;
+ if (npc != targets[tidx])
+ {
+ if (ntrg < MAXTRGTS)
+ {
+ for (int i = 0; i < nctx; i++)
+ if (buf[i].tidx >= tidx)
+ buf[i].tidx++;
+ /* insert a new target */
+ for (int i = ntrg; i > tidx; i--)
+ targets[i] = targets[i - 1];
+ ntrg += 1;
+ targets[tidx++] = npc;
+ }
+ else
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: ntrg = max\n");
+ cur->pc = npc;
+ cur->tidx = tidx;
+ continue; /* advance this context first */
+ }
+ else
+ {
+ /* Delete context */
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xe9.\n", __LINE__);
+ DELETE_CURCTX ();
+ }
+ }
+ break;
+ case 0xeb: /* jump imm8 */
+ {
+ imm8 = *(char*) cur->pc++;
+ int tidx = 0;
+ unsigned char *npc = cur->pc + imm8;
+ while (npc > targets[tidx])
+ tidx += 1;
+ if (npc != targets[tidx])
+ {
+ if (ntrg < MAXTRGTS)
+ {
+ for (int i = 0; i < nctx; i++)
+ if (buf[i].tidx >= tidx)
+ buf[i].tidx++;
+ /* insert a new target */
+ for (int i = ntrg; i > tidx; i--)
+ targets[i] = targets[i - 1];
+ ntrg += 1;
+ targets[tidx++] = npc;
+ }
+ else
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: ntrg = max\n");
+ cur->pc = npc;
+ cur->tidx = tidx;
+ continue; /* advance this context first */
+ }
+ else
+ {
+ /* Delete context */
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xeb.\n", __LINE__);
+ DELETE_CURCTX ();
+ }
+ }
+ break;
+ case 0xf0: /* lock prefix */
+ case 0xf2: /* repne prefix */
+ case 0xf3: /* repz prefix */
+ break;
+ case 0xf4: /* hlt */
+ extop2 = *(cur->pc - 3);
+ if (extop2 == 0x90)
+ {
+ // 17851712 occasional SEGV in find_i386_ret_addr in unwind.c during attach
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_END_OF_STACK);
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d returns RA_END_OF_STACK\n", __LINE__);
+ return RA_END_OF_STACK;
+ }
+ /* We see 'hlt' in _start. Stop analysis, revert to FP */
+ /* A workaround for the Linux main stack */
+ if (nctx > 1)
+ {
+ DELETE_CURCTX ();
+ break;
+ }
+ if (cur->fp == 0)
+ {
+ if (jmp_reg_switch_mode == 1)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: give up return address under jmp switch mode, opcode = 0xf4\n");
+ goto checkFP;
+ }
+ cache_put (wctx, RA_EOSTCK);
+ wctx->pc = 0;
+ wctx->sp = 0;
+ wctx->fp = 0;
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_END_OF_STACK);
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d returns RA_END_OF_STACK\n", __LINE__);
+ return RA_END_OF_STACK;
+ }
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d give up return address, opcode = 0xf4\n", __LINE__);
+ goto checkFP;
+ case 0xf5: /* cmc */
+ break;
+ case 0xf6: /* group3 Eb */
+ modrm = *cur->pc;
+ extop = MRM_EXT (modrm);
+ cur->pc = check_modrm (cur->pc);
+ if (extop == 0x0) /* test Ib */
+ cur->pc += 1;
+ break;
+ case 0xf7: /* group3 Ev */
+ modrm = *cur->pc;
+ extop = MRM_EXT (modrm);
+ cur->pc = check_modrm (cur->pc);
+ if (extop == 0x0) /* test Iz */
+ cur->pc += z;
+ break;
+ case 0xf8: /* clc */
+ case 0xf9: /* stc */
+ case 0xfa: /* cli */
+ case 0xfb: /* sti */
+ case 0xfc: /* cld */
+ case 0xfd: /* std */
+ break;
+ case 0xfe: /* group4 */
+ modrm = *cur->pc;
+ extop = MRM_EXT (modrm);
+ switch (extop)
+ {
+ case 0x0: /* inc Eb */
+ case 0x1: /* dec Eb */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x7:
+ cur->pc = check_modrm (cur->pc);
+ break;
+ default:
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d unknown opcode: 0xfe %x\n",
+ __LINE__, extop);
+ DELETE_CURCTX ();
+ break;
+ }
+ break;
+ case 0xff: /* group5 */
+ modrm = *cur->pc;
+ extop = MRM_EXT (modrm);
+ switch (extop)
+ {
+ case 0x0: /* inc Ev */
+ case 0x1: /* dec Ev */
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x2: /* calln Ev */
+ if (jmp_reg_switch_mode == 1)
+ {
+ struct AdvWalkContext* tmpctx = (struct AdvWalkContext *) alloca (sizeof (*cur));
+ __collector_memcpy (tmpctx, cur, sizeof (*cur));
+ int rc = process_return (wctx, tmpctx);
+ if (rc != RA_FAILURE)
+ {
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc);
+ return rc;
+ }
+ }
+ cur->pc = check_modrm (cur->pc);
+ break;
+ case 0x3: /* callf Ep */
+ if (jmp_reg_switch_mode == 1)
+ {
+ struct AdvWalkContext* tmpctx = (struct AdvWalkContext *) alloca (sizeof (*cur));
+ __collector_memcpy (tmpctx, cur, sizeof (*cur));
+ int rc = process_return (wctx, tmpctx);
+ if (rc != RA_FAILURE)
+ {
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc);
+ return rc;
+ }
+ }
+ cur->pc = check_modrm (cur->pc); /* XXXX */
+ break;
+ case 0x4: /* jumpn Ev */
+ /* This instruction appears in PLT or
+ * in tail call optimization.
+ * In both cases treat it as return.
+ * Save jump *(reg) - switch, etc, for later use when no ctx left
+ */
+ if (modrm == 0x25 || /* jumpn *disp32 */
+ MRM_MOD (modrm) == 0x40 || /* jumpn byte(reg) */
+ MRM_MOD (modrm) == 0x80) /* jumpn word(reg) */
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: PLT or tail call: %p\n", cur->pc - 1);
+ int rc = process_return (wctx, cur);
+ if (rc != RA_FAILURE)
+ {
+ if (jmp_reg_switch_mode == 1 && total_num_jmp_reg < max_num_jmp_reg_seen)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: give up return address under jmp switch mode, opcode = 0xff\n");
+ goto checkFP;
+ }
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc);
+ return rc;
+ }
+ }
+ else if (modrm != 0x24 /*ignore SIB*/) /* jumpn *(reg) or jumpn reg */
+ {
+ // 22846120 stack unwind does not find caller of __memcpy_ssse3_back with B64 intel-Linux
+ /*
+ * For now, let's deal rather narrowly with this scenario. If:
+ * - we are in the middle of an "ff e2" instruction, and
+ * - the next instruction is undefined ( 0f 0b == ud2 )
+ * then test return. (Might eventually have to broaden the scope
+ * of this fix to other registers/etc.)
+ */
+ if (cur->pc[0] == 0xe2 && cur->pc[1] == 0x0f && cur->pc[2] == 0x0b)
+ {
+ int rc = process_return_real (wctx, cur, 0);
+ if (rc == RA_SUCCESS)
+ {
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc);
+ return rc;
+ }
+ }
+
+ // 22691241 shjsynprog, jsynprog core dump from find_i386_ret_addr
+ /*
+ * Here is another oddity. Java 9 seems to emit dynamically generated
+ * code where a code block ends with a "jmp *reg" and then padding to a
+ * multiple-of-16 boundary and then a bunch of 0s. In this case, let's
+ * not continue to walk bytes since we would be walking off the end of
+ * the instructions into ... something. Treating them as instructions
+ * can lead to unexpected results, including SEGV.
+ */
+ /*
+ * While the general problem deserves a better solution, let's look
+ * here only for one particular case:
+ * 0xff 0xe7 jmp *reg
+ * nop to bring us to a multiple-of-16 boundary
+ * 0x0000000000000a00 something that does not look like an instruction
+ *
+ * A different nop might be used depending on how much padding is needed
+ * to reach that multiple-of-16 boundary. We've seen two:
+ * 0x90 one byte
+ * 0x0f 0x1f 0x40 0x00 four bytes
+ */
+ // confirm the instruction is 0xff 0xe7
+ if (cur->pc[0] == 0xe7)
+ {
+ // check for correct-length nop and find next 16-byte boundary
+ int found_nop = 0;
+ unsigned long long *boundary = 0;
+ switch ((((unsigned long) (cur->pc)) & 0xf))
+ {
+ case 0xb: // look for 4-byte nop
+ if (*((unsigned *) (cur->pc + 1)) == 0x00401f0f)
+ found_nop = 1;
+ boundary = (unsigned long long *) (cur->pc + 5);
+ break;
+ case 0xe: // look for 1-byte nop
+ if (cur->pc[1] == 0x90)
+ found_nop = 1;
+ boundary = (unsigned long long *) (cur->pc + 2);
+ break;
+ default:
+ break;
+ }
+
+ // if nop is found, check what's at the boundary
+ if (found_nop && *boundary == 0x000000000a00)
+ {
+ DELETE_CURCTX ();
+ break;
+ }
+ }
+
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: probably PLT or tail call or switch table: %p\n",
+ cur->pc - 1);
+ if (num_jmp_reg < expected_num_jmp_reg)
+ {
+ if (jmp_reg_ctx[num_jmp_reg] == NULL)
+ jmp_reg_ctx[num_jmp_reg] = (struct AdvWalkContext *) alloca (sizeof (*cur));
+ if (jmp_reg_ctx[num_jmp_reg] != NULL)
+ __collector_memcpy (jmp_reg_ctx[num_jmp_reg], cur, sizeof (*cur));
+ }
+ if (num_jmp_reg < expected_num_jmp_reg ||
+ (num_jmp_reg >= expected_num_jmp_reg &&
+ jmp_reg_ctx[expected_num_jmp_reg - 1] != NULL &&
+ cur->pc != jmp_reg_ctx[expected_num_jmp_reg - 1]->pc))
+ {
+ num_jmp_reg++;
+ total_num_jmp_reg++;
+ }
+ if (jmp_reg_switch_mode == 1 && total_num_jmp_reg >= max_num_jmp_reg_seen)
+ {
+ int rc = process_return_real (wctx, cur, 0);
+ if (rc == RA_SUCCESS)
+ {
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc);
+ return rc;
+ }
+ }
+ }
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d delete context, opcode 0xff.\n", __LINE__);
+ DELETE_CURCTX ();
+ break;
+ case 0x5: /* jmpf Ep */
+ cur->pc = check_modrm (cur->pc); /* XXXX */
+ break;
+ case 0x6: /* push Ev */
+ cur->pc = check_modrm (cur->pc);
+ cur->sp -= 1;
+ break;
+ case 0x7:
+ cur->pc = check_modrm (cur->pc); /* XXXX */
+ if (jmp_reg_switch_mode == 1)
+ {
+ int rc = process_return_real (wctx, cur, 0);
+ if (rc == RA_SUCCESS)
+ {
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, rc);
+ return rc;
+ }
+ }
+ break;
+ default:
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d unknown opcode: 0xff %x\n",
+ __LINE__, (int) extop);
+ DELETE_CURCTX ();
+ break;
+ }
+ break;
+ default:
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d unknown opcode: 0x%x\n",
+ __LINE__, (int) opcode);
+ DELETE_CURCTX ();
+ break;
+ }
+
+ /* switch to next context */
+ if (++cur >= buf + nctx)
+ cur = buf;
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d switch context: cur=0x%lx(%ld) nctx=%d cnt=%d\n",
+ __LINE__, (unsigned long) cur, (long) (cur - buf), (int) nctx, (int) cnt);
+ }
+
+checkFP:
+ Tprintf (DBG_LT3, "find_i386_ret_addr:%d checkFP: wctx=0x%lx fp=0x%lx ln=0x%lx pc=0x%lx sbase=0x%lx sp=0x%lx tbgn=0x%lx tend=0x%lx\n",
+ __LINE__, (unsigned long) wctx, (unsigned long) wctx->fp,
+ (unsigned long) wctx->ln, (unsigned long) wctx->pc, (unsigned long) wctx->sbase,
+ (unsigned long) wctx->sp, (unsigned long) wctx->tbgn, (unsigned long) wctx->tend);
+
+ if (jmp_reg_switch_mode == 1)
+ { // not deal with switch cases not ending with ret
+ if (jmp_reg_switch_backup_ctx != NULL)
+ __collector_memcpy (cur, jmp_reg_switch_backup_ctx, sizeof (*cur));
+ DprintfT (SP_DUMP_UNWIND, "stack_unwind jmp reg mode on: pc = 0x%lx cnt = %d, nctx = %d\n", wctx->pc, cnt, nctx);
+ }
+
+ unsigned long *cur_fp = cur->fp;
+ unsigned long *cur_sp = cur->sp;
+ if (do_walk == 0)
+ __collector_memcpy (&wctx_pc_save, wctx, sizeof (struct WalkContext));
+
+ /* Resort to the frame pointer */
+ if (cur->fp_loc)
+ cur->fp = cur->fp_sav;
+ cur->sp = cur->fp;
+ if ((unsigned long) cur->sp >= wctx->sbase ||
+ (unsigned long) cur->sp < wctx->sp)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d do_walk=%d cur->sp=0x%p out of range. wctx->sbase=0x%lx wctx->sp=0x%lx wctx->pc=0x%lx\n",
+ __LINE__, (int) do_walk, cur->sp, (unsigned long) wctx->sbase,
+ (unsigned long) wctx->sp, (unsigned long) wctx->pc);
+ if (do_walk == 0)
+ {
+ cur->sp = cur_sp;
+ cur->fp = cur_fp;
+ do_walk = 1;
+ save_ctx = 1;
+ goto startWalk;
+ }
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_FAILURE);
+ return RA_FAILURE;
+ }
+
+ unsigned long fp = *cur->sp++;
+ if (fp <= (unsigned long) cur->sp || fp >= wctx->sbase)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d fp=0x%016llx out of range. cur->sp=%p wctx->sbase=0x%lx wctx->pc=0x%lx\n",
+ __LINE__, (unsigned long long) fp, cur->sp,
+ (unsigned long) wctx->sbase, (unsigned long) wctx->pc);
+ if (do_walk == 0)
+ {
+ cur->sp = cur_sp;
+ cur->fp = cur_fp;
+ do_walk = 1;
+ save_ctx = 1;
+ goto startWalk;
+ }
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_FAILURE);
+ return RA_FAILURE;
+ }
+
+ unsigned long ra = *cur->sp++;
+ if (ra == 0)
+ {
+ cache_put (wctx, RA_EOSTCK);
+ DprintfT (SP_DUMP_UNWIND, "unwind.c:%d returns RA_END_OF_STACK wctx->pc = 0x%lx\n", __LINE__, wctx->pc);
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_END_OF_STACK);
+ return RA_END_OF_STACK;
+ }
+
+ unsigned long tbgn = wctx->tbgn;
+ unsigned long tend = wctx->tend;
+ if (ra < tbgn || ra >= tend)
+ {
+ // We do not know yet if update_map_segments is really needed
+ if (!__collector_check_segment (ra, &tbgn, &tend, 0))
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: __collector_check_segment fail. wctx->pc = 0x%lx\n", wctx->pc);
+ if (do_walk == 0)
+ {
+ cur->sp = cur_sp;
+ cur->fp = cur_fp;
+ do_walk = 1;
+ save_ctx = 1;
+ goto startWalk;
+ }
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_FAILURE);
+ return RA_FAILURE;
+ }
+ }
+
+ unsigned long npc = adjust_ret_addr (ra, ra - tbgn, tend);
+ if (npc == 0)
+ {
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: adjust_ret_addr fail. wctx->pc = 0x%lx\n", wctx->pc);
+ if (do_walk == 0)
+ {
+ cur->sp = cur_sp;
+ cur->fp = cur_fp;
+ do_walk = 1;
+ save_ctx = 1;
+ goto startWalk;
+ }
+ if (save_ctx)
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_FAILURE);
+ return RA_FAILURE;
+ }
+ wctx->pc = npc;
+ wctx->sp = (unsigned long) cur->sp;
+ wctx->fp = fp;
+ wctx->tbgn = tbgn;
+ wctx->tend = tend;
+
+ if (save_ctx)
+ {
+ omp_cache_put (cur->sp_safe, &wctx_pc_save, wctx, RA_SUCCESS);
+ DprintfT (SP_DUMP_UNWIND, "unwind.c: cache walk context. wctx_pc_save->pc = 0x%lx\n", wctx_pc_save.pc);
+ }
+ return RA_SUCCESS;
+}
+
+/*
+ * We have the return address, but we would like to report to the user
+ * the calling PC, which is the instruction immediately preceding the
+ * return address. Unfortunately, x86 instructions can have variable
+ * length. So we back up 8 bytes and try to figure out where the
+ * calling PC starts. (FWIW, call instructions are often 5-bytes long.)
+ */
+unsigned long
+adjust_ret_addr (unsigned long ra, unsigned long segoff, unsigned long tend)
+{
+ unsigned long npc = 0;
+ int i = segoff < 8 ? segoff : 8;
+ for (; i > 1; i--)
+ {
+ unsigned char *ptr = (unsigned char*) ra - i;
+ int z = 4;
+ int a = 4;
+ int done = 0;
+ int bVal;
+ while (!done)
+ {
+ bVal = getByteInstruction (ptr);
+ if (bVal < 0)
+ return 0;
+ switch (bVal)
+ {
+ case 0x26:
+ case 0x36:
+#if WSIZE(64)
+ ptr += 1;
+ break;
+#endif
+ case 0x64:
+ case 0x65:
+ bVal = getByteInstruction (ptr + 1);
+ if (bVal < 0)
+ return 0;
+ if (bVal == 0xe8)
+ // a workaround for bug 16193041, assuming "call Jz" has no segment override prefix
+ done = 1;
+ else
+ ptr += 1;
+ break;
+ case 0x66:
+ z = 2;
+ ptr += 1;
+ break;
+ case 0x67:
+ a = 2;
+ ptr += 1;
+ break;
+ default:
+ done = 1;
+ break;
+ }
+ }
+#if WSIZE(64)
+ bVal = getByteInstruction (ptr);
+ if (bVal < 0)
+ return 0;
+ if (bVal >= 0x40 && bVal <= 0x4f)
+ { /* XXXX not all REX codes applicable */
+ if (bVal & 0x8)
+ z = 4;
+ ptr += 1;
+ }
+#endif
+ int opcode = getByteInstruction (ptr);
+ if (opcode < 0)
+ return 0;
+ ptr++;
+ switch (opcode)
+ {
+ case 0xe8: /* call Jz (f64) */
+ ptr += z;
+ break;
+ case 0x9a: /* callf Ap */
+ ptr += 2 + a;
+ break;
+ case 0xff: /* calln Ev , callf Ep */
+ {
+ int extop = MRM_EXT (*ptr);
+ if (extop == 2 || extop == 3)
+ ptr = check_modrm (ptr);
+ }
+ break;
+ default:
+ continue;
+ }
+ if ((unsigned long) ptr == ra)
+ {
+ npc = ra - i;
+ break;
+ }
+ }
+ if (npc == 0)
+ {
+ unsigned char * ptr = (unsigned char *) ra;
+#if WSIZE(32)
+ // test __kernel_sigreturn or __kernel_rt_sigreturn
+ if ((ra + 7 < tend && getByteInstruction (ptr) == 0x58
+ && getByteInstruction (ptr + 1) == 0xb8
+ && getByteInstruction (ptr + 6) == 0xcd
+ && getByteInstruction (ptr + 7) == 0x80) /* pop %eax; mov $NNNN, %eax; int */
+ || (ra + 7 < tend && getByteInstruction (ptr) == 0x58
+ && getByteInstruction (ptr + 1) == 0xb8
+ && getByteInstruction (ptr + 6) == 0x0f
+ && getByteInstruction (ptr + 7) == 0x05) /* pop %eax; mov $NNNN, %eax; syscall */
+ || (ra + 6 < tend && getByteInstruction (ptr) == 0xb8
+ && getByteInstruction (ptr + 5) == 0xcd
+ && getByteInstruction (ptr + 6) == 0x80) /* mov $NNNN, %eax; int */
+ || (ra + 6 < tend && getByteInstruction (ptr) == 0xb8
+ && getByteInstruction (ptr + 5) == 0x0f
+ && getByteInstruction (ptr + 6) == 0x05)) /* mov $NNNN, %eax; syscall */
+#else //WSIZE(64)
+ // test __restore_rt
+ if (ra + 8 < tend && getByteInstruction (ptr) == 0x48
+ && getByteInstruction (ptr + 7) == 0x0f
+ && getByteInstruction (ptr + 8) == 0x05) /* mov $NNNNNNNN, %rax; syscall */
+#endif
+ {
+ npc = ra;
+ }
+ }
+ if (npc == 0 && __collector_java_mode
+ && __collector_java_asyncgetcalltrace_loaded)
+ { // detect jvm interpreter code for java user threads
+ unsigned char * ptr = (unsigned char *) ra;
+#if WSIZE(32)
+ // up to J170
+ /*
+ * ff 24 9d e0 64 02 f5 jmp *-0xafd9b20(,%ebx,4)
+ * 8b 4e 01 movl 1(%esi),%ecx
+ * f7 d1 notl %ecx
+ * 8b 5d ec movl -0x14(%ebp),%ebx
+ * c1 e1 02 shll $2,%ecx
+ * eb d8 jmp .-0x26 [ 0x92a ]
+ * 83 ec 08 subl $8,%esp || 8b 65 f8 movl -8(%ebp),%esp
+ * */
+ if (ra - 20 >= (ra - segoff) && ((*ptr == 0x83 && *(ptr + 1) == 0xec) || (*ptr == 0x8b && *(ptr + 1) == 0x65))
+ && *(ptr - 2) == 0xeb
+ && *(ptr - 5) == 0xc1 && *(ptr - 4) == 0xe1
+ && *(ptr - 8) == 0x8b && *(ptr - 7) == 0x5d
+ && *(ptr - 10) == 0xf7 && *(ptr - 9) == 0xd1
+ && *(ptr - 13) == 0x8b && *(ptr - 12) == 0x4e
+ && *(ptr - 20) == 0xff && *(ptr - 19) == 0x24 && *(ptr - 18) == 0x9d)
+ {
+ npc = ra - 20;
+ }
+ // J180 J190
+ // ff 24 9d ** ** ** ** jmp *-0x*******(,%ebx,4)
+ if (npc == 0
+ && ra - 7 >= (ra - segoff)
+ && *(ptr - 7) == 0xff
+ && *(ptr - 6) == 0x24
+ && *(ptr - 5) == 0x9d)
+ {
+ npc = ra - 7;
+ }
+#else //WSIZE(64)
+ // up to J170
+ /*
+ * 41 ff 24 da jmp *(%r10,%rbx,8)
+ * 41 8b 4d 01 movl 1(%r13),%ecx
+ * f7 d1 notl %ecx
+ * 48 8b 5d d8 movq -0x28(%rbp),%rbx
+ * c1 e1 02 shll $2,%ecx
+ * eb cc jmp .-0x32 [ 0xd23 ]
+ * 48 8b 65 f0 movq -0x10(%rbp),%rsp
+ */
+ if (ra - 19 >= (ra - segoff) && *ptr == 0x48 && ((*(ptr + 1) == 0x8b && *(ptr + 2) == 0x65) || (*(ptr + 1) == 0x83 && *(ptr + 2) == 0xec))
+ && *(ptr - 2) == 0xeb
+ && *(ptr - 5) == 0xc1 && *(ptr - 4) == 0xe1
+ && *(ptr - 9) == 0x48 && *(ptr - 8) == 0x8b && *(ptr - 7) == 0x5d
+ && *(ptr - 11) == 0xf7 && *(ptr - 10) == 0xd1
+ && *(ptr - 15) == 0x41 && *(ptr - 14) == 0x8b && *(ptr - 13) == 0x4d
+ && *(ptr - 19) == 0x41 && *(ptr - 18) == 0xff)
+ npc = ra - 19;
+ // J180 J190
+ // 41 ff 24 da jmp *(%r10,%rbx,8)
+ if (npc == 0
+ && ra - 4 >= (ra - segoff)
+ && *(ptr - 4) == 0x41
+ && *(ptr - 3) == 0xff
+ && *(ptr - 2) == 0x24
+ && *(ptr - 1) == 0xda)
+ npc = ra - 4;
+#endif
+ }
+
+ return npc;
+}
+
+/*
+ * Parses AVX instruction and returns its length.
+ * Returns 0 if parsing failed.
+ * https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
+ */
+static int
+parse_x86_AVX_instruction (unsigned char *pc)
+{
+ /*
+ * VEX prefix has a two-byte form (0xc5) and a three byte form (0xc4).
+ * If an instruction syntax can be encoded using the two-byte form,
+ * it can also be encoded using the three byte form of VEX.
+ * The latter increases the length of the instruction by one byte.
+ * This may be helpful in some situations for code alignment.
+ *
+ Byte 0 Byte 1 Byte 2 Byte 3
+ (Bit Position) 7 0 7 6 5 4 0 7 6 3 2 10
+ 3-byte VEX [ 11000100 ] [ R X B | m-mmmm ] [ W | vvvv | L | pp ]
+ 7 0 7 6 3 2 10
+ 2-byte VEX [ 11000101 ] [ R | vvvv | L | pp ]
+ 7 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
+ 4-byte EVEX [ 01100010 ] [ R X B R1 0 0 m m ] [ W v v v v 1 p p ] [ z L1 L B1 V1 a a a ]
+
+ R: REX.R in 1's complement (inverted) form
+ 0: Same as REX.R=1 (64-bit mode only)
+ 1: Same as REX.R=0 (must be 1 in 32-bit mode)
+
+ X: REX.X in 1's complement (inverted) form
+ 0: Same as REX.X=1 (64-bit mode only)
+ 1: Same as REX.X=0 (must be 1 in 32-bit mode)
+
+ B: REX.B in 1's complement (inverted) form
+ 0: Same as REX.B=1 (64-bit mode only)
+ 1: Same as REX.B=0 (Ignored in 32-bit mode).
+
+ W: opcode specific (use like REX.W, or used for opcode
+ extension, or ignored, depending on the opcode byte)
+
+ m-mmmm:
+ 00000: Reserved for future use (will #UD)
+ 00001: implied 0F leading opcode byte
+ 00010: implied 0F 38 leading opcode bytes
+ 00011: implied 0F 3A leading opcode bytes
+ 00100-11111: Reserved for future use (will #UD)
+
+ vvvv: a register specifier (in 1's complement form) or 1111 if unused.
+
+ L: Vector Length
+ 0: scalar or 128-bit vector
+ 1: 256-bit vector
+
+ pp: opcode extension providing equivalent functionality of a SIMD prefix
+ 00: None
+ 01: 66
+ 10: F3
+ 11: F2
+ *
+ * Example: 0xc5f877L vzeroupper
+ * VEX prefix: 0xc5 0x77
+ * Opcode: 0xf8
+ *
+ */
+ int len = 0;
+ disassemble_info dis_info;
+ dis_info.arch = bfd_arch_i386;
+ dis_info.mach = bfd_mach_x86_64;
+ dis_info.flavour = bfd_target_unknown_flavour;
+ dis_info.endian = BFD_ENDIAN_UNKNOWN;
+ dis_info.endian_code = dis_info.endian;
+ dis_info.octets_per_byte = 1;
+ dis_info.disassembler_needs_relocs = FALSE;
+ dis_info.fprintf_func = fprintf_func;
+ dis_info.stream = NULL;
+ dis_info.disassembler_options = NULL;
+ dis_info.read_memory_func = read_memory_func;
+ dis_info.memory_error_func = memory_error_func;
+ dis_info.print_address_func = print_address_func;
+ dis_info.symbol_at_address_func = symbol_at_address_func;
+ dis_info.symbol_is_valid = symbol_is_valid;
+ dis_info.display_endian = BFD_ENDIAN_UNKNOWN;
+ dis_info.symtab = NULL;
+ dis_info.symtab_size = 0;
+ dis_info.buffer_vma = 0;
+ dis_info.buffer = pc;
+ dis_info.buffer_length = 8;
+
+ disassembler_ftype disassemble = print_insn_i386;
+ if (disassemble == NULL)
+ {
+ DprintfT (SP_DUMP_UNWIND, "parse_x86_AVX_instruction ERROR: unsupported disassemble\n");
+ return 0;
+ }
+ len = disassemble (0, &dis_info);
+ DprintfT (SP_DUMP_UNWIND, "parse_x86_AVX_instruction: returned %d pc: %p\n", len, pc);
+ return len;
+}
+
+/*
+ * In the Intel world, a stack frame looks like this:
+ *
+ * %fp0->| |
+ * |-------------------------------|
+ * | Args to next subroutine |
+ * |-------------------------------|-\
+ * %sp0->| One word struct-ret address | |
+ * |-------------------------------| > minimum stack frame (8 bytes)
+ * | Previous frame pointer (%fp0)| |
+ * %fp1->|-------------------------------|-/
+ * | Local variables |
+ * %sp1->|-------------------------------|
+ *
+ */
+
+int
+stack_unwind (char *buf, int size, void *bptr, void *eptr, ucontext_t *context, int mode)
+{
+ long *lbuf = (long*) buf;
+ int lsize = size / sizeof (long);
+ int ind = 0;
+ int do_walk = 1;
+ int extra_frame = 0;
+ if (mode & FRINFO_NO_WALK)
+ do_walk = 0;
+ if ((mode & 0xffff) == FRINFO_FROM_STACK)
+ extra_frame = 1;
+
+ /*
+ * trace the stack frames from user stack.
+ * We are assuming that the frame pointer and return address
+ * are null when we are at the top level.
+ */
+ struct WalkContext wctx;
+ wctx.pc = GET_PC (context);
+ wctx.sp = GET_SP (context);
+ wctx.fp = GET_FP (context);
+ wctx.ln = (unsigned long) context->uc_link;
+ unsigned long *sbase = (unsigned long*) __collector_tsd_get_by_key (unwind_key);
+ if (sbase && *sbase > wctx.sp)
+ wctx.sbase = *sbase;
+ else
+ {
+ wctx.sbase = wctx.sp + 0x100000;
+ if (wctx.sbase < wctx.sp) /* overflow */
+ wctx.sbase = (unsigned long) - 1;
+ }
+ // We do not know yet if update_map_segments is really needed
+ __collector_check_segment (wctx.pc, &wctx.tbgn, &wctx.tend, 0);
+
+ for (;;)
+ {
+ if (ind >= lsize || wctx.pc == 0)
+ break;
+ if (bptr != NULL && extra_frame && wctx.sp <= (unsigned long) bptr && ind < 2)
+ {
+ lbuf[0] = wctx.pc;
+ if (ind == 0)
+ {
+ ind++;
+ if (ind >= lsize)
+ break;
+ }
+ }
+ if (bptr == NULL || wctx.sp > (unsigned long) bptr)
+ {
+ lbuf[ind++] = wctx.pc;
+ if (ind >= lsize)
+ break;
+ }
+
+ for (;;)
+ {
+ if (eptr != NULL && wctx.sp >= (unsigned long) eptr)
+ {
+ ind = ind >= 2 ? ind - 2 : 0;
+ goto exit;
+ }
+ int ret = find_i386_ret_addr (&wctx, do_walk);
+ DprintfT (SP_DUMP_UNWIND, "stack_unwind (x86 walk):%d find_i386_ret_addr returns %d\n", __LINE__, ret);
+ if (ret == RA_FAILURE)
+ {
+ /* lbuf[ind++] = SP_FAILED_UNWIND_MARKER; */
+ goto exit;
+ }
+
+ if (ret == RA_END_OF_STACK)
+ goto exit;
+#if WSIZE(32)
+ if (ret == RA_RT_SIGRETURN)
+ {
+ struct SigFrame
+ {
+ unsigned long arg0;
+ unsigned long arg1;
+ unsigned long arg2;
+ } *sframe = (struct SigFrame*) wctx.sp;
+ ucontext_t *ncontext = (ucontext_t*) sframe->arg2;
+ wctx.pc = GET_PC (ncontext);
+ if (!__collector_check_segment (wctx.pc, &wctx.tbgn, &wctx.tend, 0))
+ {
+ /* lbuf[ind++] = SP_FAILED_UNWIND_MARKER; */
+ goto exit;
+ }
+ unsigned long nsp = GET_SP (ncontext);
+ /* Check the new stack pointer */
+ if (nsp <= sframe->arg2 || nsp > sframe->arg2 + sizeof (ucontext_t) + 1024)
+ {
+ /* lbuf[ind++] = SP_FAILED_UNWIND_MARKER; */
+ goto exit;
+ }
+ wctx.sp = nsp;
+ wctx.fp = GET_FP (ncontext);
+ break;
+ }
+ else if (ret == RA_SIGRETURN)
+ {
+ struct sigcontext *sctx = (struct sigcontext*) wctx.sp;
+ wctx.pc = sctx->eip;
+ if (!__collector_check_segment (wctx.pc, &wctx.tbgn, &wctx.tend, 0))
+ {
+ /* lbuf[ind++] = SP_FAILED_UNWIND_MARKER; */
+ goto exit;
+ }
+ wctx.sp = sctx->esp;
+ wctx.fp = sctx->ebp;
+ break;
+ }
+#elif WSIZE(64)
+ if (ret == RA_RT_SIGRETURN)
+ {
+ ucontext_t *ncontext = (ucontext_t*) wctx.sp;
+ wctx.pc = GET_PC (ncontext);
+ if (!__collector_check_segment (wctx.pc, &wctx.tbgn, &wctx.tend, 0))
+ {
+ /* lbuf[ind++] = SP_FAILED_UNWIND_MARKER; */
+ goto exit;
+ }
+ unsigned long nsp = GET_SP (ncontext);
+ /* Check the new stack pointer */
+ if (nsp <= wctx.sp || nsp > wctx.sp + sizeof (ucontext_t) + 1024)
+ {
+ /* lbuf[ind++] = SP_FAILED_UNWIND_MARKER; */
+ goto exit;
+ }
+ wctx.sp = nsp;
+ wctx.fp = GET_FP (ncontext);
+ break;
+ }
+#endif /* WSIZE() */
+ if (bptr != NULL && extra_frame && wctx.sp <= (unsigned long) bptr && ind < 2)
+ {
+ lbuf[0] = wctx.pc;
+ if (ind == 0)
+ {
+ ind++;
+ if (ind >= lsize)
+ break;
+ }
+ }
+ if (bptr == NULL || wctx.sp > (unsigned long) bptr)
+ {
+ lbuf[ind++] = wctx.pc;
+ if (ind >= lsize)
+ goto exit;
+ }
+ }
+ }
+
+exit:
+#if defined(DEBUG)
+ if ((SP_DUMP_UNWIND & __collector_tracelevel) != 0)
+ {
+ DprintfT (SP_DUMP_UNWIND, "stack_unwind (x86 walk):%d found %d frames\n\n", __LINE__, ind);
+ for (int i = 0; i < ind; i++)
+ DprintfT (SP_DUMP_UNWIND, " %3d: 0x%lx\n", i, (unsigned long) lbuf[i]);
+ }
+#endif
+ dump_stack (__LINE__);
+ if (ind >= lsize)
+ {
+ ind = lsize - 1;
+ lbuf[ind++] = (unsigned long) SP_TRUNC_STACK_MARKER;
+ }
+ return ind * sizeof (long);
+}
+
+#elif ARCH(Aarch64)
+
+static int
+stack_unwind (char *buf, int size, void *bptr, void *eptr, ucontext_t *context, int mode)
+{
+ if (buf && bptr && eptr && context && size + mode > 0)
+ getByteInstruction ((unsigned char *) eptr);
+ int ind = 0;
+ __u64 *lbuf = (void *) buf;
+ int lsize = size / sizeof (__u64);
+ __u64 pc = context->uc_mcontext.pc;
+ __u64 sp = context->uc_mcontext.sp;
+ __u64 stack_base;
+ unsigned long tbgn = 0;
+ unsigned long tend = 0;
+
+ unsigned long *sbase = (unsigned long*) __collector_tsd_get_by_key (unwind_key);
+ if (sbase && *sbase > sp)
+ stack_base = *sbase;
+ else
+ {
+ stack_base = sp + 0x100000;
+ if (stack_base < sp) // overflow
+ stack_base = (__u64) -1;
+ }
+ DprintfT (SP_DUMP_UNWIND,
+ "unwind.c:%d stack_unwind %2d pc=0x%llx sp=0x%llx stack_base=0x%llx\n",
+ __LINE__, ind, (unsigned long long) pc, (unsigned long long) sp,
+ (unsigned long long) stack_base);
+
+ while (sp && pc)
+ {
+ DprintfT (SP_DUMP_UNWIND,
+ "unwind.c:%d stack_unwind %2d pc=0x%llx sp=0x%llx\n",
+ __LINE__, ind, (unsigned long long) pc, (unsigned long long) sp);
+// Dl_info dlinfo;
+// if (!dladdr ((void *) pc, &dlinfo))
+// break;
+// DprintfT (SP_DUMP_UNWIND, "%2d: %llx <%s+%llu> (%s)\n",
+// ind, (unsigned long long) pc,
+// dlinfo.dli_sname ? dlinfo.dli_sname : "(?)",
+// (unsigned long long) pc - (unsigned long long) dlinfo.dli_saddr,
+// dlinfo.dli_fname);
+ lbuf[ind++] = pc;
+ if (ind >= lsize || sp >= stack_base || (sp & 15) != 0)
+ break;
+ if (pc < tbgn || pc >= tend)
+ if (!__collector_check_segment ((unsigned long) pc, &tbgn, &tend, 0))
+ {
+ DprintfT (SP_DUMP_UNWIND,
+ "unwind.c:%d __collector_check_segment failed. sp=0x%lx\n",
+ __LINE__, (unsigned long) sp);
+ break;
+ }
+ pc = ((__u64 *) sp)[1];
+ __u64 old_sp = sp;
+ sp = ((__u64 *) sp)[0];
+ if (sp < old_sp)
+ break;
+ }
+ if (ind >= lsize)
+ {
+ ind = lsize - 1;
+ lbuf[ind++] = (__u64) SP_TRUNC_STACK_MARKER;
+ }
+ return ind * sizeof (__u64);
+}
+#endif /* ARCH() */
diff --git a/gprofng/src/ABS.h b/gprofng/src/ABS.h
new file mode 100644
index 0000000..a5bcbea
--- /dev/null
+++ b/gprofng/src/ABS.h
@@ -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
index 0000000..e28956c
--- /dev/null
+++ b/gprofng/src/Application.cc
@@ -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
index 0000000..404383b
--- /dev/null
+++ b/gprofng/src/Application.h
@@ -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
index 0000000..e7ebfa9
--- /dev/null
+++ b/gprofng/src/ArchiveExp.cc
@@ -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
index 0000000..809ed58
--- /dev/null
+++ b/gprofng/src/ArchiveExp.h
@@ -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
index 0000000..bb51ddf
--- /dev/null
+++ b/gprofng/src/BaseMetric.cc
@@ -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
index 0000000..e056993
--- /dev/null
+++ b/gprofng/src/BaseMetric.h
@@ -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
index 0000000..2d1db99
--- /dev/null
+++ b/gprofng/src/BaseMetricTreeNode.cc
@@ -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
index 0000000..0076dff
--- /dev/null
+++ b/gprofng/src/BaseMetricTreeNode.h
@@ -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
index 0000000..a575749
--- /dev/null
+++ b/gprofng/src/CacheMap.h
@@ -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
index 0000000..7671f9f
--- /dev/null
+++ b/gprofng/src/CallStack.cc
@@ -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
index 0000000..62e0686
--- /dev/null
+++ b/gprofng/src/CallStack.h
@@ -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
index 0000000..61b91cf
--- /dev/null
+++ b/gprofng/src/CatchOutOfMemory.cc
@@ -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
index 0000000..7dd64a7
--- /dev/null
+++ b/gprofng/src/ClassFile.cc
@@ -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
index 0000000..bd4c61b
--- /dev/null
+++ b/gprofng/src/ClassFile.h
@@ -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
index 0000000..d1620d7
--- /dev/null
+++ b/gprofng/src/Command.cc
@@ -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
index 0000000..4dd28ad
--- /dev/null
+++ b/gprofng/src/Command.h
@@ -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
index 0000000..3a035a9
--- /dev/null
+++ b/gprofng/src/CompCom.cc
@@ -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
index 0000000..e653939
--- /dev/null
+++ b/gprofng/src/CompCom.h
@@ -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
index 0000000..870a531
--- /dev/null
+++ b/gprofng/src/DataObject.cc
@@ -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
index 0000000..f70bbad
--- /dev/null
+++ b/gprofng/src/DataObject.h
@@ -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
index 0000000..e5b48dd
--- /dev/null
+++ b/gprofng/src/DataSpace.cc
@@ -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
index 0000000..c4d80fb
--- /dev/null
+++ b/gprofng/src/DataSpace.h
@@ -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
index 0000000..8e244e2
--- /dev/null
+++ b/gprofng/src/DataStream.cc
@@ -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
index 0000000..59ee293
--- /dev/null
+++ b/gprofng/src/DataStream.h
@@ -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
index 0000000..d9b0067
--- /dev/null
+++ b/gprofng/src/Data_window.cc
@@ -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
index 0000000..a3e98c0
--- /dev/null
+++ b/gprofng/src/Data_window.h
@@ -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
index 0000000..1a6e521
--- /dev/null
+++ b/gprofng/src/Dbe.cc
@@ -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
index 0000000..f811096
--- /dev/null
+++ b/gprofng/src/Dbe.h
@@ -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
index 0000000..382bd45
--- /dev/null
+++ b/gprofng/src/DbeApplication.cc
@@ -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
index 0000000..b6bdaaf
--- /dev/null
+++ b/gprofng/src/DbeApplication.h
@@ -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
index 0000000..af7c36e
--- /dev/null
+++ b/gprofng/src/DbeArray.h
@@ -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
index 0000000..4c51a34
--- /dev/null
+++ b/gprofng/src/DbeCacheMap.h
@@ -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
index 0000000..9e1fe1c
--- /dev/null
+++ b/gprofng/src/DbeFile.cc
@@ -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
index 0000000..abd7180
--- /dev/null
+++ b/gprofng/src/DbeFile.h
@@ -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
index 0000000..9029512
--- /dev/null
+++ b/gprofng/src/DbeJarFile.cc
@@ -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
index 0000000..f0b4f7b
--- /dev/null
+++ b/gprofng/src/DbeJarFile.h
@@ -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
index 0000000..760cc67
--- /dev/null
+++ b/gprofng/src/DbeLinkList.h
@@ -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
index 0000000..14a1eb3
--- /dev/null
+++ b/gprofng/src/DbeLock.cc
@@ -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
index 0000000..28dfb6e
--- /dev/null
+++ b/gprofng/src/DbeLock.h
@@ -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
index 0000000..4370114
--- /dev/null
+++ b/gprofng/src/DbeSession.cc
@@ -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
index 0000000..7d635d2
--- /dev/null
+++ b/gprofng/src/DbeSession.cc.1
@@ -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
index 0000000..0a5c01c
--- /dev/null
+++ b/gprofng/src/DbeSession.h
@@ -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
index 0000000..f13f7b4
--- /dev/null
+++ b/gprofng/src/DbeSyncMap.h
@@ -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
index 0000000..7eb3cb7
--- /dev/null
+++ b/gprofng/src/DbeThread.cc
@@ -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
index 0000000..8ee148b
--- /dev/null
+++ b/gprofng/src/DbeThread.h
@@ -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
index 0000000..68613a5
--- /dev/null
+++ b/gprofng/src/DbeView.cc
@@ -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
index 0000000..bb6bb90
--- /dev/null
+++ b/gprofng/src/DbeView.h
@@ -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
index 0000000..4c3d82c
--- /dev/null
+++ b/gprofng/src/DefaultHandler.h
@@ -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
index 0000000..4a87fcc
--- /dev/null
+++ b/gprofng/src/DefaultMap.h
@@ -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
index 0000000..8045aad
--- /dev/null
+++ b/gprofng/src/DefaultMap2D.h
@@ -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
index 0000000..9f504a5
--- /dev/null
+++ b/gprofng/src/DerivedMetrics.cc
@@ -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
index 0000000..b457e5e
--- /dev/null
+++ b/gprofng/src/DerivedMetrics.h
@@ -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
index 0000000..0fec9c3
--- /dev/null
+++ b/gprofng/src/Disasm.cc
@@ -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
index 0000000..c1530cc
--- /dev/null
+++ b/gprofng/src/Disasm.h
@@ -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
index 0000000..eb8bd9e
--- /dev/null
+++ b/gprofng/src/Dwarf.cc
@@ -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
index 0000000..12ffbc0
--- /dev/null
+++ b/gprofng/src/Dwarf.h
@@ -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
index 0000000..c8af0ab
--- /dev/null
+++ b/gprofng/src/DwarfLib.cc
@@ -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
index 0000000..95eff57
--- /dev/null
+++ b/gprofng/src/DwarfLib.h
@@ -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
index 0000000..4117cf2
--- /dev/null
+++ b/gprofng/src/Elf.cc
@@ -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
index 0000000..3648b88
--- /dev/null
+++ b/gprofng/src/Elf.h
@@ -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
index 0000000..11bad97
--- /dev/null
+++ b/gprofng/src/Emsg.cc
@@ -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
index 0000000..f1d47c5
--- /dev/null
+++ b/gprofng/src/Emsg.h
@@ -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
index 0000000..cef8332
--- /dev/null
+++ b/gprofng/src/Emsgnum.h
@@ -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
index 0000000..0ad269a
--- /dev/null
+++ b/gprofng/src/ExpGroup.cc
@@ -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
index 0000000..b3c9422
--- /dev/null
+++ b/gprofng/src/ExpGroup.h
@@ -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
index 0000000..dfe1432
--- /dev/null
+++ b/gprofng/src/Exp_Layout.cc
@@ -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
index 0000000..c5fbe4c
--- /dev/null
+++ b/gprofng/src/Exp_Layout.h
@@ -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
index 0000000..a23c10c
--- /dev/null
+++ b/gprofng/src/Experiment.cc
@@ -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
index 0000000..41c44e4
--- /dev/null
+++ b/gprofng/src/Experiment.h
@@ -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
index 0000000..49c94a8
--- /dev/null
+++ b/gprofng/src/Expression.cc
@@ -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
index 0000000..7542853
--- /dev/null
+++ b/gprofng/src/Expression.h
@@ -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
index 0000000..7a941f5
--- /dev/null
+++ b/gprofng/src/FileData.cc
@@ -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
index 0000000..67de689
--- /dev/null
+++ b/gprofng/src/FileData.h
@@ -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
index 0000000..34eda0d
--- /dev/null
+++ b/gprofng/src/Filter.cc
@@ -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
index 0000000..1338218
--- /dev/null
+++ b/gprofng/src/Filter.h
@@ -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
index 0000000..b186af1
--- /dev/null
+++ b/gprofng/src/FilterExp.h
@@ -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
index 0000000..29dc437
--- /dev/null
+++ b/gprofng/src/FilterSet.cc
@@ -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
index 0000000..6908565
--- /dev/null
+++ b/gprofng/src/FilterSet.h
@@ -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
index 0000000..b0e4a8f
--- /dev/null
+++ b/gprofng/src/Function.cc
@@ -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
index 0000000..b0a856b
--- /dev/null
+++ b/gprofng/src/Function.h
@@ -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
index 0000000..f66a6fe
--- /dev/null
+++ b/gprofng/src/HashMap.h
@@ -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
index 0000000..943183d
--- /dev/null
+++ b/gprofng/src/HeapActivity.cc
@@ -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
index 0000000..582b0b7
--- /dev/null
+++ b/gprofng/src/HeapActivity.h
@@ -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
index 0000000..5f001ad
--- /dev/null
+++ b/gprofng/src/HeapData.cc
@@ -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
index 0000000..7ff68e9
--- /dev/null
+++ b/gprofng/src/HeapData.h
@@ -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
index 0000000..8e6c009
--- /dev/null
+++ b/gprofng/src/HeapMap.cc
@@ -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
index 0000000..c46129d
--- /dev/null
+++ b/gprofng/src/HeapMap.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#ifndef _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
index 0000000..4412203
--- /dev/null
+++ b/gprofng/src/Hist_data.cc
@@ -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
index 0000000..c5f7281
--- /dev/null
+++ b/gprofng/src/Hist_data.h
@@ -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
index 0000000..c4cf854
--- /dev/null
+++ b/gprofng/src/Histable.h
@@ -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
index 0000000..401cab5
--- /dev/null
+++ b/gprofng/src/IOActivity.cc
@@ -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
index 0000000..35c4517
--- /dev/null
+++ b/gprofng/src/IOActivity.h
@@ -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
index 0000000..0f68a3a
--- /dev/null
+++ b/gprofng/src/IndexMap2D.h
@@ -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
index 0000000..a7c8a37
--- /dev/null
+++ b/gprofng/src/IndexObject.cc
@@ -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
index 0000000..23f21d3
--- /dev/null
+++ b/gprofng/src/IndexObject.h
@@ -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
index 0000000..8c20474
--- /dev/null
+++ b/gprofng/src/IntervalMap.h
@@ -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
index 0000000..d9ce3e8
--- /dev/null
+++ b/gprofng/src/LoadObject.cc
@@ -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
index 0000000..0c997e3
--- /dev/null
+++ b/gprofng/src/LoadObject.h
@@ -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
index 0000000..15f493a
--- /dev/null
+++ b/gprofng/src/MachineModel.cc
@@ -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
index 0000000..b874b5b
--- /dev/null
+++ b/gprofng/src/Makefile.am
@@ -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
index 0000000..f21671d
--- /dev/null
+++ b/gprofng/src/Makefile.in
@@ -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
index 0000000..530dcfc
--- /dev/null
+++ b/gprofng/src/Map.h
@@ -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
index 0000000..41b2be2
--- /dev/null
+++ b/gprofng/src/Map2D.h
@@ -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
index 0000000..d207a99
--- /dev/null
+++ b/gprofng/src/MemObject.cc
@@ -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
index 0000000..6bc459f
--- /dev/null
+++ b/gprofng/src/MemObject.h
@@ -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
index 0000000..3f7c78d
--- /dev/null
+++ b/gprofng/src/MemorySpace.cc
@@ -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
index 0000000..7d02e5e
--- /dev/null
+++ b/gprofng/src/MemorySpace.h
@@ -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
index 0000000..3b026ff
--- /dev/null
+++ b/gprofng/src/Metric.cc
@@ -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
index 0000000..a2b3778
--- /dev/null
+++ b/gprofng/src/Metric.h
@@ -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
index 0000000..7596524
--- /dev/null
+++ b/gprofng/src/MetricList.cc
@@ -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
index 0000000..b8486c1
--- /dev/null
+++ b/gprofng/src/MetricList.h
@@ -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
index 0000000..1e61b42
--- /dev/null
+++ b/gprofng/src/Module.cc
@@ -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
index 0000000..39c4322
--- /dev/null
+++ b/gprofng/src/Module.h
@@ -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
index 0000000..2cd5718
--- /dev/null
+++ b/gprofng/src/Ovw_data.cc
@@ -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
index 0000000..0c3372c
--- /dev/null
+++ b/gprofng/src/Ovw_data.h
@@ -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
index 0000000..5046a91
--- /dev/null
+++ b/gprofng/src/PRBTree.cc
@@ -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
index 0000000..1a6f07f
--- /dev/null
+++ b/gprofng/src/PRBTree.h
@@ -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
index 0000000..798e55c
--- /dev/null
+++ b/gprofng/src/PathTree.cc
@@ -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
index 0000000..dc3ad1f
--- /dev/null
+++ b/gprofng/src/PathTree.h
@@ -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
index 0000000..553afd3
--- /dev/null
+++ b/gprofng/src/PreviewExp.cc
@@ -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
index 0000000..8b7834a
--- /dev/null
+++ b/gprofng/src/PreviewExp.h
@@ -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
index 0000000..d6662df
--- /dev/null
+++ b/gprofng/src/Print.cc
@@ -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
index 0000000..4bc6655
--- /dev/null
+++ b/gprofng/src/Print.h
@@ -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
index 0000000..c4665e8
--- /dev/null
+++ b/gprofng/src/QLParser.h
@@ -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
index 0000000..4517b2e
--- /dev/null
+++ b/gprofng/src/QLParser.tab.cc
@@ -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
index 0000000..eaf2cb5
--- /dev/null
+++ b/gprofng/src/QLParser.tab.hh
@@ -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
index 0000000..689d0e1
--- /dev/null
+++ b/gprofng/src/QLParser.yy
@@ -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
index 0000000..dde3e06
--- /dev/null
+++ b/gprofng/src/SAXParser.h
@@ -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
index 0000000..7d9e851
--- /dev/null
+++ b/gprofng/src/SAXParserFactory.cc
@@ -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
index 0000000..8e2c366
--- /dev/null
+++ b/gprofng/src/SAXParserFactory.h
@@ -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
index 0000000..7c00334
--- /dev/null
+++ b/gprofng/src/Sample.cc
@@ -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
index 0000000..312bdcc
--- /dev/null
+++ b/gprofng/src/Sample.h
@@ -0,0 +1,80 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#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
index 0000000..fbfe727
--- /dev/null
+++ b/gprofng/src/SegMem.h
@@ -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
index 0000000..965b917
--- /dev/null
+++ b/gprofng/src/Settings.cc
@@ -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
index 0000000..fc696e8
--- /dev/null
+++ b/gprofng/src/Settings.h
@@ -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
index 0000000..bd0a1f1
--- /dev/null
+++ b/gprofng/src/SourceFile.cc
@@ -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
index 0000000..8e90682
--- /dev/null
+++ b/gprofng/src/SourceFile.h
@@ -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
index 0000000..9f1247d
--- /dev/null
+++ b/gprofng/src/Stabs.cc
@@ -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
index 0000000..1a7443a
--- /dev/null
+++ b/gprofng/src/Stabs.h
@@ -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
index 0000000..2595bc7
--- /dev/null
+++ b/gprofng/src/Stats_data.cc
@@ -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
index 0000000..2f6b6a7
--- /dev/null
+++ b/gprofng/src/Stats_data.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#ifndef _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
index 0000000..a9656d9
--- /dev/null
+++ b/gprofng/src/StringBuilder.cc
@@ -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
index 0000000..5fe1a51
--- /dev/null
+++ b/gprofng/src/StringBuilder.h
@@ -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
index 0000000..31898f4
--- /dev/null
+++ b/gprofng/src/StringMap.h
@@ -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
index 0000000..afe44bd
--- /dev/null
+++ b/gprofng/src/Table.cc
@@ -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
index 0000000..48ce06a
--- /dev/null
+++ b/gprofng/src/Table.h
@@ -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
index 0000000..bdb9922
--- /dev/null
+++ b/gprofng/src/UserLabel.cc
@@ -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
index 0000000..0cb37e4
--- /dev/null
+++ b/gprofng/src/UserLabel.h
@@ -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
index 0000000..105821e
--- /dev/null
+++ b/gprofng/src/checks.cc
@@ -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
index 0000000..48c65ff
--- /dev/null
+++ b/gprofng/src/collctrl.cc
@@ -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
index 0000000..6555df7
--- /dev/null
+++ b/gprofng/src/collctrl.h
@@ -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
index 0000000..c500dee
--- /dev/null
+++ b/gprofng/src/collect.h
@@ -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
index 0000000..512af7a
--- /dev/null
+++ b/gprofng/src/collector_module.h
@@ -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
index 0000000..486bd1a
--- /dev/null
+++ b/gprofng/src/comp_com.c
@@ -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
index 0000000..e410924
--- /dev/null
+++ b/gprofng/src/comp_com.h
@@ -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
index 0000000..6005a49
--- /dev/null
+++ b/gprofng/src/count.cc
@@ -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
index 0000000..93d0307
--- /dev/null
+++ b/gprofng/src/data_pckts.h
@@ -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
index 0000000..9219a8e
--- /dev/null
+++ b/gprofng/src/dbe_collctrl.cc
@@ -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
index 0000000..74b6838
--- /dev/null
+++ b/gprofng/src/dbe_hwc.h
@@ -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
index 0000000..a471c3e
--- /dev/null
+++ b/gprofng/src/dbe_hwcdrv.c
@@ -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
index 0000000..66d371a
--- /dev/null
+++ b/gprofng/src/dbe_hwcfuncs.c
@@ -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
index 0000000..ce077a1
--- /dev/null
+++ b/gprofng/src/dbe_hwctable.c
@@ -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
index 0000000..2c2e2b4
--- /dev/null
+++ b/gprofng/src/dbe_memmgr.c
@@ -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
index 0000000..e6eaed6
--- /dev/null
+++ b/gprofng/src/dbe_structs.h
@@ -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
index 0000000..79fd6c7
--- /dev/null
+++ b/gprofng/src/dbe_types.h
@@ -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
index 0000000..9761f2a
--- /dev/null
+++ b/gprofng/src/debug.h
@@ -0,0 +1,89 @@
+/* Copyright (C) 2021 Free Software Foundation, Inc.
+ Contributed by Oracle.
+
+ This file is part of GNU Binutils.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, 51 Franklin Street - Fifth Floor, Boston,
+ MA 02110-1301, USA. */
+
+#ifndef _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
index 0000000..a2c9500
--- /dev/null
+++ b/gprofng/src/enums.h
@@ -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
index 0000000..de06fbf
--- /dev/null
+++ b/gprofng/src/envsets.cc
@@ -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
index 0000000..8ba7295
--- /dev/null
+++ b/gprofng/src/gethrtime.c
@@ -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
index 0000000..8d3fc23
--- /dev/null
+++ b/gprofng/src/gp-archive.cc
@@ -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
index 0000000..1d937e0
--- /dev/null
+++ b/gprofng/src/gp-archive.h
@@ -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
index 0000000..afaae70
--- /dev/null
+++ b/gprofng/src/gp-collect-app.cc
@@ -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
index 0000000..ca7853d
--- /dev/null
+++ b/gprofng/src/gp-display-src.cc
@@ -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
index 0000000..7183553
--- /dev/null
+++ b/gprofng/src/gp-display-text.cc
@@ -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
index 0000000..80c922f
--- /dev/null
+++ b/gprofng/src/gp-print.h
@@ -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
index 0000000..1bf5679
--- /dev/null
+++ b/gprofng/src/gprofng.cc
@@ -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
index 0000000..8786768
--- /dev/null
+++ b/gprofng/src/gprofng.h2m
@@ -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
index 0000000..3870220
--- /dev/null
+++ b/gprofng/src/gprofng.rc
@@ -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
index 0000000..32c9960
--- /dev/null
+++ b/gprofng/src/i18n.cc
@@ -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
index 0000000..d02ec0e
--- /dev/null
+++ b/gprofng/src/i18n.h
@@ -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
index 0000000..5b05833
--- /dev/null
+++ b/gprofng/src/info.h
@@ -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
index 0000000..932423c
--- /dev/null
+++ b/gprofng/src/ipc.cc
@@ -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
index 0000000..57f2617
--- /dev/null
+++ b/gprofng/src/ipcio.cc
@@ -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
index 0000000..94a635e
--- /dev/null
+++ b/gprofng/src/ipcio.h
@@ -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
index 0000000..19fcc8e
--- /dev/null
+++ b/gprofng/src/machinemodels/generic.ermm
@@ -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
index 0000000..83f125d
--- /dev/null
+++ b/gprofng/src/machinemodels/m5.ermm
@@ -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
index 0000000..1071e9e
--- /dev/null
+++ b/gprofng/src/machinemodels/m6.ermm
@@ -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
index 0000000..29e3bef
--- /dev/null
+++ b/gprofng/src/machinemodels/m7.ermm
@@ -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
index 0000000..e27f3a4
--- /dev/null
+++ b/gprofng/src/machinemodels/t4.ermm
@@ -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
index 0000000..6d666a9
--- /dev/null
+++ b/gprofng/src/machinemodels/t5.ermm
@@ -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
index 0000000..ab22270
--- /dev/null
+++ b/gprofng/src/parse.cc
@@ -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
index 0000000..4610105
--- /dev/null
+++ b/gprofng/src/stab.h
@@ -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
index 0000000..b93deaf
--- /dev/null
+++ b/gprofng/src/util.cc
@@ -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
index 0000000..0d1b8bc
--- /dev/null
+++ b/gprofng/src/util.h
@@ -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
index 0000000..28b1800c
--- /dev/null
+++ b/gprofng/src/vec.h
@@ -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
index 0000000..6fde0a1
--- /dev/null
+++ b/gprofng/testsuite/config/default.exp
@@ -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
index 0000000..108144c
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/display.exp
@@ -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
index 0000000..016e7b2
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/jsynprog/Intface.java
@@ -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
index 0000000..33ee06c
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/jsynprog/Launcher.java
@@ -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
index 0000000..e78b692
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/jsynprog/Makefile
@@ -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
index 0000000..cfe45d2
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/jsynprog/Routine.java
@@ -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
index 0000000..11e045e
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/jsynprog/Sub_Routine.java
@@ -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
index 0000000..eac58a2
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/jsynprog/check_results.pl
@@ -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
index 0000000..cf8b779
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/jsynprog/cloop.cc
@@ -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
index 0000000..34b4f6c
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/jsynprog/jsynprog.h
@@ -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
index 0000000..eb98b5e
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/jsynprog/jsynprog.java
@@ -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
index 0000000..0613ffb
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/mttest/Makefile
@@ -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
index 0000000..2d67e8b
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/mttest/check_results.pl
@@ -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
index 0000000..a985401
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/mttest/gethrtime.c
@@ -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
index 0000000..5d22af7
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/mttest/mttest.c
@@ -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
index 0000000..7c50ea2
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/Makefile
@@ -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
index 0000000..6ff5c99
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/callso.c
@@ -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
index 0000000..5adcf90
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/callsx.c
@@ -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
index 0000000..e77d074
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/check_results.pl
@@ -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
index 0000000..5f9fb43
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/endcases.c
@@ -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
index 0000000..f343876
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/fitos.c
@@ -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
index 0000000..2126ea3
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/inc_body.h
@@ -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
index 0000000..2126ea3
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/inc_brace.h
@@ -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
index 0000000..fdf9eed
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/inc_entry.h
@@ -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
index 0000000..4ada146
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/inc_exit.h
@@ -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
index 0000000..7b14359
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/inc_func.h
@@ -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
index 0000000..219aee0
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/inc_inline.h
@@ -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
index 0000000..c2093da
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/inc_macro.h
@@ -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
index 0000000..278ceea
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/iosyn.c
@@ -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
index 0000000..a909600
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/pagethrash.c
@@ -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
index 0000000..6fc5aa6
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/so_syn.c
@@ -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
index 0000000..ae7da6f
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/so_syx.c
@@ -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
index 0000000..5cb5281
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/stopwatch.c
@@ -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
index 0000000..704b165
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/stopwatch.h
@@ -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
index 0000000..a5361a4
--- /dev/null
+++ b/gprofng/testsuite/gprofng.display/synprog/synprog.c
@@ -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
index 0000000..7134c27
--- /dev/null
+++ b/gprofng/testsuite/lib/Makefile.skel
@@ -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
index 0000000..1b0168e
--- /dev/null
+++ b/gprofng/testsuite/lib/acct.pm
@@ -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
index 0000000..38ecb8d
--- /dev/null
+++ b/gprofng/testsuite/lib/display-lib.exp
@@ -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
+}